From 15d0d80cb9fc0c5fabb0a1fef0e6261d60aed1c3 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Thu, 29 Feb 2024 17:43:45 +0100 Subject: [PATCH 01/34] Add stub implementation of the new plugin and the readme. --- README.md | 2 + devops/install_deps.bb | 8 +- .../LICENSE | 201 + .../README.md | 95 + .../package-lock.json | 3572 +++++++++++++++++ .../package.json | 62 + .../src/hash-preimage-proof.ts | 21 + .../src/plugin.ts | 144 + .../src/prover.ts | 84 + .../src/zkclaim.ts | 7 + .../tsconfig.json | 28 + 11 files changed, 4221 insertions(+), 3 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/LICENSE create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/README.md create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/package.json create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json diff --git a/README.md b/README.md index 5d5f6c6..59e1d8c 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,5 @@ The work on the library was funded by: * zkIgnite (https://zkignite.minaprotocol.com/) * MINA Navigators (https://minaprotocol.com/join-mina-navigators) * MLabs (https://mlabs.city/) + +Thank you! <3 diff --git a/devops/install_deps.bb b/devops/install_deps.bb index 7f97f47..a7449fa 100755 --- a/devops/install_deps.bb +++ b/devops/install_deps.bb @@ -10,13 +10,15 @@ (def packages [{:name "minauth-simple-preimage-plugin" :path "/home/anks/spre" :deps [:mlib]} {:name "minauth-erc721-timelock-plugin" :path "/home/anks/etl" :deps [:mlib]} {:name "minauth-merkle-membership-plugin" :path "/home/anks/mm" :deps [:mlib]} + {:name "minauth-verified-zkdocument-plugin" :path "/home/anks/zdoc" :deps [:mlib]} {:name "minauth-demo-server" :path "/home/anks/serv" :deps [:spre :mlib :mm :etl]} {:name "minauth-demo-client" :path "/home/anks/client" :deps [:spre :mlib :mm :etl]}]) (def global-deps {:spre {:name "minauth-simple-preimage-plugin" :path "/home/anks/spre"} - :etl {:name "minauth-erc721-timelock-plugin" :path "/home/anks/etl"} - :mlib {:name "minauth" :path "/home/anks/mlib"} - :mm {:name "minauth-merkle-membership-plugin" :path "/home/anks/mm"}}) + :etl {:name "minauth-erc721-timelock-plugin" :path "/home/anks/etl"} + :zdoc {:name "minauth-verified-zkdocument-plugin" :path "/home/anks/zdoc"} + :mlib {:name "minauth" :path "/home/anks/mlib"} + :mm {:name "minauth-merkle-membership-plugin" :path "/home/anks/mm"}}) (defn- logret [msg] (println msg) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/LICENSE b/minauth-plugins/minauth-verified-zkdocument-plugin/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md new file mode 100644 index 0000000..cb6580e --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md @@ -0,0 +1,95 @@ +# MinAuth Verified ZK-Document Plugin + +🚧 **DISCLAIMER**: The plugin & the documentation under development. + +This package contains an implementation of a MinAuth plugin. +It uses MINA's o1js library for its zero-knowledge proof part. + +The plugin allows to use zk cryptographically secure proofs of claims +on the zk-documents to be used as a source of authentication. + +## Plugin's overview + +The simple example is the popular case of proving a credit score. +There are 3 entities involved: + +- The verifying entity (verifier) - one that needs the proof +- The credit score issuer (3rd party / issuer) - one that approves the validity of the document +- The proving entity (prover) - one that is requested to prove the required claim. + +Additionally there is a passive 4th entity that is the legitimate source of claim standards. +It could be a recognized repository with hashes pinned on-chain in a DAO-guarded contract. + +The verifier uses one of the required "credit score above X" claim proving programs to create +a proof against their document. The proof along the claim proving zkprogram verification key hash +and other details such as the user's private key go into the authorization verifier. + +On succesful authorization the MinAuth plugin return the set of proven data to the verifying entity +to provide access to its services. + +### ZK-document + +First we assume the existence of a document type that is issued and recognized by +the 3rd party. This can be done via a signature of a trusted public key, i.e. the +verifier trusts the public key of the 3rd party. The document is malleable to a +set of claim-proving zk-programs, this can be implemented as a merkle list of +verifification_keys hashes. +The signature of the 3rd party includes the public key of the prover. + +The document can then be used by the prover as input to claim proving algorithms. +The proofs coming from the algorithms are then used in the verifier final proof verifier, +which is integrated and customizable in the IMinauthPlugin intance provided by this +package. + +### ZK-document standard (schema) + +The issuer issuing the document additionally issues a standard to which the document adheres. +This standard describes the document and its structure (currently as a list of Fields). +So an example could be: + +``` +document_id | 0-0 | The identifier of the document in the issuer database +document_end_of_validity_timestamp | 1-1 | The document validity period. +subject_id | 2-2 | The identifier of the subject of the new document +subject_age | 3-3 | The age of the subject. Valid range is: [0-150] +subject_credit_score | 4-4 | The credit_score of the subject Valid range is: [0-1.000.000.000] +subject_country_of_residence | 5-5 | `ISO 3166-1 numeric` standard country code +``` + +### UI + +The UI design of this plugin' prover can easily get complex enough to be a project on its +own. Given the scope and resources as of today it will need careful consideration +on how to keep it minimal. + +## Implemented claim provers + +In most cases users of the library will want to use their own claim provers designed +to suit there needs, but some demonstrational one are implemented as a part of the +package. + +### Document valid to X + +Assuming the document being a list of Fields. Validity timestamp index is hardcoded into the claim prover. +X is a part of the public input. + +### Age over X + +Assuming the document being a list of Fields Age index is hardcoded into the claim prover. +X is a part of the public input. + +### Country of residence equal to X via `ISO 3166-1 numeric` + +Assuming the document being a list of Fields Age index is hardcoded into the claim prover. +X is a part of the public input. + + +## Configuration + +🚧 **Under construction** + +## Plugin's output revocation + +The claims proven about the document do not go outdated, but the documents can. +Additionally the plugin user may want to query the issuer for deprecation of their public +key or designated withdrawal of the recognition of particular documents. diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json new file mode 100644 index 0000000..5e21e43 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json @@ -0,0 +1,3572 @@ +{ + "name": "minauth-verified-zkdocument-plugin", + "version": "0.10.0-alpha", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "minauth-verified-zkdocument-plugin", + "version": "0.10.0-alpha", + "license": "Apache-2.0", + "dependencies": { + "express": "^4.18.2", + "fp-ts": "^2.16.1", + "minauth": "0.10.0-alpha", + "zod": "^3.22.2" + }, + "devDependencies": { + "@types/axios": "^0.14.*", + "@types/express": "^4.17.17", + "@typescript-eslint/eslint-plugin": "^6.7.4", + "@typescript-eslint/parser": "^6.8.0", + "eslint": "^8.51.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-deprecation": "^2.0.0", + "eslint-plugin-prettier": "^5.0.0", + "nodemon": "^3.0.1", + "prettier": "^3.0.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.2.2" + }, + "peerDependencies": { + "o1js": "0.16.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==", + "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "dev": true, + "dependencies": { + "axios": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "devOptional": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "devOptional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "devOptional": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "devOptional": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "devOptional": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-proxy-middleware": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz", + "integrity": "sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw==", + "deprecated": "This is a stub types definition. http-proxy-middleware provides its own type definitions, so you do not need this installed.", + "dependencies": { + "http-proxy-middleware": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "devOptional": true + }, + "node_modules/@types/node": { + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.12", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", + "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==", + "devOptional": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "devOptional": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "devOptional": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "devOptional": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "peer": true + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cmd-ts": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/cmd-ts/-/cmd-ts-0.13.0.tgz", + "integrity": "sha512-nsnxf6wNIM/JAS7T/x/1JmbEsjH0a8tezXqqpaL0O6+eV0/aDEnRxwjxpu0VzDdRcaC1ixGSbRlUuf/IU59I4g==", + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "didyoumean": "^1.2.2", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-gpu": { + "version": "5.0.38", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.38.tgz", + "integrity": "sha512-36QeGHSXYcJ/RfrnPEScR8GDprbXFG4ZhXsfVNVHztZr38+fRxgHnJl3CjYXXjbeRUhu3ZZBJh6Lg0A9v0Qd8A==", + "peer": true, + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/env-var": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/env-var/-/env-var-7.4.1.tgz", + "integrity": "sha512-H8Ga2SbXTQwt6MKEawWSvmxoH1+J6bnAXkuyE7eDvbGmrhIL2i+XGjzGM3DFHcJu8GY1zY9/AnBJY8uGQYPHiw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-deprecation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-2.0.0.tgz", + "integrity": "sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^6.0.0", + "tslib": "^2.3.1", + "tsutils": "^3.21.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "typescript": "^4.2.4 || ^5.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/express": { + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.2.tgz", + "integrity": "sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng==" + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "peer": true, + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==", + "peer": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minauth": { + "version": "0.10.0-alpha", + "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.0-alpha.tgz", + "integrity": "sha512-L4GXlthfKt+jefDtX+ghcHG5HGTyRuf7ZGbNmswLk+OneyZhvXlV4ppylkT9lmqKNTX4iUV1olq629rII7ezug==", + "dependencies": { + "@types/http-proxy-middleware": "^1.0.0", + "axios": "^1.5.0", + "big-integer": "^1.6.51", + "body-parser": "^1.20.2", + "cmd-ts": "^0.13.0", + "env-var": "^7.4.1", + "express": "^4.18.2", + "fp-ts": "^2.16.1", + "http-proxy-middleware": "^2.0.6", + "jsonwebtoken": "^9.0.2", + "passport": "^0.6.0", + "passport-jwt": "^4.0.1", + "passport-strategy": "^1.0.0", + "path": "^0.12.7", + "tslog": "^4.9.2", + "yaml": "^2.3.2", + "zod": "^3.22.2" + }, + "peerDependencies": { + "o1js": "0.16.0" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "peer": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nodemon": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", + "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/o1js": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.0.tgz", + "integrity": "sha512-H6fKHLgH68v18De0tZydQKqF2bOIvF+EsPHJ+P53dJDOaS7Dlp8Uf4hGVo8S8luCfYsFvCdDGU3YwfegfCk6TQ==", + "peer": true, + "dependencies": { + "blakejs": "1.2.1", + "cachedir": "^2.4.0", + "detect-gpu": "^5.0.5", + "isomorphic-fetch": "^3.0.0", + "js-sha256": "^0.9.0", + "reflect-metadata": "^0.1.13", + "tslib": "^2.3.0" + }, + "bin": { + "snarky-run": "src/build/run.js" + }, + "engines": { + "node": ">=16.4.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", + "peer": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "peer": true + }, + "node_modules/ts-api-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tslog": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/tslog/-/tslog-4.9.2.tgz", + "integrity": "sha512-wBM+LRJoNl34Bdu8mYEFxpvmOUedpNUwMNQB/NcuPIZKwdDde6xLHUev3bBjXQU7gdurX++X/YE7gLH8eXYsiQ==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/fullstack-build/tslog?sponsor=1" + } + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==", + "peer": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "peer": true + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "peer": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "peer": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", + "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json new file mode 100644 index 0000000..e6da713 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json @@ -0,0 +1,62 @@ +{ + "name": "minauth-verified-zkdocument-plugin", + "version": "0.10.0-alpha", + "description": "Plugin for authorization with verified zk claims on 3rd-party approved documents.", + "type": "module", + "main": "dist/index.js", + "browser": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist/**/*" + ], + "scripts": { + "build": "tsc -p tsconfig.json", + "lint": "eslint . --ext .ts", + "prettier-format": "prettier --config .prettierrc './**/*.ts' --write", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "express": "^4.18.2", + "fp-ts": "^2.16.1", + "minauth": "0.10.0-alpha", + "zod": "^3.22.2" + }, + "devDependencies": { + "@types/axios": "^0.14.*", + "@types/express": "^4.17.17", + "@typescript-eslint/eslint-plugin": "^6.7.4", + "@typescript-eslint/parser": "^6.8.0", + "eslint": "^8.51.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-deprecation": "^2.0.0", + "eslint-plugin-prettier": "^5.0.0", + "nodemon": "^3.0.1", + "prettier": "^3.0.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.2.2" + }, + "peerDependencies": { + "o1js": "0.16.0" + }, + "keywords": [ + "authentication", + "blockchain", + "cryptography", + "express", + "mina", + "minauth", + "o1js", + "passport", + "security", + "typescript", + "zero-knowledge" + ], + "author": { + "name": "Michał Adamczyk", + "email": "michal@mlabs.city", + "url": "https://github.com/adamczykm" + }, + "contributors": [], + "license": "Apache-2.0" +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts new file mode 100644 index 0000000..07f67f8 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts @@ -0,0 +1,21 @@ +import { Field, ZkProgram, Poseidon } from 'o1js'; + +export const ProvePreimageProgram = ZkProgram({ + name: 'ProvePreimage', + publicInput: Field, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [Field], + method(publicInput: Field, secretInput: Field) { + Poseidon.hash([secretInput]).assertEquals(publicInput); + return publicInput; + } + } + } +}); + +export const ProvePreimageProofClass = ZkProgram.Proof(ProvePreimageProgram); + +export default ProvePreimageProgram; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts new file mode 100644 index 0000000..259c8ac --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts @@ -0,0 +1,144 @@ +import { Cache, PublicKey, verify } from 'o1js'; +import { + IMinAuthPlugin, + IMinAuthPluginFactory, + OutputValidity, + outputInvalid, + outputValid +} from 'minauth/dist/plugin/plugintype.js'; +import ProvePreimageProgram from './hash-preimage-proof.js'; +import { Router } from 'express'; +import { z } from 'zod'; +import { TsInterfaceType } from 'minauth/dist/plugin/interfacekind.js'; +import { + wrapZodDec, + combineEncDec, + noOpEncoder +} from 'minauth/dist/plugin/encodedecoder.js'; +import { Logger } from 'minauth/dist/plugin/logger.js'; +import { VerificationKey } from 'minauth/dist/common/verificationkey.js'; +import { JsonProofSchema } from 'minauth/dist/common/proof.js'; +import { ZkClaimSubplugin } from './zkclaim.js'; + + +// TODO +export const configurationSchema = z.unknown() + +export type Configuration = z.infer; + +export const InputSchema = z.object( + { proof: JsonProofSchema + , additionalData: z.array(z.unknown()) // TODO considering making it into a template + }); + +export type Input = z.infer; + + +export const OutputSchema = z.object({ provedClaims: z.array(z.unknown()) }); // TODO considering making it into a template + +export type Output = z.infer; + +/** + * TODO + * The plugin allows to use zk cryptographically secure proofs of claims + * on the zk-documents to be used as a source of authentication. + * See README.md for more details. + */ +export class ZkDocumentClaimsPlugin + implements IMinAuthPlugin +{ + /** + * This plugin uses an idiomatic Typescript interface + */ + readonly __interface_tag = 'ts'; + + /** The plugin's logger */ + protected readonly logger: Logger; + + /** + * A memoized main authorization zk-circuit verification key + */ + readonly verificationKey: VerificationKey; + + /** + * The mapping between hashes and claims + */ + readonly zkClaimsSubplugins: Record; + + /** + * The mapping between hashes and claims + */ + readonly trustedIssuers: Record; + + /** + * Verify a proof and return the verified claims. + */ + async verifyAndGetOutput(inp: Input): Promise { + // TODO + return Promise.resolve({ provedClaims: [] }); + } + + /** + */ + readonly customRoutes = Router() + + /** + * Check if produced output is still valid. + * - check if the isueer is still trusted + * - foreach claim check it's validation rules: + * - for example for the timestamp validity claim the validity timestamp + * - can be checked if the date is still in the future + */ + async checkOutputValidity(output: Output): Promise { + // TODO + return Promise.resolve(outputValid); + } + + /** + * This ctor is meant ot be called by the `initialize` function. + */ + constructor( + verificationKey: VerificationKey, + logger: Logger + ) { + this.verificationKey = verificationKey; + this.logger = logger; + } + + static readonly __interface_tag = 'ts'; + + /** + * Initialize the plugin with a configuration. + */ + static async initialize( + configuration: Configuration, + logger: Logger + ): Promise { + const { verificationKey } = await ProvePreimageProgram.compile({ + cache: Cache.None + }); + return new ZkDocumentClaimsPlugin(verificationKey, logger); + } + + static readonly configurationDec = wrapZodDec('ts', configurationSchema); + + readonly inputDecoder = wrapZodDec( + 'ts', + InputSchema + ); + + /** output parsing and serialization */ + readonly outputEncDec = combineEncDec( + noOpEncoder('ts'), + wrapZodDec('ts', OutputSchema) + ); +} + +// sanity check +ZkDocumentClaimsPlugin satisfies IMinAuthPluginFactory< + TsInterfaceType, + ZkDocumentClaimsPlugin, + Configuration +>; + +export default ZkDocumentClaimsPlugin diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts new file mode 100644 index 0000000..028ded7 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts @@ -0,0 +1,84 @@ +import { Field, JsonProof, Cache } from 'o1js'; +import { + IMinAuthProver, + IMinAuthProverFactory +} from 'minauth/dist/plugin/plugintype.js'; +import { TsInterfaceType } from 'minauth/dist/plugin/interfacekind.js'; +import { Logger } from 'minauth/dist/plugin/logger.js'; +import ProvePreimageProgram from './hash-preimage-proof.js'; +import { VerificationKey } from 'minauth/dist/common/verificationkey.js'; +import { PluginRouter } from 'minauth/dist/plugin/pluginrouter.js'; + + +export type Configuration = { + logger: Logger; + pluginRoutes: PluginRouter; +}; + +/** TODO + * The plugin allows to use zk cryptographically secure proofs of claims + * on the zk-documents to be used as a source of authentication. + * See README.md for more details. +*/ +export class ZkDocumentClaimsProver + implements IMinAuthProver +{ + /** This prover uses an idiomatic Typescript interface */ + readonly __interface_tag: 'ts'; + static readonly __interface_tag: 'ts'; + + /** The prover's logger */ + protected readonly logger: Logger; + + /** The prover's plugin routes */ + protected readonly pluginRoutes: PluginRouter; + + protected constructor(logger: Logger, pluginRoutes: PluginRouter) { + this.logger = logger; + this.pluginRoutes = pluginRoutes; + } + + /** Build a proof. */ + async prove(publicInput: Field, secretInput: Field): Promise { + this.logger.debug('Building proof started.'); + const proof = await ProvePreimageProgram.baseCase(publicInput, secretInput); + this.logger.debug('Building proof finished.'); + return proof.toJSON(); + } + + /** Fetches a list of hashes recognized by the server. */ + fetchPublicInputs(): Promise { + throw 'not implemented, please query the `/roles` endpoint'; + } + + /** Compile the underlying zk circuit */ + static async compile(): Promise<{ verificationKey: VerificationKey }> { + // TODO check if still the case? + // disable cache because of bug in o1js 0.14.1: + // you have a verification key acquired by using cached circuit AND + // not build a proof locally, + // but use a serialized one - it will hang during verification. + return await ProvePreimageProgram.compile({ cache: Cache.None }); + } + + /** Initialize the prover */ + static async initialize( + config: Configuration, + { compile = true } = {} + ): Promise { + const { logger, pluginRoutes } = config; + logger.info('ZkDocumentClaimsProver.initialize'); + if (compile) { + logger.info('compiling the circuit'); + await ZkDocumentClaimsProver.compile(); + logger.info('compiled'); + } + return new ZkDocumentClaimsProver(logger, pluginRoutes); + } +} + +ZkDocumentClaimsProver satisfies IMinAuthProverFactory< + TsInterfaceType, + ZkDocumentClaimsProver, + unknown +>; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts new file mode 100644 index 0000000..f8cb147 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts @@ -0,0 +1,7 @@ +import { z } from "zod"; + +export const ZkClaimSubpluginSchema = z.object({ + zkClaimProgramVerificationKeyHash: z.string(), +}) + +export type ZkClaimSubplugin = z.infer; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json b/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json new file mode 100644 index 0000000..0422d60 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "es2020", + "lib": ["es2020"], + "allowJs": true, + "allowSyntheticDefaultImports": true, + "baseUrl": ".", + "declaration": true, + "emitDecoratorMetadata": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "outDir": "./dist", + "rootDir": "./src", + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "strictPropertyInitialization": false + }, + "include": ["src/**/*"], + "ts-node": { + "require": ["tsconfig-paths/register"] + }, + "exclude": ["node_modules", "**/*.spec.ts"] +} From ab7b4cf41bca051815c6430e6a04b9455415e3a4 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Thu, 29 Feb 2024 19:40:50 +0100 Subject: [PATCH 02/34] Add initial zkClaims implementation. --- .../README.md | 19 ++- .../src/hash-preimage-proof.ts | 21 --- .../src/prover.ts | 1 - .../src/zkclaim.ts | 5 + .../src/zkclaims/dateClaims.ts | 134 ++++++++++++++++++ .../src/zkclaims/numberClaims.ts | 132 +++++++++++++++++ .../src/zkclaims/rollupClaim.ts | 36 +++++ .../src/zkdoc-spec.ts | 18 +++ 8 files changed, 340 insertions(+), 26 deletions(-) delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateClaims.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/numberClaims.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkdoc-spec.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md index cb6580e..4afda60 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md @@ -27,7 +27,7 @@ and other details such as the user's private key go into the authorization verif On succesful authorization the MinAuth plugin return the set of proven data to the verifying entity to provide access to its services. -### ZK-document +### ZK-document & zk-claims First we assume the existence of a document type that is issued and recognized by the 3rd party. This can be done via a signature of a trusted public key, i.e. the @@ -41,6 +41,7 @@ The proofs coming from the algorithms are then used in the verifier final proof which is integrated and customizable in the IMinauthPlugin intance provided by this package. + ### ZK-document standard (schema) The issuer issuing the document additionally issues a standard to which the document adheres. @@ -68,21 +69,31 @@ In most cases users of the library will want to use their own claim provers desi to suit there needs, but some demonstrational one are implemented as a part of the package. -### Document valid to X +### Document valid to X (and general date claim prover) Assuming the document being a list of Fields. Validity timestamp index is hardcoded into the claim prover. X is a part of the public input. -### Age over X +### Age over X (and general number size claim prover) Assuming the document being a list of Fields Age index is hardcoded into the claim prover. X is a part of the public input. -### Country of residence equal to X via `ISO 3166-1 numeric` +### Country of residence equal to X via `ISO 3166-1 numeric` (and general string prover) Assuming the document being a list of Fields Age index is hardcoded into the claim prover. X is a part of the public input. +### Possible zk-claims rollups + +If possible the claims will be able to be rolled up for space & server-time efficiency. +The verifier could ask for a joined claim of: + +- Document valid > month from now +- Subject age > 18 +- Subject residency in EU + +All the claims could be rolled up into a single proof of constant size. ## Configuration diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts deleted file mode 100644 index 07f67f8..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/hash-preimage-proof.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Field, ZkProgram, Poseidon } from 'o1js'; - -export const ProvePreimageProgram = ZkProgram({ - name: 'ProvePreimage', - publicInput: Field, - publicOutput: Field, - - methods: { - baseCase: { - privateInputs: [Field], - method(publicInput: Field, secretInput: Field) { - Poseidon.hash([secretInput]).assertEquals(publicInput); - return publicInput; - } - } - } -}); - -export const ProvePreimageProofClass = ZkProgram.Proof(ProvePreimageProgram); - -export default ProvePreimageProgram; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts index 028ded7..be9e0e3 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts @@ -5,7 +5,6 @@ import { } from 'minauth/dist/plugin/plugintype.js'; import { TsInterfaceType } from 'minauth/dist/plugin/interfacekind.js'; import { Logger } from 'minauth/dist/plugin/logger.js'; -import ProvePreimageProgram from './hash-preimage-proof.js'; import { VerificationKey } from 'minauth/dist/common/verificationkey.js'; import { PluginRouter } from 'minauth/dist/plugin/pluginrouter.js'; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts index f8cb147..0fbd2dd 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaim.ts @@ -5,3 +5,8 @@ export const ZkClaimSubpluginSchema = z.object({ }) export type ZkClaimSubplugin = z.infer; + +// ZkClaim should be able to +// - communicate to the user what is being claimed +// - communicate the need of auditional context to check the validity of the claim, e.g. current time (actually this might be something that should not be a part of claims) + diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateClaims.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateClaims.ts new file mode 100644 index 0000000..831c82b --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateClaims.ts @@ -0,0 +1,134 @@ +import { Field, ZkProgram, Poseidon, CircuitString, Struct, Provable } from 'o1js'; + + +// TODO extend so that the programs are wrapped in to zkclaim class that can explain +// what is being claimed to the user and more +// how to check the validity of the claim etc +// TODO base them on numberClaims.ts reuse ciircuit but change the +// wrappers to be more convenient etc + +export const mkClaimTimestampGreaterThan = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'IntegerIsGreaterThan', + publicInput: Field, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(publicInput: Field, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + thenumber.assertGreaterThan(publicInput); + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} + +export const mkClaimTimestampIsLessThan = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'TimestampIsLessThan', + publicInput: Field, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(publicInput: Field, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + thenumber.assertLessThan(publicInput); + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} + + +export const mkClaimTimestampIsEqualTo = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'TimestampIsEqualTo', + publicInput: Field, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(publicInput: Field, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + thenumber.assertEquals(publicInput); + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} + +export class Range extends Struct({ + min: Field, + minInclusive: Field, + max: Field, + maxInclusive: Field, +}) {} + +export const mkClaimTimestampIsBetween = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'TimestampIsInBetween', + publicInput: Range, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(range: Range, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + + const min = Provable.if(range.minInclusive.equals(new Field(0)), range.min.add(new Field(1)), range.min); + const max = Provable.if(range.maxInclusive.equals(new Field(0)), range.max.sub(new Field(1)), range.max); + + thenumber.assertGreaterThanOrEqual(min); + thenumber.assertLessThanOrEqual(max); + + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/numberClaims.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/numberClaims.ts new file mode 100644 index 0000000..ff02339 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/numberClaims.ts @@ -0,0 +1,132 @@ +import { Field, ZkProgram, Poseidon, CircuitString, Struct, Provable } from 'o1js'; + + +// TODO extend so that the programs are wrapped in to zkclaim class that can explain +// what is being claimed to the user and more +// how to check the validity of the claim etc + +export const mkClaimIntegerIsGreaterThan = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'IntegerIsGreaterThan', + publicInput: Field, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(publicInput: Field, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + thenumber.assertGreaterThan(publicInput); + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} + +export const mkClaimIntegerIsLessThan = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'IntegerIsLessThan', + publicInput: Field, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(publicInput: Field, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + thenumber.assertLessThan(publicInput); + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} + + +export const mkClaimIntegerIsEqualTo = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'IntegerIsEqualTo', + publicInput: Field, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(publicInput: Field, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + thenumber.assertEquals(publicInput); + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} + +export class Range extends Struct({ + min: Field, + minInclusive: Field, + max: Field, + maxInclusive: Field, +}) {} + +export const mkClaimIntegerIsBetween = (index: number) => { + + if (index < 0) { + throw new Error('index must be non-negative'); + } + + const prog = ZkProgram({ + name: 'IntegerIsInBetween', + publicInput: Range, + publicOutput: Field, + + methods: { + baseCase: { + privateInputs: [CircuitString], + method(range: Range, secretInput: CircuitString) { + const fields = secretInput.toFields(); + const thenumber = fields[index]; + + const min = Provable.if(range.minInclusive.equals(new Field(0)), range.min.add(new Field(1)), range.min); + const max = Provable.if(range.maxInclusive.equals(new Field(0)), range.max.sub(new Field(1)), range.max); + + thenumber.assertGreaterThanOrEqual(min); + thenumber.assertLessThanOrEqual(max); + + const inputHash = Poseidon.hash(fields); + return inputHash; + } + } + } + }); + + return prog; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts new file mode 100644 index 0000000..fde980b --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts @@ -0,0 +1,36 @@ +import { + Field, + ZkProgram, + Poseidon, + CircuitString, + Struct, + Provable, + Proof +} from 'o1js'; + +const prog = ZkProgram({ + name: 'IntegerIsGreaterThan', + publicInput: CircuitString, + publicOutput: Field, + + methods: { + fromFieldClaim: { + privateInputs: [Proof], + method(publicInput: CircuitString, fieldClaimProof: Proof) { + fieldClaimProof.verify(); + return fieldClaimProof.publicOutput; + } + }, + rollupClaims: { + privateInputs: [Proof, Proof], + method(claim1: Proof, claim2: Proof) { + claim1.verify(); + claim2.verify(); + return claim1.publicOutput; + // TODO + // Find a way to preserve information about the claims + // so that one can verify that the rollup claim is valid + } + } + } +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkdoc-spec.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkdoc-spec.ts new file mode 100644 index 0000000..0534cbb --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkdoc-spec.ts @@ -0,0 +1,18 @@ +import * as z from 'zod'; + +export const ZkDocPartSpecSchema = z.object( + { partName: z.string() + , partLocation: z.object({first: z.number(), last: z.number()}) + , humanDescription: z.string() + , endorsedZkClaimProgramVerificationKeyHashes: z.array(z.string()) +}); + +export type ZkDocPartSpec = z.infer; + +const zkDocSpecSchema = z.object( + { title: z.string() + , description: z.string() + , parts: z.array(ZkDocPartSpecSchema) + }); + +export type ZkDocSpec = z.infer; From d3d7e27da8d74390a35e6151b7a4b728171664fb Mon Sep 17 00:00:00 2001 From: adamczykm Date: Wed, 6 Mar 2024 19:21:00 +0100 Subject: [PATCH 03/34] Bump o1js --- minauth-demo/minauth-demo-client/package.json | 2 +- minauth-demo/minauth-demo-server/package.json | 2 +- .../package-lock.json | 160 ++++++------------ .../package.json | 6 +- .../package-lock.json | 116 ++++--------- .../package.json | 6 +- .../package-lock.json | 116 ++++--------- .../package.json | 6 +- .../package-lock.json | 62 ++++--- .../package.json | 11 +- minauth/package-lock.json | 121 +++++-------- minauth/package.json | 4 +- 12 files changed, 226 insertions(+), 386 deletions(-) diff --git a/minauth-demo/minauth-demo-client/package.json b/minauth-demo/minauth-demo-client/package.json index 45d7cb5..ff4ab74 100644 --- a/minauth-demo/minauth-demo-client/package.json +++ b/minauth-demo/minauth-demo-client/package.json @@ -26,7 +26,7 @@ "minauth-merkle-membership-plugin": "0.10.0-alpha", "minauth-simple-preimage-plugin": "0.10.0-alpha", "next": "^14.0.3", - "o1js": "0.16.0", + "o1js": "0.16.2", "postcss": "8.4.32", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/minauth-demo/minauth-demo-server/package.json b/minauth-demo/minauth-demo-server/package.json index b7b1f9b..ca5de1f 100644 --- a/minauth-demo/minauth-demo-server/package.json +++ b/minauth-demo/minauth-demo-server/package.json @@ -33,7 +33,7 @@ "minauth-erc721-timelock-plugin": "0.10.0-alpha", "minauth-merkle-membership-plugin": "0.10.0-alpha", "minauth-simple-preimage-plugin": "0.10.0-alpha", - "o1js": "0.16.0", + "o1js": "0.16.2", "passport": "^0.6.0", "passport-jwt": "^4.0.1", "passport-strategy": "^1.0.0", diff --git a/minauth-plugins/minauth-erc721-timelock-plugin/package-lock.json b/minauth-plugins/minauth-erc721-timelock-plugin/package-lock.json index 773a1a4..7539219 100644 --- a/minauth-plugins/minauth-erc721-timelock-plugin/package-lock.json +++ b/minauth-plugins/minauth-erc721-timelock-plugin/package-lock.json @@ -1,12 +1,12 @@ { "name": "minauth-erc721-timelock-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minauth-erc721-timelock-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "license": "Apache-2.0", "dependencies": { "@types/node": "^20.10.5", @@ -14,7 +14,7 @@ "ethers": "^6.9.1", "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "minauth": "0.10.1-alpha", "web3": "^4.3.0", "zod": "^3.22.2" }, @@ -39,7 +39,7 @@ "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -57,13 +57,13 @@ "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -1271,14 +1271,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz", - "integrity": "sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -1294,9 +1294,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1309,9 +1309,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", - "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1669,9 +1669,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.22.tgz", - "integrity": "sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==", + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", "dependencies": { "undici-types": "~5.26.4" } @@ -2286,12 +2286,12 @@ "peer": true }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -2299,7 +2299,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -2459,9 +2459,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001591", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", - "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", + "version": "1.0.30001594", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001594.tgz", + "integrity": "sha512-VblSX6nYqyJVs8DKFMldE2IVCJjZ225LW00ydtUWwh5hk9IfkTOffO6r8gJNsH0qqqeAF8KrbMYA2VEwTlGW5g==", "dev": true, "funding": [ { @@ -2951,9 +2951,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.686", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.686.tgz", - "integrity": "sha512-3avY1B+vUzNxEgkBDpKOP8WarvUAEwpRaiCL0He5OKWEFxzaOFiq4WoZEZe7qh0ReS7DiWoHMnYoQCKxNZNzSg==", + "version": "1.4.693", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.693.tgz", + "integrity": "sha512-/if4Ueg0GUQlhCrW2ZlXwDAm40ipuKo+OgeHInlL8sbjt+hzISxZK949fZeJaVsheamrzANXvw1zQTvbxTvSHw==", "dev": true }, "node_modules/emittery": { @@ -3410,13 +3410,13 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -5296,9 +5296,9 @@ } }, "node_modules/minauth": { - "version": "0.10.0-alpha", - "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.0-alpha.tgz", - "integrity": "sha512-L4GXlthfKt+jefDtX+ghcHG5HGTyRuf7ZGbNmswLk+OneyZhvXlV4ppylkT9lmqKNTX4iUV1olq629rII7ezug==", + "version": "0.10.1-alpha", + "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.1-alpha.tgz", + "integrity": "sha512-CgBpJg2x+1ch9JGxRUp9NAujoNygNLrVOrz6PXSJutFK39zc/MPRNertXm/8roIA/mr+1u7V+Cen5tVJ4sw7KA==", "dependencies": { "@types/http-proxy-middleware": "^1.0.0", "axios": "^1.5.0", @@ -5319,57 +5319,7 @@ "zod": "^3.22.2" }, "peerDependencies": { - "o1js": "0.16.0" - } - }, - "node_modules/minauth/node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/minauth/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/minauth/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/minauth/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" + "o1js": "0.16.2" } }, "node_modules/minimatch": { @@ -5576,9 +5526,9 @@ } }, "node_modules/o1js": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.0.tgz", - "integrity": "sha512-H6fKHLgH68v18De0tZydQKqF2bOIvF+EsPHJ+P53dJDOaS7Dlp8Uf4hGVo8S8luCfYsFvCdDGU3YwfegfCk6TQ==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.2.tgz", + "integrity": "sha512-CyQFURc2UzzNpPJcYUdvFqa6I7SjXksDCubgJixWjEoS3R+FOl/yttMwOwopxb3oLLK92MyD2ZM/OEdKqVUyyg==", "peer": true, "dependencies": { "blakejs": "1.2.1", @@ -6106,9 +6056,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -6430,11 +6380,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -7606,9 +7556,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "bin": { "yaml": "bin.mjs" }, diff --git a/minauth-plugins/minauth-erc721-timelock-plugin/package.json b/minauth-plugins/minauth-erc721-timelock-plugin/package.json index 34a747b..efe351a 100644 --- a/minauth-plugins/minauth-erc721-timelock-plugin/package.json +++ b/minauth-plugins/minauth-erc721-timelock-plugin/package.json @@ -1,6 +1,6 @@ { "name": "minauth-erc721-timelock-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "description": "", "type": "module", "files": [ @@ -18,12 +18,12 @@ "ethers": "^6.9.1", "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "minauth": "0.10.1-alpha", "web3": "^4.3.0", "zod": "^3.22.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" }, "devDependencies": { "@types/axios": "^0.14.0", diff --git a/minauth-plugins/minauth-merkle-membership-plugin/package-lock.json b/minauth-plugins/minauth-merkle-membership-plugin/package-lock.json index f1909f7..791eef1 100644 --- a/minauth-plugins/minauth-merkle-membership-plugin/package-lock.json +++ b/minauth-plugins/minauth-merkle-membership-plugin/package-lock.json @@ -1,17 +1,17 @@ { "name": "minauth-merkle-membership-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minauth-merkle-membership-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "license": "Apache-2.0", "dependencies": { "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "minauth": "0.10.1-alpha", "zod": "^3.22.2" }, "devDependencies": { @@ -30,7 +30,7 @@ "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -372,9 +372,9 @@ "devOptional": true }, "node_modules/@types/node": { - "version": "20.11.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.22.tgz", - "integrity": "sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==", + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", "dependencies": { "undici-types": "~5.26.4" } @@ -784,12 +784,12 @@ "peer": true }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -797,7 +797,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -1445,13 +1445,13 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -2361,9 +2361,9 @@ } }, "node_modules/minauth": { - "version": "0.10.0-alpha", - "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.0-alpha.tgz", - "integrity": "sha512-L4GXlthfKt+jefDtX+ghcHG5HGTyRuf7ZGbNmswLk+OneyZhvXlV4ppylkT9lmqKNTX4iUV1olq629rII7ezug==", + "version": "0.10.1-alpha", + "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.1-alpha.tgz", + "integrity": "sha512-CgBpJg2x+1ch9JGxRUp9NAujoNygNLrVOrz6PXSJutFK39zc/MPRNertXm/8roIA/mr+1u7V+Cen5tVJ4sw7KA==", "dependencies": { "@types/http-proxy-middleware": "^1.0.0", "axios": "^1.5.0", @@ -2384,57 +2384,7 @@ "zod": "^3.22.2" }, "peerDependencies": { - "o1js": "0.16.0" - } - }, - "node_modules/minauth/node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/minauth/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/minauth/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/minauth/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" + "o1js": "0.16.2" } }, "node_modules/minimatch": { @@ -2596,9 +2546,9 @@ } }, "node_modules/o1js": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.0.tgz", - "integrity": "sha512-H6fKHLgH68v18De0tZydQKqF2bOIvF+EsPHJ+P53dJDOaS7Dlp8Uf4hGVo8S8luCfYsFvCdDGU3YwfegfCk6TQ==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.2.tgz", + "integrity": "sha512-CyQFURc2UzzNpPJcYUdvFqa6I7SjXksDCubgJixWjEoS3R+FOl/yttMwOwopxb3oLLK92MyD2ZM/OEdKqVUyyg==", "peer": true, "dependencies": { "blakejs": "1.2.1", @@ -2930,9 +2880,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -3159,11 +3109,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -3579,9 +3529,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "bin": { "yaml": "bin.mjs" }, diff --git a/minauth-plugins/minauth-merkle-membership-plugin/package.json b/minauth-plugins/minauth-merkle-membership-plugin/package.json index 8523f1a..e4b7ac5 100644 --- a/minauth-plugins/minauth-merkle-membership-plugin/package.json +++ b/minauth-plugins/minauth-merkle-membership-plugin/package.json @@ -1,6 +1,6 @@ { "name": "minauth-merkle-membership-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "description": "", "type": "module", "files": [ @@ -15,11 +15,11 @@ "dependencies": { "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "minauth": "0.10.1-alpha", "zod": "^3.22.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" }, "devDependencies": { "@types/axios": "^0.14.0", diff --git a/minauth-plugins/minauth-simple-preimage-plugin/package-lock.json b/minauth-plugins/minauth-simple-preimage-plugin/package-lock.json index 4e62ff4..59d1cee 100644 --- a/minauth-plugins/minauth-simple-preimage-plugin/package-lock.json +++ b/minauth-plugins/minauth-simple-preimage-plugin/package-lock.json @@ -1,17 +1,17 @@ { "name": "minauth-simple-preimage-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minauth-simple-preimage-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "license": "Apache-2.0", "dependencies": { "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "minauth": "0.10.1-alpha", "zod": "^3.22.2" }, "devDependencies": { @@ -30,7 +30,7 @@ "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -372,9 +372,9 @@ "devOptional": true }, "node_modules/@types/node": { - "version": "20.11.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.22.tgz", - "integrity": "sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==", + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", "dependencies": { "undici-types": "~5.26.4" } @@ -784,12 +784,12 @@ "peer": true }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -797,7 +797,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -1445,13 +1445,13 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -2361,9 +2361,9 @@ } }, "node_modules/minauth": { - "version": "0.10.0-alpha", - "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.0-alpha.tgz", - "integrity": "sha512-L4GXlthfKt+jefDtX+ghcHG5HGTyRuf7ZGbNmswLk+OneyZhvXlV4ppylkT9lmqKNTX4iUV1olq629rII7ezug==", + "version": "0.10.1-alpha", + "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.1-alpha.tgz", + "integrity": "sha512-CgBpJg2x+1ch9JGxRUp9NAujoNygNLrVOrz6PXSJutFK39zc/MPRNertXm/8roIA/mr+1u7V+Cen5tVJ4sw7KA==", "dependencies": { "@types/http-proxy-middleware": "^1.0.0", "axios": "^1.5.0", @@ -2384,57 +2384,7 @@ "zod": "^3.22.2" }, "peerDependencies": { - "o1js": "0.16.0" - } - }, - "node_modules/minauth/node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/minauth/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/minauth/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/minauth/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" + "o1js": "0.16.2" } }, "node_modules/minimatch": { @@ -2596,9 +2546,9 @@ } }, "node_modules/o1js": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.0.tgz", - "integrity": "sha512-H6fKHLgH68v18De0tZydQKqF2bOIvF+EsPHJ+P53dJDOaS7Dlp8Uf4hGVo8S8luCfYsFvCdDGU3YwfegfCk6TQ==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.2.tgz", + "integrity": "sha512-CyQFURc2UzzNpPJcYUdvFqa6I7SjXksDCubgJixWjEoS3R+FOl/yttMwOwopxb3oLLK92MyD2ZM/OEdKqVUyyg==", "peer": true, "dependencies": { "blakejs": "1.2.1", @@ -2930,9 +2880,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -3159,11 +3109,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -3579,9 +3529,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "bin": { "yaml": "bin.mjs" }, diff --git a/minauth-plugins/minauth-simple-preimage-plugin/package.json b/minauth-plugins/minauth-simple-preimage-plugin/package.json index 0a12328..6a5e1eb 100644 --- a/minauth-plugins/minauth-simple-preimage-plugin/package.json +++ b/minauth-plugins/minauth-simple-preimage-plugin/package.json @@ -1,6 +1,6 @@ { "name": "minauth-simple-preimage-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "description": "A very simple Minauth plugin that allows users to authenticate by providing a preimage to a given hash.", "type": "module", "main": "dist/index.js", @@ -18,7 +18,7 @@ "dependencies": { "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "minauth": "0.10.1-alpha", "zod": "^3.22.2" }, "devDependencies": { @@ -37,7 +37,7 @@ "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" }, "keywords": [ "authentication", diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json index 5e21e43..4e7ddf9 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json @@ -1,17 +1,20 @@ { "name": "minauth-verified-zkdocument-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minauth-verified-zkdocument-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "license": "Apache-2.0", "dependencies": { + "@types/luxon": "^3.4.2", "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "luxon": "^3.4.4", + "minauth": "0.10.1-alpha", + "o1js-pack": "^0.5.4", "zod": "^3.22.2" }, "devDependencies": { @@ -25,12 +28,12 @@ "eslint-plugin-prettier": "^5.0.0", "nodemon": "^3.0.1", "prettier": "^3.0.3", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -365,6 +368,11 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -2282,6 +2290,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -2361,9 +2377,9 @@ } }, "node_modules/minauth": { - "version": "0.10.0-alpha", - "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.0-alpha.tgz", - "integrity": "sha512-L4GXlthfKt+jefDtX+ghcHG5HGTyRuf7ZGbNmswLk+OneyZhvXlV4ppylkT9lmqKNTX4iUV1olq629rII7ezug==", + "version": "0.10.1-alpha", + "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.1-alpha.tgz", + "integrity": "sha512-CgBpJg2x+1ch9JGxRUp9NAujoNygNLrVOrz6PXSJutFK39zc/MPRNertXm/8roIA/mr+1u7V+Cen5tVJ4sw7KA==", "dependencies": { "@types/http-proxy-middleware": "^1.0.0", "axios": "^1.5.0", @@ -2384,7 +2400,7 @@ "zod": "^3.22.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" } }, "node_modules/minimatch": { @@ -2546,9 +2562,9 @@ } }, "node_modules/o1js": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.0.tgz", - "integrity": "sha512-H6fKHLgH68v18De0tZydQKqF2bOIvF+EsPHJ+P53dJDOaS7Dlp8Uf4hGVo8S8luCfYsFvCdDGU3YwfegfCk6TQ==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.2.tgz", + "integrity": "sha512-CyQFURc2UzzNpPJcYUdvFqa6I7SjXksDCubgJixWjEoS3R+FOl/yttMwOwopxb3oLLK92MyD2ZM/OEdKqVUyyg==", "peer": true, "dependencies": { "blakejs": "1.2.1", @@ -2566,6 +2582,14 @@ "node": ">=16.4.0" } }, + "node_modules/o1js-pack": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/o1js-pack/-/o1js-pack-0.5.4.tgz", + "integrity": "sha512-qcrLVWNmB3Rw8IgNacWEP/Zk+IUVUvbcMxmmEWSvXSQ3hI+OxWOkGq60CXB7gjMlXYsJhUZ67zZABWt5uOxyYQ==", + "peerDependencies": { + "o1js": "^0.16.2" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -3109,11 +3133,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -3529,9 +3553,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "bin": { "yaml": "bin.mjs" }, diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json index e6da713..3d201fe 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/package.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json @@ -1,6 +1,6 @@ { "name": "minauth-verified-zkdocument-plugin", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "description": "Plugin for authorization with verified zk claims on 3rd-party approved documents.", "type": "module", "main": "dist/index.js", @@ -16,9 +16,12 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { + "@types/luxon": "^3.4.2", "express": "^4.18.2", "fp-ts": "^2.16.1", - "minauth": "0.10.0-alpha", + "luxon": "^3.4.4", + "minauth": "0.10.1-alpha", + "o1js-pack": "^0.5.4", "zod": "^3.22.2" }, "devDependencies": { @@ -32,12 +35,12 @@ "eslint-plugin-prettier": "^5.0.0", "nodemon": "^3.0.1", "prettier": "^3.0.3", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" }, "keywords": [ "authentication", diff --git a/minauth/package-lock.json b/minauth/package-lock.json index 25492ea..a42b6db 100644 --- a/minauth/package-lock.json +++ b/minauth/package-lock.json @@ -1,12 +1,12 @@ { "name": "minauth", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minauth", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "license": "Apache-2.0", "dependencies": { "@types/http-proxy-middleware": "^1.0.0", @@ -53,7 +53,7 @@ "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -66,13 +66,13 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -1269,14 +1269,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz", - "integrity": "sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -1292,9 +1292,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1307,9 +1307,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", - "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1605,9 +1605,9 @@ "devOptional": true }, "node_modules/@types/node": { - "version": "20.11.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.22.tgz", - "integrity": "sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==", + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", "dependencies": { "undici-types": "~5.26.4" } @@ -2411,9 +2411,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001591", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", - "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", + "version": "1.0.30001594", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001594.tgz", + "integrity": "sha512-VblSX6nYqyJVs8DKFMldE2IVCJjZ225LW00ydtUWwh5hk9IfkTOffO6r8gJNsH0qqqeAF8KrbMYA2VEwTlGW5g==", "dev": true, "funding": [ { @@ -2854,9 +2854,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.686", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.686.tgz", - "integrity": "sha512-3avY1B+vUzNxEgkBDpKOP8WarvUAEwpRaiCL0He5OKWEFxzaOFiq4WoZEZe7qh0ReS7DiWoHMnYoQCKxNZNzSg==", + "version": "1.4.693", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.693.tgz", + "integrity": "sha512-/if4Ueg0GUQlhCrW2ZlXwDAm40ipuKo+OgeHInlL8sbjt+hzISxZK949fZeJaVsheamrzANXvw1zQTvbxTvSHw==", "dev": true }, "node_modules/emittery": { @@ -3243,13 +3243,13 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -3283,29 +3283,6 @@ "node": ">= 0.10.0" } }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3319,20 +3296,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/express/node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5256,9 +5219,9 @@ } }, "node_modules/o1js": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.0.tgz", - "integrity": "sha512-H6fKHLgH68v18De0tZydQKqF2bOIvF+EsPHJ+P53dJDOaS7Dlp8Uf4hGVo8S8luCfYsFvCdDGU3YwfegfCk6TQ==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.2.tgz", + "integrity": "sha512-CyQFURc2UzzNpPJcYUdvFqa6I7SjXksDCubgJixWjEoS3R+FOl/yttMwOwopxb3oLLK92MyD2ZM/OEdKqVUyyg==", "peer": true, "dependencies": { "blakejs": "1.2.1", @@ -6079,11 +6042,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -6856,9 +6819,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "bin": { "yaml": "bin.mjs" }, diff --git a/minauth/package.json b/minauth/package.json index 81595f8..e2cb6f5 100644 --- a/minauth/package.json +++ b/minauth/package.json @@ -1,6 +1,6 @@ { "name": "minauth", - "version": "0.10.0-alpha", + "version": "0.10.1-alpha", "description": "A TypeScript library for building authentication systems on top of the Mina blockchain and other zero-knowledge proofs solutions.", "type": "module", "files": [ @@ -61,7 +61,7 @@ "typescript": "^5.2.2" }, "peerDependencies": { - "o1js": "0.16.0" + "o1js": "0.16.2" }, "keywords": [ "authentication", From b07d55fb1bd67406723e7594104d1c3f6474a6b6 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Wed, 6 Mar 2024 19:21:22 +0100 Subject: [PATCH 04/34] More prototyping in the new plugin. --- .../README.md | 68 ++++++- .../src/index.ts | 47 +++++ .../src/plugin.ts | 9 +- .../src/prover.ts | 8 +- .../src/vc-data-model.ts | 48 +++++ .../src/zkclaims/VCredProof.ts | 178 ++++++++++++++++++ .../src/zkclaims/claimProof.ts | 56 ++++++ .../src/zkclaims/claimProofExample.ts | 16 ++ .../src/zkclaims/rollupClaim.ts | 8 +- 9 files changed, 421 insertions(+), 17 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/vc-data-model.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProof.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProofExample.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md index 4afda60..f4c7ea9 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md @@ -1,3 +1,11 @@ +# TODO + +- more spec on the structure of claims, verifiable credentials, transformation into verifiable presentations. +- then credentials specs and the registry +- maybe add some diagrams + + + # MinAuth Verified ZK-Document Plugin 🚧 **DISCLAIMER**: The plugin & the documentation under development. @@ -8,6 +16,60 @@ It uses MINA's o1js library for its zero-knowledge proof part. The plugin allows to use zk cryptographically secure proofs of claims on the zk-documents to be used as a source of authentication. +## Simplified conceptual overview + +Plugin allows to assume one of roles: verifier, holder(prover), issuer. +The issuer issues claims on some subject (usually the holder). Sets of claims form 'credentials'. +Such credentials can then be passed to a credential holder. The credential holder may transform +them into 'presentations' in a way that verifiably preserve validity of the credentials. +The transformation involve deriving information from the credentials using ZK-proofs. +For example one can derive "age over 18" from a passport document issued by a nation state. +Then by providing them to 'verifiers' can get authorization in systems guarded by the verifiers. +There are some desirable characteristics that this plugin should have that are described below. + +## Verifiable Credentials W3C Standard Context + +The plugin will make use of or be inspired by the standards developed by W3C +on Verifiable Credentials. +The goal is to make design decisions that will be more easily portable to +more complex systems that are compatible with those standards and also to re-use +the conceptual work done on the development on those standards given the same end +goals that the projects share. +In particular (https://www.w3.org/TR/vc-data-model/)[Verifiable Credentials Data Model v1.1] +will be cited here for many system parts. + +### Basic concepts / Vocabulary + + - user agent - An entity that acts in the system on the behalf of a user performing one of the system roles (issuer, holder, verifier) + - claim - An assertion made about a subject. + - credential - A set of one or more claims made by an issuer. + - verifiable credential - a tamper-evident credential that has authorship that can be cryptographically verified. + - holder - A role an entity might perform by possessing one or more verifiable credentials and generating presentations from them. A holder is usually, but not always, a subject of the verifiable credentials they are holding. Holders store their credentials in credential repositories. + - issuer - A role an entity can perform by asserting claims about one or more subjects, creating a verifiable credential from these claims, and transmitting the verifiable credential to a holder. + - presentation - Data derived from one or more verifiable credentials, issued by one or more issuers, that is shared with a specific verifier. + - verifiable presentation - A tamper-evident presentation encoded in such a way that authorship of the data can be trusted after a process of cryptographic verification. Certain types of verifiable presentations might contain data that is synthesized from, but do not contain, the original verifiable credentials (for example, zero-knowledge proofs). + - subject - A thing about which claims are made. + - verifier - A role an entity performs by receiving one or more verifiable credentials, optionally inside a verifiable presentation for processing. + - verifiable data registry - A role a system might perform by mediating the creation and verification of identifiers, keys, and other relevant data, such as verifiable credential schemas, revocation registries, issuer public keys, and so on, which might be required to use verifiable credentials. + +### Desirable characteristics + + - Acting as issuer, holder, or verifier requires neither registration nor approval by any authority, as the trust involved is bilateral between parties. + - Issuers can issue verifiable credentials about any subject. + - Holders can receive verifiable credentials from anyone. + - Verifiable presentations allow any verifier to verify the authenticity of verifiable credentials from any issuer. + - Holders can interact with any issuer and any verifier through any user agent. + - Holders can share verifiable presentations, which can then be verified without revealing the identity of the verifier to the issuer. + - Holders can store verifiable credentials in any location, without affecting their verifiability and without the issuer knowing anything about where they are stored or when they are accessed. + - Holders can present verifiable presentations to any verifier without affecting authenticity of the claims and without revealing that action to the issuer. + - A verifier can verify verifiable presentations from any holder, containing proofs of claims from any issuer. + - Verification should not depend on direct interactions between issuers and verifiers. + - Verification should not reveal the identity of the verifier to any issuer. + - Issuers can issue revocable verifiable credentials. + - Revocation by the issuer should not reveal any identifying information about the subject, the holder, the specific verifiable credential, or the verifier. + - Issuers can disclose the revocation reason. + - Issuers revoking verifiable credentials should distinguish between revocation for cryptographic integrity (for example, the signing key is compromised) versus revocation for a status change (for example, the driver’s license is suspended). + ## Plugin's overview The simple example is the popular case of proving a credit score. @@ -16,11 +78,9 @@ There are 3 entities involved: - The verifying entity (verifier) - one that needs the proof - The credit score issuer (3rd party / issuer) - one that approves the validity of the document - The proving entity (prover) - one that is requested to prove the required claim. +- The verifiable data registry - additionally there is a passive 4th entity that is the legitimate source of claim standards. It, for example, could be a recognized repository with hashes pinned on-chain in a DAO-guarded contract, or publicly shared merkle map of standards. -Additionally there is a passive 4th entity that is the legitimate source of claim standards. -It could be a recognized repository with hashes pinned on-chain in a DAO-guarded contract. - -The verifier uses one of the required "credit score above X" claim proving programs to create +The verifier uses one of the required 'credit score above X' claim proving programs to create a proof against their document. The proof along the claim proving zkprogram verification key hash and other details such as the user's private key go into the authorization verifier. diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts new file mode 100644 index 0000000..4003152 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -0,0 +1,47 @@ +import { Field, verify } from "o1js"; +import { FakeP1, P1, VerifyProgram } from "./zkclaims/VCredProof.js"; + + +console.log("compiling p1"); +const p1vk = await P1.compile(); +console.log("compiling fakep1"); +const fakeP1vk = await FakeP1.compile(); +console.log("compiling verifyProgram"); +const verifyProgramVk = await VerifyProgram.compile(); + +// compare behabiour of VerifyProgram with FakeP1 and P1 + +console.log("create a proof for P1"); +const p1 = await P1.someMethod(new Field("123")); + +// create a proof for P1 + +console.log("create a proof for FakeP1"); +const fakeP1 = await FakeP1.someMethod(new Field("123")); + + +console.log("create a proof for verifyP1"); +const vp1 = await VerifyProgram.someMethod(new Field("123")); + +console.log("create a recursive proof for VerifyProgram"); +let proof +try{ +proof = await VerifyProgram.verifyP1(new Field(0), p1) + console.log("created a proof for VerifyProgram with P1") + + console.log("verify the proof for VerifyProgram"); + await verify(proof, verifyProgramVk.verificationKey); +} catch (e) { + console.log("cannot create a proof for VerifyProgram with P1") + console.log(e) +} + +try{ + proof = await VerifyProgram.verifyP1(new Field(0), vp1) + console.log("created a proof for VerifyProgram with VP1") + console.log("verify the proof for VerifyProgram"); + await verify(proof, verifyProgramVk.verificationKey); +} catch (e) { + console.log("cannot create a proof for VerifyProgram with VP1") + console.log(e) +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts index 259c8ac..7f36c27 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/plugin.ts @@ -6,7 +6,6 @@ import { outputInvalid, outputValid } from 'minauth/dist/plugin/plugintype.js'; -import ProvePreimageProgram from './hash-preimage-proof.js'; import { Router } from 'express'; import { z } from 'zod'; import { TsInterfaceType } from 'minauth/dist/plugin/interfacekind.js'; @@ -114,9 +113,11 @@ export class ZkDocumentClaimsPlugin configuration: Configuration, logger: Logger ): Promise { - const { verificationKey } = await ProvePreimageProgram.compile({ - cache: Cache.None - }); + // TODO + const verificationKey = undefined as unknown as VerificationKey; + // const { verificationKey } = await ProvePreimageProgram.compile({ + // cache: Cache.None + // }); return new ZkDocumentClaimsPlugin(verificationKey, logger); } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts index be9e0e3..90564bb 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/prover.ts @@ -39,10 +39,8 @@ export class ZkDocumentClaimsProver /** Build a proof. */ async prove(publicInput: Field, secretInput: Field): Promise { - this.logger.debug('Building proof started.'); - const proof = await ProvePreimageProgram.baseCase(publicInput, secretInput); - this.logger.debug('Building proof finished.'); - return proof.toJSON(); + this.logger.warn('TODO no proof'); + return undefined as unknown as JsonProof; } /** Fetches a list of hashes recognized by the server. */ @@ -57,7 +55,7 @@ export class ZkDocumentClaimsProver // you have a verification key acquired by using cached circuit AND // not build a proof locally, // but use a serialized one - it will hang during verification. - return await ProvePreimageProgram.compile({ cache: Cache.None }); + return undefined as unknown as { verificationKey: VerificationKey }; } /** Initialize the prover */ diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/vc-data-model.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/vc-data-model.ts new file mode 100644 index 0000000..d1c6000 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/vc-data-model.ts @@ -0,0 +1,48 @@ +import { DateTime } from 'luxon'; + +// This is a temporary file for prototyping data models related to the Verifiable Credentials. +// It will not only contain the data model but also the methods to interact with the data model. + +// json data model +type JsonValue = string | number | boolean | null | JsonObject | JsonArray; + +interface JsonObject { + [key: string]: JsonValue; +} + +interface JsonArray extends Array {} + + +type Entity = { + publicKey: string; +} + +export type Subject = Entity + +export type Issuer = Entity + + +/** + * A statement made by an entity about a subject. + */ +export type Claim = { + subject: Subject; + subjectProperty: string; // TODO: should these be somehow enumerated / registered? + propertyValue: JsonValue; +} + +export type CredentialSchema = { + id: string; +} + +/** + * Represents a Verifiable Credential. + */ +export type VCred = { + id: string; + issuer: Issuer; + claims: Claim[]; + credentialSchema: CredentialSchema; + issuanceDate?: DateTime; + expirationDate?: DateTime; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts new file mode 100644 index 0000000..f4350a4 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts @@ -0,0 +1,178 @@ +import { Signature, PublicKey, UInt32, SelfProof, Field, ZkProgram, Poseidon, CircuitString, Struct } from 'o1js'; + +export const MAX_VCRED_SIZE = 128; + +/** + What does it mean to validate a credential or when can we know that the claim + is based on a valid credential? + +``` + export type VCred = { + id: string; + issuer: Issuer; + claims: Claim[]; + credentialSchema: CredentialSchema; + issuanceDate?: DateTime; + expirationDate?: DateTime; + } +``` + + From this data model, we need to be able to derive data that contains the following: + +``` + export class VCredStruct extends Struct({ + + id: Field; + issuer: PublicKey; + + issuanceDate: Field; // UTC timestamp + expirationDate: Field; // UTC timestamp + + claims: Field[MAX_CLAIMS_SIZE]; + + credentialSchema: Field; + + }) {} + +``` + + Then we need it it signed from the same public key that issued the credential. + Then we need a zk-program that will use this data to verify that the credential is valid, + i.e. + - the signature is valid + - the credential within validity period + And produce two verified hashes one of the entire credential and one of the claims. + */ + +/** For now, we will use a CircuitString to represent the claims. */ +export const Claims = CircuitString; + + +export class VCredValidationContext extends Struct({ + validationTime: Field, // UTC timestamp for which the validation is being done + signature: Signature, // The signature of the credential + verificationKeyHash: Field // The hash of the zk program that will be used to verify the credential +}) {} + +export class VCredStruct extends Struct({ + + id: Field, + issuer: PublicKey, + + issuanceDate: Field, // UTC timestamp + expirationDate: Field, // UTC timestamp + + claims: Claims, + + credentialSchema: Field, + + }) { + + public toFields() { + let fields = [ + this.id, + ...this.issuer.toFields(), + this.issuanceDate, + this.expirationDate, + this.claims, + this.credentialSchema + ]; + return fields; + } + +} + +export class VCredValidationOutput extends Struct({ + credentialHash: Field, + claimsHash: Field, +}) {}; + +export const ValidateVCredProgram = ZkProgram({ + name: 'ValidateVCred', + publicInput: VCredValidationContext, + publicOutput: VCredValidationOutput, + methods: { + validate: { + privateInputs: [VCredStruct], + method(publicInput: VCredValidationContext, cred: VCredStruct): VCredValidationOutput { + // Check the signature + publicInput.signature.verify(cred.issuer, cred.toFields()); + // Check the validity period + publicInput.validationTime.assertLessThanOrEqual(cred.expirationDate); + publicInput.validationTime.assertGreaterThanOrEqual(cred.issuanceDate); + // Produce the hashes + return new VCredValidationOutput({ + credentialHash: Poseidon.hash(cred.toFields()), + claimsHash: Poseidon.hash(cred.claims.toFields()) + }); + } + } + } +}); +export const P1 = ZkProgram({ + name: 'P1', + publicInput: Field, + methods: { + someMethod: { + privateInputs: [], + method(publicInput: Field) { + return publicInput; + } + } + } +}); + +export const FakeP1 = ZkProgram({ + name: 'P1', + publicInput: Field, + methods: { + someMethod: { + privateInputs: [], + method(publicInput: Field) { + return new Field("10101"); + } + } + } +}); + +export const VerifyProgram = ZkProgram({ + name: 'VerifyProgram', + publicInput: Field, + methods: { + verifyP1: { + privateInputs: [SelfProof], + method(publicInput: Field, secretInput: SelfProof) { + secretInput.verify(); + } + }, + someMethod: { + privateInputs: [], + method(publicInput: Field) { + return publicInput; + } + } + } +}); + +export const FakeValidateVCredProgram = ZkProgram({ + name: 'ValidateVCred', + publicInput: VCredValidationContext, + publicOutput: VCredValidationOutput, + methods: { + validate: { + privateInputs: [VCredStruct], + method(publicInput: VCredValidationContext, cred: VCredStruct): VCredValidationOutput { + // Check the signature + publicInput.signature.verify(cred.issuer, cred.toFields()); + // Check the validity period + publicInput.validationTime.assertLessThanOrEqual(cred.expirationDate); + publicInput.validationTime.assertGreaterThanOrEqual(cred.issuanceDate); + // Produce the hashes + return new VCredValidationOutput({ + credentialHash: Poseidon.hash(cred.toFields()), + claimsHash: Poseidon.hash(cred.claims.toFields()) + }); + } + } + } +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProof.ts new file mode 100644 index 0000000..b6d9f5e --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProof.ts @@ -0,0 +1,56 @@ +import { UInt32, Proof, Field, ZkProgram, Poseidon, CircuitString, Struct } from 'o1js'; + +export const MAX_VCRED_SIZE = 128; + +export class ClaimLocation extends Struct({ + start: UInt32, + end: UInt32 +}) {} + +export class ZkClaimPublicInput extends Struct({ + credentialHash: Field, + claimLocation: ClaimLocation, +}) {} + +export class ZkClaimSecretInput extends Struct({ + credential: CircuitString, +}) {} + +export class ZkClaimOutput extends Struct({ + resultValue: CircuitString, +}) {} + +export const ZkClaimProof = Proof; +export type ZkClaimProof = Proof; + + +export const RollupZkClaimProofProgram = ZkProgram({ + name: 'RollupClaimProof', + publicInput: ZkClaimPublicInput, + publicOutput: ZkClaimOutput, + + methods: { + rollup2: { + privateInputs: [ZkClaimProof, ZkClaimProof], + method(publicInput: ZkClaimPublicInput, proof1: ZkClaimProof, proof2: ZkClaimProof): ZkClaimOutput { + + // make sure that sub-proofs are concerned with the same credential + publicInput.credentialHash.assertEquals(proof1.publicInput.credentialHash); + publicInput.credentialHash.assertEquals(proof2.publicInput.credentialHash); + + // make sure that sub-proofs are concerned with the same claims + publicInput.claimLocation.start.assertLessThanOrEqual(proof1.publicInput.claimLocation.start); + publicInput.claimLocation.start.assertLessThanOrEqual(proof2.publicInput.claimLocation.start); + publicInput.claimLocation.end.assertGreaterThanOrEqual(proof1.publicInput.claimLocation.end); + publicInput.claimLocation.end.assertGreaterThanOrEqual(proof2.publicInput.claimLocation.end); + + proof1.verify(); + proof2.verify(); + + return new ZkClaimOutput({ resultValue: Poseidon.hash(proof1.publicOutput.resultValue.concat(proof2.publicOutput.resultValue).toFields()) }); + } + } + } +}); + + diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProofExample.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProofExample.ts new file mode 100644 index 0000000..bf05534 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/claimProofExample.ts @@ -0,0 +1,16 @@ + + +const someCredentialClaims = [ + { + subjectProperty: "name", + propertyValue: "Alice" + }, + { + subjectProperty: "age", + propertyValue: "25" + }, + { + subjectProperty: "creditScore", + propertyValue: "25" + } +]; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts index fde980b..a3db103 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/rollupClaim.ts @@ -15,15 +15,15 @@ const prog = ZkProgram({ methods: { fromFieldClaim: { - privateInputs: [Proof], - method(publicInput: CircuitString, fieldClaimProof: Proof) { + privateInputs: [Proof], + method(publicInput: CircuitString, fieldClaimProof: Proof) { fieldClaimProof.verify(); return fieldClaimProof.publicOutput; } }, rollupClaims: { - privateInputs: [Proof, Proof], - method(claim1: Proof, claim2: Proof) { + privateInputs: [Proof, Proof], + method(claim1: Proof, claim2: Proof) { claim1.verify(); claim2.verify(); return claim1.publicOutput; From 8a75ff6d98f3188841b60b07d399fcb46d699ab9 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Fri, 8 Mar 2024 16:26:04 +0100 Subject: [PATCH 05/34] Finalize verifiable credential circuit-related module. --- .../src/index.ts | 2 +- .../src/zkclaims/VCredProof.ts | 178 ----------------- .../src/zkclaims/vcred-proof.ts | 181 ++++++++++++++++++ 3 files changed, 182 insertions(+), 179 deletions(-) delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 4003152..a576b21 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -37,7 +37,7 @@ proof = await VerifyProgram.verifyP1(new Field(0), p1) } try{ - proof = await VerifyProgram.verifyP1(new Field(0), vp1) + proof = await VerifyProgram.verifyP1(new Field(0), fakeP1) console.log("created a proof for VerifyProgram with VP1") console.log("verify the proof for VerifyProgram"); await verify(proof, verifyProgramVk.verificationKey); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts deleted file mode 100644 index f4350a4..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/VCredProof.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { Signature, PublicKey, UInt32, SelfProof, Field, ZkProgram, Poseidon, CircuitString, Struct } from 'o1js'; - -export const MAX_VCRED_SIZE = 128; - -/** - What does it mean to validate a credential or when can we know that the claim - is based on a valid credential? - -``` - export type VCred = { - id: string; - issuer: Issuer; - claims: Claim[]; - credentialSchema: CredentialSchema; - issuanceDate?: DateTime; - expirationDate?: DateTime; - } -``` - - From this data model, we need to be able to derive data that contains the following: - -``` - export class VCredStruct extends Struct({ - - id: Field; - issuer: PublicKey; - - issuanceDate: Field; // UTC timestamp - expirationDate: Field; // UTC timestamp - - claims: Field[MAX_CLAIMS_SIZE]; - - credentialSchema: Field; - - }) {} - -``` - - Then we need it it signed from the same public key that issued the credential. - Then we need a zk-program that will use this data to verify that the credential is valid, - i.e. - - the signature is valid - - the credential within validity period - And produce two verified hashes one of the entire credential and one of the claims. - */ - -/** For now, we will use a CircuitString to represent the claims. */ -export const Claims = CircuitString; - - -export class VCredValidationContext extends Struct({ - validationTime: Field, // UTC timestamp for which the validation is being done - signature: Signature, // The signature of the credential - verificationKeyHash: Field // The hash of the zk program that will be used to verify the credential -}) {} - -export class VCredStruct extends Struct({ - - id: Field, - issuer: PublicKey, - - issuanceDate: Field, // UTC timestamp - expirationDate: Field, // UTC timestamp - - claims: Claims, - - credentialSchema: Field, - - }) { - - public toFields() { - let fields = [ - this.id, - ...this.issuer.toFields(), - this.issuanceDate, - this.expirationDate, - this.claims, - this.credentialSchema - ]; - return fields; - } - -} - -export class VCredValidationOutput extends Struct({ - credentialHash: Field, - claimsHash: Field, -}) {}; - -export const ValidateVCredProgram = ZkProgram({ - name: 'ValidateVCred', - publicInput: VCredValidationContext, - publicOutput: VCredValidationOutput, - methods: { - validate: { - privateInputs: [VCredStruct], - method(publicInput: VCredValidationContext, cred: VCredStruct): VCredValidationOutput { - // Check the signature - publicInput.signature.verify(cred.issuer, cred.toFields()); - // Check the validity period - publicInput.validationTime.assertLessThanOrEqual(cred.expirationDate); - publicInput.validationTime.assertGreaterThanOrEqual(cred.issuanceDate); - // Produce the hashes - return new VCredValidationOutput({ - credentialHash: Poseidon.hash(cred.toFields()), - claimsHash: Poseidon.hash(cred.claims.toFields()) - }); - } - } - } -}); -export const P1 = ZkProgram({ - name: 'P1', - publicInput: Field, - methods: { - someMethod: { - privateInputs: [], - method(publicInput: Field) { - return publicInput; - } - } - } -}); - -export const FakeP1 = ZkProgram({ - name: 'P1', - publicInput: Field, - methods: { - someMethod: { - privateInputs: [], - method(publicInput: Field) { - return new Field("10101"); - } - } - } -}); - -export const VerifyProgram = ZkProgram({ - name: 'VerifyProgram', - publicInput: Field, - methods: { - verifyP1: { - privateInputs: [SelfProof], - method(publicInput: Field, secretInput: SelfProof) { - secretInput.verify(); - } - }, - someMethod: { - privateInputs: [], - method(publicInput: Field) { - return publicInput; - } - } - } -}); - -export const FakeValidateVCredProgram = ZkProgram({ - name: 'ValidateVCred', - publicInput: VCredValidationContext, - publicOutput: VCredValidationOutput, - methods: { - validate: { - privateInputs: [VCredStruct], - method(publicInput: VCredValidationContext, cred: VCredStruct): VCredValidationOutput { - // Check the signature - publicInput.signature.verify(cred.issuer, cred.toFields()); - // Check the validity period - publicInput.validationTime.assertLessThanOrEqual(cred.expirationDate); - publicInput.validationTime.assertGreaterThanOrEqual(cred.issuanceDate); - // Produce the hashes - return new VCredValidationOutput({ - credentialHash: Poseidon.hash(cred.toFields()), - claimsHash: Poseidon.hash(cred.claims.toFields()) - }); - } - } - } -}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts new file mode 100644 index 0000000..dc89d84 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts @@ -0,0 +1,181 @@ +/** @module VCredProof + +This module contains the data model and zk-programs for creating and verifing +circuit compatible Verifiable Credentials (VCreds). + + */ +import { + Signature, + PublicKey, + Field, + ZkProgram, + Poseidon, + Struct, + CircuitString +} from 'o1js'; + +// Constants +export const MAX_VCRED_SIZE = 128; + +/** + * Represents the claims as a CircuitString. + * It's like Field[128] but has necessary interfaces for the circuit. + */ +export const Claims = CircuitString; + +/** + * Represents an issuer with a public key. Future versions might replace this + * with a more complex ID system, such as DIDs. + */ +export class Issuer extends Struct({ + pubkey: PublicKey +}) { + public toFields() { + return this.pubkey.toFields(); + } +} + +/** + * Represents a unique identifier for a credential schema. + */ +export class CredentialSchemaId extends Struct({ + credId: Field +}) { + public toFields() { + return [this.credId]; + } +} + +/** + * Represents a Verifiable Credential (VCred) with its associated data. + */ +export class VCredStruct extends Struct({ + id: Field, + issuer: Issuer, + issuanceDate: Field, // UTC timestamp + expirationDate: Field, // UTC timestamp + claims: Claims, + credentialSchema: CredentialSchemaId, + signature: Signature +}) { + // without the signature - for the signature verification + public contentToFields() { + return [ + this.id, + ...this.issuer.toFields(), + this.issuanceDate, + this.expirationDate, + this.claims, + ...this.credentialSchema.toFields() + ]; + } + + public toFields() { + return [...this.contentToFields(), ...this.signature.toFields()]; + } +} + +/** + * Context for VCred validation, defining the valid timeframe. + * The fields are UTC Unix timestamps. + */ +export class VCredValidationContext extends Struct({ + validFrom: Field, + validTo: Field +}) {} + +/** + * Output of the VCred validation process. + * In order to make sense of the credential proof, you have to be able to guess + * the issuer and the credential schema. + * Additionally to further assert the validity of any of the credential's claims + * you have to know the salt used to create the claims hash. + */ +export class VCredValidationOutput extends Struct({ + // Hash combining hasshes of the issuer's public key and the credential schema. + identificationHash: Field, + // Salted hash of the credential's claims. No attacks possible against simple claims "{age: 18}". + saltedClaimsHash: Field +}) {} + +/** + * ZkProgram for validating Verifiable Credentials (VCreds). + + What does it mean to validate a credential or when can we know that the claim + is based on a valid credential? + + ``` + export type VCred = { + id: string; + issuer: Issuer; + claims: Claim[]; + credentialSchema: CredentialSchema; + issuanceDate?: DateTime; + expirationDate?: DateTime; + signature: Signature; + } + ``` + + From this data model, we need to be able to derive data that contains the following: + + ``` + export class VCredStruct extends Struct({ + id: Field, + + credentialSchema: CredentialSchemaId, + claims: Claims, + + issuanceDate: Field, // UTC timestamp + expirationDate: Field, // UTC timestamp + + issuer: Issuer, + signature: Signature + }) { + + Then we need a zk-program that will use this data to verify that the credential is valid, + i.e. + - The signature must be made with a private key matching `issuer` public key. + - The credential is valid withing a given validity period. + The zk program does not reveal any information about the credential, but it produces two verified hashes: + - First for veryfing the credential's identification ( issuer x credential schema) + - Second for verifying the credential's claims. + */ +export const ValidateVCredProgram = ZkProgram({ + name: 'ValidateVCred', + publicInput: VCredValidationContext, + publicOutput: VCredValidationOutput, + methods: { + validate: { + privateInputs: [VCredStruct, Field], + method( + publicInput: VCredValidationContext, + cred: VCredStruct, + claimsSalt: Field + ): VCredValidationOutput { + // Verify the credential's signature. + cred.signature.verify(cred.issuer.pubkey, cred.contentToFields()); + + // Ensure the credential is within the validity period. + publicInput.validFrom.assertGreaterThanOrEqual( + cred.issuanceDate, + 'Credential is not yet valid.' + ); + publicInput.validTo.assertLessThanOrEqual( + cred.expirationDate, + 'Credential has expired.' + ); + + // Calculate hashes for credential identification and claims verification. + const identificationHash = Poseidon.hash([ + Poseidon.hash(cred.issuer.toFields()), + Poseidon.hash([...cred.credentialSchema.toFields(), claimsSalt]) + ]); + + return new VCredValidationOutput({ + identificationHash, + saltedClaimsHash: Poseidon.hash(cred.claims.toFields()) + }); + } + } + } +}); From 5e2362ce0d233dd41e21551b87edfdd654b597ee Mon Sep 17 00:00:00 2001 From: adamczykm Date: Fri, 8 Mar 2024 18:23:40 +0100 Subject: [PATCH 06/34] Add initial (circuit-part) revised implementation of zkclaim provers. --- .../src/zkclaims/vcred-proof.ts | 21 +++--- .../src/zkclaims/zkclaim-proof.ts | 75 +++++++++++++++++++ 2 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts index dc89d84..bffde8b 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts @@ -14,14 +14,17 @@ import { CircuitString } from 'o1js'; -// Constants -export const MAX_VCRED_SIZE = 128; - /** * Represents the claims as a CircuitString. * It's like Field[128] but has necessary interfaces for the circuit. */ -export const Claims = CircuitString; +export class Claims extends Struct({ + claims: CircuitString +}) { + public toFields() { + return this.claims.toFields(); + } +} /** * Represents an issuer with a public key. Future versions might replace this @@ -65,7 +68,7 @@ export class VCredStruct extends Struct({ ...this.issuer.toFields(), this.issuanceDate, this.expirationDate, - this.claims, + ...this.claims.toFields(), ...this.credentialSchema.toFields() ]; } @@ -158,22 +161,22 @@ export const ValidateVCredProgram = ZkProgram({ // Ensure the credential is within the validity period. publicInput.validFrom.assertGreaterThanOrEqual( cred.issuanceDate, - 'Credential is not yet valid.' + "Valid from date cannot be set before the credential's issuance date." ); publicInput.validTo.assertLessThanOrEqual( cred.expirationDate, - 'Credential has expired.' + "Valid to date cannot be set after the credential's expiration date." ); // Calculate hashes for credential identification and claims verification. const identificationHash = Poseidon.hash([ Poseidon.hash(cred.issuer.toFields()), - Poseidon.hash([...cred.credentialSchema.toFields(), claimsSalt]) + Poseidon.hash(cred.credentialSchema.toFields()) ]); return new VCredValidationOutput({ identificationHash, - saltedClaimsHash: Poseidon.hash(cred.claims.toFields()) + saltedClaimsHash: Poseidon.hash([...cred.claims.toFields(), claimsSalt]) }); } } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts new file mode 100644 index 0000000..222eac5 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts @@ -0,0 +1,75 @@ +import { CircuitString, Struct, Field, Poseidon, ZkProgram } from 'o1js'; +import { Claims } from './vcred-proof'; + +// TODO consider renaming salt to password +/** The verification of claims is secured with additional salt */ +export class ZkClaimValidationContext extends Struct({ + saltedClaimsHash: Field +}) {} + +/** The assumption is that the computation is done both in the zk proof + * and outside of it. Then the outside computation is verified by the hash + * produced by the ZkClaimProver in `outputVerificationHash`. + */ +export class ZkClaimProofOutput extends Struct({ + outputVerificationHash: Field +}) {} + +/** Helper: wrap the actual logic with necessary tests and assertions */ +export const mkZkClaimProveMethod = + ({ proveMethod }: { proveMethod: (claims: Claims) => Field }) => + ( + publicInput: ZkClaimValidationContext, + claims: Claims, + claimsSalt: Field + ) => { + // verify the claims + const computedSaltedClaimsHash = Poseidon.hash([ + ...claims.toFields(), + claimsSalt + ]); + publicInput.saltedClaimsHash.assertEquals( + computedSaltedClaimsHash, + 'Claims hash does not match the expected value.' + ); + // mk the derived claim against the claims + const verificationHash = proveMethod(claims); + + // return the verification hash + return new ZkClaimProofOutput({ + outputVerificationHash: verificationHash + }); + }; + +export const mkZkClaimProverProgram = ({ name, proveMethod }) => { + const program = ZkProgram({ + name, + publicInput: ZkClaimValidationContext, + publicOutput: ZkClaimProofOutput, + methods: { + prove: { + privateInputs: [Claims, Field], + method: mkZkClaimProveMethod({ proveMethod }) + } + } + }); + + return { program }; +}; + +export const fieldNumberGreaterOrEqual = (fieldIndex: number, to: Field) => { + return { + claimProver: mkZkClaimProverProgram({ + name: 'fieldNumberGreaterOrEqual', + proveMethod: (claims: Claims) => { + const field = claims.toFields()[fieldIndex]; + field.assertGreaterThanOrEqual( + to, + `Field ${fieldIndex} must be greater or equal to ${to}` + ); + const msg = `Field ${fieldIndex} is greater or equal to ${to}`; + return Poseidon.hash(CircuitString.fromString(msg).toFields()); + } + }) + }; +}; From 82b4ca84aa3107f58774bb983e42b604ee1bbe66 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Fri, 8 Mar 2024 18:50:29 +0100 Subject: [PATCH 07/34] Add the proof rollup circuit part. --- .../src/zkclaims/vcred-proof.ts | 7 +- .../src/zkclaims/zkclaim-proof-rollup.ts | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts index bffde8b..e8a3b96 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts @@ -176,9 +176,14 @@ export const ValidateVCredProgram = ZkProgram({ return new VCredValidationOutput({ identificationHash, - saltedClaimsHash: Poseidon.hash([...cred.claims.toFields(), claimsSalt]) + saltedClaimsHash: Poseidon.hash([ + ...cred.claims.toFields(), + claimsSalt + ]) }); } } } }); + +export class ValidateVCredProof extends ZkProgram.Proof(ValidateVCredProgram) {} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts new file mode 100644 index 0000000..aad0a3d --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts @@ -0,0 +1,77 @@ +import { Field, Proof, SelfProof, Struct, ZkProgram} from 'o1js'; +import { ValidateVCredProof } from './vcred-proof'; +import { ZkClaimProofOutput, ZkClaimValidationContext } from './zkclaim-proof'; + +/** + * Context for VCred validation, defining the valid timeframe. + * The fields are UTC Unix timestamps. + */ +export class ZkClaimRollupValidationContext extends Struct({ + validFrom: Field, + validTo: Field, + identificationHash: Field, +}) {} + +/** The assumption is that the computation is done both in the zk proof + * and outside of it. + * During a rollup all the resulting derived claims are combined and the + * hash of results is combined as well. + */ +export class ZkClaimRollupProofOutput extends Struct({ + outputVerificationHash: Field +}) {} + +// TODO: needs to come from actual provers dynamically +// class proofType = ZkProgram.Proof(theprover); +class ZkClaimValidationProof extends Proof{} + +/** This Program allows to rollup multiple claims against a single VCred. + * The result will be a single proof. + * It is assumed that necessary data (required to match the proved output hash) + * is gathered outside of the built zk proof. + */ +export const ValidateZkClaimProgram = ZkProgram({ + name: 'ValidateZkClaim', + publicInput: ZkClaimRollupValidationContext, + publicOutput: ZkClaimRollupProofOutput, + methods: { + firstClaim: { + privateInputs: [ValidateVCredProof, ZkClaimValidationProof], + method( + publicInput: ZkClaimRollupValidationContext, + credProof: ValidateVCredProof, + claimProof: ZkClaimValidationProof, + ): ZkClaimRollupProofOutput { + + // verify proofs + credProof.verify(); + claimProof.verify(); + + // verify contexts + publicInput.identificationHash.assertEquals(credProof.publicOutput.identificationHash); + publicInput.validFrom.assertGreaterThanOrEqual(credProof.publicInput.validFrom); + publicInput.validTo.assertLessThanOrEqual(credProof.publicInput.validTo); + + // output + const verificationHash = claimProof.publicOutput.outputVerificationHash; + + return new ZkClaimRollupProofOutput({ outputVerificationHash: verificationHash }); + } + }, + recursiveClaim: { + privateInputs: [SelfProof, ZkClaimValidationProof], + method( + publicInput: ZkClaimRollupValidationContext, + rollupProof: SelfProof, + claimProof: ZkClaimValidationProof, + ): ZkClaimRollupProofOutput { + + // TODO + + return undefined as unknown as ZkClaimRollupProofOutput; + + } + } + } +}); + From 685c6b363252b339d3223abd6aab6f2e065d106a Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 9 Mar 2024 11:18:47 +0100 Subject: [PATCH 08/34] Clean prototyping module. Finish initial circuit implementation the claim rollup prover --- .../src/index.ts | 45 ----------- .../src/zkclaims/vcred-proof.ts | 2 +- .../src/zkclaims/zkclaim-proof-rollup.ts | 76 ++++++++++++++----- 3 files changed, 59 insertions(+), 64 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index a576b21..707f3e8 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,47 +1,2 @@ import { Field, verify } from "o1js"; -import { FakeP1, P1, VerifyProgram } from "./zkclaims/VCredProof.js"; - -console.log("compiling p1"); -const p1vk = await P1.compile(); -console.log("compiling fakep1"); -const fakeP1vk = await FakeP1.compile(); -console.log("compiling verifyProgram"); -const verifyProgramVk = await VerifyProgram.compile(); - -// compare behabiour of VerifyProgram with FakeP1 and P1 - -console.log("create a proof for P1"); -const p1 = await P1.someMethod(new Field("123")); - -// create a proof for P1 - -console.log("create a proof for FakeP1"); -const fakeP1 = await FakeP1.someMethod(new Field("123")); - - -console.log("create a proof for verifyP1"); -const vp1 = await VerifyProgram.someMethod(new Field("123")); - -console.log("create a recursive proof for VerifyProgram"); -let proof -try{ -proof = await VerifyProgram.verifyP1(new Field(0), p1) - console.log("created a proof for VerifyProgram with P1") - - console.log("verify the proof for VerifyProgram"); - await verify(proof, verifyProgramVk.verificationKey); -} catch (e) { - console.log("cannot create a proof for VerifyProgram with P1") - console.log(e) -} - -try{ - proof = await VerifyProgram.verifyP1(new Field(0), fakeP1) - console.log("created a proof for VerifyProgram with VP1") - console.log("verify the proof for VerifyProgram"); - await verify(proof, verifyProgramVk.verificationKey); -} catch (e) { - console.log("cannot create a proof for VerifyProgram with VP1") - console.log(e) -} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts index e8a3b96..0ff245f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts @@ -137,7 +137,7 @@ export class VCredValidationOutput extends Struct({ Then we need a zk-program that will use this data to verify that the credential is valid, i.e. - - The signature must be made with a private key matching `issuer` public key. + - The signature must be valid and made with a private key matching `issuer` public key. - The credential is valid withing a given validity period. The zk program does not reveal any information about the credential, but it produces two verified hashes: - First for veryfing the credential's identification ( issuer x credential schema) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts index aad0a3d..cb8f0cd 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts @@ -1,4 +1,4 @@ -import { Field, Proof, SelfProof, Struct, ZkProgram} from 'o1js'; +import { Poseidon, Field, Proof, SelfProof, Struct, ZkProgram } from 'o1js'; import { ValidateVCredProof } from './vcred-proof'; import { ZkClaimProofOutput, ZkClaimValidationContext } from './zkclaim-proof'; @@ -9,7 +9,7 @@ import { ZkClaimProofOutput, ZkClaimValidationContext } from './zkclaim-proof'; export class ZkClaimRollupValidationContext extends Struct({ validFrom: Field, validTo: Field, - identificationHash: Field, + vCredIdentificationHash: Field }) {} /** The assumption is that the computation is done both in the zk proof @@ -23,13 +23,16 @@ export class ZkClaimRollupProofOutput extends Struct({ // TODO: needs to come from actual provers dynamically // class proofType = ZkProgram.Proof(theprover); -class ZkClaimValidationProof extends Proof{} +class ZkClaimValidationProof extends Proof< + ZkClaimValidationContext, + ZkClaimProofOutput +> {} /** This Program allows to rollup multiple claims against a single VCred. - * The result will be a single proof. - * It is assumed that necessary data (required to match the proved output hash) - * is gathered outside of the built zk proof. - */ + * The result will be a single proof. + * It is assumed that necessary data (required to match the proved output hash) + * is gathered outside of the built zk proof. + */ export const ValidateZkClaimProgram = ZkProgram({ name: 'ValidateZkClaim', publicInput: ZkClaimRollupValidationContext, @@ -40,38 +43,75 @@ export const ValidateZkClaimProgram = ZkProgram({ method( publicInput: ZkClaimRollupValidationContext, credProof: ValidateVCredProof, - claimProof: ZkClaimValidationProof, + claimProof: ZkClaimValidationProof ): ZkClaimRollupProofOutput { - // verify proofs credProof.verify(); claimProof.verify(); // verify contexts - publicInput.identificationHash.assertEquals(credProof.publicOutput.identificationHash); - publicInput.validFrom.assertGreaterThanOrEqual(credProof.publicInput.validFrom); - publicInput.validTo.assertLessThanOrEqual(credProof.publicInput.validTo); + publicInput.vCredIdentificationHash.assertEquals( + credProof.publicOutput.identificationHash + ); + publicInput.validFrom.assertGreaterThanOrEqual( + credProof.publicInput.validFrom + ); + publicInput.validTo.assertLessThanOrEqual( + credProof.publicInput.validTo + ); + + // verify claim link to credential + claimProof.publicInput.saltedClaimsHash.assertEquals( + credProof.publicOutput.saltedClaimsHash + ); // output const verificationHash = claimProof.publicOutput.outputVerificationHash; - return new ZkClaimRollupProofOutput({ outputVerificationHash: verificationHash }); + return new ZkClaimRollupProofOutput({ + outputVerificationHash: verificationHash + }); } }, recursiveClaim: { privateInputs: [SelfProof, ZkClaimValidationProof], method( publicInput: ZkClaimRollupValidationContext, - rollupProof: SelfProof, - claimProof: ZkClaimValidationProof, + rollupProof: SelfProof< + ZkClaimRollupValidationContext, + ZkClaimRollupProofOutput + >, + claimProof: ZkClaimValidationProof ): ZkClaimRollupProofOutput { + // verify proofs + rollupProof.verify(); + claimProof.verify(); + + // verify contexts + publicInput.vCredIdentificationHash.assertEquals( + rollupProof.publicInput.vCredIdentificationHash + ); + publicInput.validFrom.assertGreaterThanOrEqual( + rollupProof.publicInput.validFrom + ); + publicInput.validTo.assertLessThanOrEqual( + rollupProof.publicInput.validTo + ); - // TODO + // verify claim link to rollup credential + claimProof.publicInput.saltedClaimsHash.assertEquals( + rollupProof.publicInput.vCredIdentificationHash + ); - return undefined as unknown as ZkClaimRollupProofOutput; + const outputVerificationHash = Poseidon.hash([ + rollupProof.publicOutput.outputVerificationHash, + claimProof.publicOutput.outputVerificationHash + ]); + return new ZkClaimRollupProofOutput({ + outputVerificationHash + }); } } } }); - From 266aba4ce279ea662fb2399beecf4bc1298cb8b2 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 9 Mar 2024 11:34:05 +0100 Subject: [PATCH 09/34] Make some minor fixes --- .../src/zkclaims/vcred-proof.ts | 6 +++--- .../src/zkclaims/zkclaim-proof-rollup.ts | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts index 0ff245f..108f3f7 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts @@ -41,7 +41,7 @@ export class Issuer extends Struct({ /** * Represents a unique identifier for a credential schema. */ -export class CredentialSchemaId extends Struct({ +export class CredentialSchemaHash extends Struct({ credId: Field }) { public toFields() { @@ -58,7 +58,7 @@ export class VCredStruct extends Struct({ issuanceDate: Field, // UTC timestamp expirationDate: Field, // UTC timestamp claims: Claims, - credentialSchema: CredentialSchemaId, + credentialSchema: CredentialSchemaHash, signature: Signature }) { // without the signature - for the signature verification @@ -125,7 +125,7 @@ export class VCredValidationOutput extends Struct({ export class VCredStruct extends Struct({ id: Field, - credentialSchema: CredentialSchemaId, + credentialSchema: CredentialSchemaHash, claims: Claims, issuanceDate: Field, // UTC timestamp diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts index cb8f0cd..acc779a 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts @@ -4,7 +4,7 @@ import { ZkClaimProofOutput, ZkClaimValidationContext } from './zkclaim-proof'; /** * Context for VCred validation, defining the valid timeframe. - * The fields are UTC Unix timestamps. + * The fields are Unix UTC timestamps. */ export class ZkClaimRollupValidationContext extends Struct({ validFrom: Field, @@ -16,6 +16,10 @@ export class ZkClaimRollupValidationContext extends Struct({ * and outside of it. * During a rollup all the resulting derived claims are combined and the * hash of results is combined as well. + * In the non-recursive case the rollupOutputVerificationHash is the same as + * claimOutputVerificationHash. + * In the recursive case the rollup resulting hash is computed like this: + * `hash(rollupOutputVerificationHash, claimOutputVerificationHash)` */ export class ZkClaimRollupProofOutput extends Struct({ outputVerificationHash: Field From a0597632540cee00cc8fbcdae3f27d974cd93b24 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 9 Mar 2024 19:38:09 +0100 Subject: [PATCH 10/34] Add auxiliary types for credential subjects. --- .../src/index.ts | 11 +- .../src/zkclaims/vcred-proof.ts | 147 +++++++++++++++++- .../src/zkclaims/zkclaim-proof.ts | 2 +- 3 files changed, 155 insertions(+), 5 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 707f3e8..097f86c 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,2 +1,11 @@ -import { Field, verify } from "o1js"; +import { Field, PrivateKey, verify } from "o1js"; +const p = PrivateKey.random(); + +const pk = p.toPublicKey(); + + +const pkf = pk.toFields(); + + +console.log(pkf.length); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts index 108f3f7..1c49448 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts @@ -11,19 +11,160 @@ import { ZkProgram, Poseidon, Struct, - CircuitString + CircuitString, + UInt32, + CircuitValue, + arrayProp } from 'o1js'; +import { __decorate, __metadata } from "tslib"; +import { PackedUInt32Factory } from 'o1js-pack'; + +export class IxRange extends Field { + public get first(): number { + return Number(PackedUInt32Factory().unpack(this)[0].toBigint()); + } + public get last(): number { + return Number(PackedUInt32Factory().unpack(this)[1].toBigint()); + } + + static fromNumbers(first: number, last: number): IxRange { + return new IxRange(PackedUInt32Factory().pack([new UInt32(first), new UInt32(last)])); + } +} + +// export class Fields extends CircuitValue { +// static maxLength = CircuitString.maxLength; + +// constructor(fields: Field[]) { +// super(fields); +// } + +// slice(ixRange: IxRange): Field[] { +// const first = ixRange.first; +// const last = ixRange.last; +// return new Fields(this.values.slice(first, last + 1)); +// } + + +// } + +// __decorate([ +// arrayProp(Field, CircuitString.maxLength), +// __metadata("design:type", Array) +// ], CircuitString.prototype, "values", void 0); /** - * Represents the claims as a CircuitString. + * Represents indices to a set of claims along with a subject + * against which they are made. + */ +export class CredClaimSubject extends Struct({ + pubKey: PublicKey, + claimsRange: IxRange +}) { + public toFields() { + return this.pubKey.toFields().concat(this.claimsRange.toFields()); + } + + static fromFields(fields: Field[]): CredClaimSubject { + return new CredClaimSubject({ + pubKey: new PublicKey(fields.slice(0, 2)), + claimsRange: new IxRange(fields.slice(2, 3)[0]) + }); + +} + + static createCredClaimSubjectsArray(fields: Field[]): CredClaimSubject[] { + // Check if the length of the fields array is divisible by 3 + if (fields.length % 3 !== 0) { + throw new Error('The array length must be divisible by 3.'); + } + + const credClaimSubjects: CredClaimSubject[] = []; + // Iterate over the fields array in steps of 3 + for (let i = 0; i < fields.length; i += 3) { + // Extract fields for a single CredClaimSubject + const pubKeyFields = fields.slice(i, i + 2); + const claimRangeField = fields[i + 2]; + + // Create a new CredClaimSubject instance and add it to the result array + const credClaimSubject = new CredClaimSubject({ + pubKey: new PublicKey(pubKeyFields), + claimsRange: new IxRange(claimRangeField) + }); + + credClaimSubjects.push(credClaimSubject); + } + + return credClaimSubjects; + } +} + +/** + * Represents the claims as a CircuitString (is it feasible?) * It's like Field[128] but has necessary interfaces for the circuit. */ export class Claims extends Struct({ - claims: CircuitString + // indices[i] : IxRange - the indices of the ith claims + indices: CircuitString, + // claims - the actual data indexed by the indices + // first field of the claim is the index of the pubkey + claims: CircuitString, + // in reality it's an array of `CredClaimSubject`s + subjects: CircuitString }) { public toFields() { return this.claims.toFields(); } + + static fromRecord(record: Map): Claims { + // Initialize arrays to hold indices and claim data. + let indicesArray: Field[] = []; + let claimsArray: Field[] = []; + let subjectsArray: Field[] = []; + + let claimIndex = 0; // To track the index of the claim. + + // Iterate over the record entries. + record.forEach((claims, pubKey) => { + + const firstSubjectClaimIndex = claimIndex; + + // Iterate over the claims associated with the public key. + claims.forEach((claimFields) => { + // Calculate the indices for this claim. + const firstIndex = claimIndex; + const lastIndex = claimIndex + claimFields.length - 1; + + const indices: IxRange = IxRange.fromNumbers(firstIndex, lastIndex); + + // Update the index for the next claim. + claimIndex = lastIndex + 1; + + // Add the indices to the indices array. + indicesArray.push(indices); + + // Add the claim fields to the claims array. + claimsArray = claimsArray.concat(claimFields); + + }); + + // Add the subject to the subjects array. + const subject = new CredClaimSubject({ + pubKey: pubKey, + claimsRange: IxRange.fromNumbers(firstSubjectClaimIndex, claimIndex - 1) + }); + + subjectsArray = subjectsArray.concat(subject.toFields()); + }); + + + // Return the new Claims instance. + return new Claims({ + indices: CircuitString.fromFields(indicesArray), + claims: claimsCircuitString, + subjects: subjectsCircuitString + }); + } } /** diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts index 222eac5..0e56a25 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof.ts @@ -41,7 +41,7 @@ export const mkZkClaimProveMethod = }); }; -export const mkZkClaimProverProgram = ({ name, proveMethod }) => { +export const mkZkClaimProverProgram = ({ name, proveMethod } : {name: string, proveMethod: any}) => { const program = ZkProgram({ name, publicInput: ZkClaimValidationContext, From 6e7dd7ec8d27d533a3b39f2ae8da55bbfb6d860c Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 9 Mar 2024 19:38:35 +0100 Subject: [PATCH 11/34] Make note in README about result of the implementation inquiry. --- .../minauth-verified-zkdocument-plugin/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md index f4c7ea9..6596759 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md @@ -16,6 +16,16 @@ It uses MINA's o1js library for its zero-knowledge proof part. The plugin allows to use zk cryptographically secure proofs of claims on the zk-documents to be used as a source of authentication. +## Important info + +- The documentation below became a bit outdated. +- An initial inquiry into the possible implementation of zk-circuits made it apparent that supporting + multi-subject credentials will make it much more complex and difficult. Such cases will mostly not + concern MinAuth and web authorization so in the first version it will be assumed that a credential + only have one subject and it will be represented by a MINA public key, as opposed to some more + involved identifiers. + + ## Simplified conceptual overview Plugin allows to assume one of roles: verifier, holder(prover), issuer. @@ -38,6 +48,7 @@ goals that the projects share. In particular (https://www.w3.org/TR/vc-data-model/)[Verifiable Credentials Data Model v1.1] will be cited here for many system parts. + ### Basic concepts / Vocabulary - user agent - An entity that acts in the system on the behalf of a user performing one of the system roles (issuer, holder, verifier) From 18e86744d370ed100b9c0a12c8069c9cb4ea59be Mon Sep 17 00:00:00 2001 From: adamczykm Date: Mon, 11 Mar 2024 17:26:39 +0100 Subject: [PATCH 12/34] Add happy path implementation / test plan. Define types and schemas for data --- .../package-lock.json | 1 + .../package.json | 1 + .../src/data/claims.ts | 33 +++++ .../src/data/ids.ts | 66 ++++++++++ .../src/data/simple.ts | 114 ++++++++++++++++++ .../src/data/vcred.ts | 99 +++++++++++++++ .../src/index.ts | 101 +++++++++++++++- .../src/zkclaims/vcred-proof.ts | 107 +++++++++------- .../src/zkclaims/zkclaim-proof-rollup.ts | 2 +- 9 files changed, 475 insertions(+), 49 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json index 4e7ddf9..f6135f1 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json @@ -15,6 +15,7 @@ "luxon": "^3.4.4", "minauth": "0.10.1-alpha", "o1js-pack": "^0.5.4", + "tslog": "^4.9.2", "zod": "^3.22.2" }, "devDependencies": { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json index 3d201fe..c2a1449 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/package.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json @@ -22,6 +22,7 @@ "luxon": "^3.4.4", "minauth": "0.10.1-alpha", "o1js-pack": "^0.5.4", + "tslog": "^4.9.2", "zod": "^3.22.2" }, "devDependencies": { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts new file mode 100644 index 0000000..78a9efb --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts @@ -0,0 +1,33 @@ +import {Struct, Provable, Field} from "o1js" +import {z} from "zod" +import {FieldsSchema} from "./simple.js" + +const CLAIMS_MAX_SIZE = 128; + +export function Claims(n: number) { + if (n > CLAIMS_MAX_SIZE) { + throw new Error(`Claims size ${n} exceeds the maximum size ${CLAIMS_MAX_SIZE}`); + } + + class Claims_ extends Struct({ + packed: Provable.Array(Field, n), + }) { + static MAX_SIZE = CLAIMS_MAX_SIZE; + + public toFields() { + return this.packed; + } + + static get schema() { + return z.object({ + packed: FieldsSchema.length(n) + }).transform((o) => new Claims_({ packed: o.packed })); + } + + public claim(r :{firstFieldIx: number, lastFieldIx: number }): Field[] { + return this.packed.slice(r.firstFieldIx, r.lastFieldIx+1); + } + } + + return Claims_; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts new file mode 100644 index 0000000..463e0ed --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts @@ -0,0 +1,66 @@ +import { + Field, + PublicKey, + Struct, +} from 'o1js'; +import { Logger } from 'tslog'; +import { z } from 'zod'; +import * as SimpleSchemas from './simple.js'; + +/** + * Represents an issuer with a public key. Future versions might replace this + * with a more complex ID system, such as DIDs. + */ +export class IssuerId extends Struct({ + pubkey: PublicKey +}) { + public toFields() { + return this.pubkey.toFields(); + } +} + +export const IssuerIdSchema = z + .object({ + pubkey: SimpleSchemas.PublicKeyB58Schema + }) + .transform((o) => new IssuerId({ pubkey: o.pubkey })); + +export class VCredId extends Struct({ + id: Field +}) { + public toFields() { + return this.id.toFields(); + } +} + +export const VCredIdSchema = z + .object({ + id: z.union([SimpleSchemas.FieldSchemaDec, SimpleSchemas.FieldSchemaHex]) + }) + .transform((o) => new VCredId({ id: o.id })); + +export const inline_tests = () => { + const log = new Logger({ name: 'simple schema inline tests' }); + + const issuer = IssuerIdSchema.parse({ + pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' + }); + log.info('Parsed issuer: ', issuer.toFields()); + + try { + IssuerIdSchema.parse({ pubkey: 'abc' }); + } catch (e) { + const err = e as z.ZodError; + log.debug('Caught error: ', err.message); + } + + const vcredid = VCredIdSchema.parse({ id: '123' }); + log.info('Parsed vcredid: ', vcredid.toFields()); + + try { + VCredIdSchema.parse({ id: 'abc' }); + } catch (e) { + const err = e as z.ZodError; + log.debug('Caught error: ', err.message); + } +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts new file mode 100644 index 0000000..3507256 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts @@ -0,0 +1,114 @@ +import { Field, PublicKey, Struct, Signature } from 'o1js'; +import { Logger } from 'tslog'; +import { z } from 'zod'; + +export const FieldSchemaDec = z.string().regex(/^\d+$/).transform(Field); +export const FieldSchemaHex = z + .string() + .regex(/^(0x|0X)?[0-9a-fA-F]+$/) + .transform((s) => Field(BigInt(s))); +export const FieldsSchema = z.array(z.union([FieldSchemaDec, FieldSchemaHex])); +export const Base58Schema = z.string().regex(/^[A-HJ-NP-Za-km-z1-9]+$/); +export const PublicKeyB58Schema = Base58Schema.length(55).transform( + PublicKey.fromBase58 +); +export const SignatureSchema = z + .object({ + signature: Base58Schema.length(96) + }) + .transform((o) => Signature.fromBase58(o.signature)); + +export class UnixTimestamp extends Struct({ + unixTimestamp: Field +}) { + public toFields() { + return this.unixTimestamp.toFields(); + } +} + +export const UnixTimestampSchema = z + .object({ + unixTimestamp: FieldSchemaDec + }) + .transform((o) => new UnixTimestamp({ unixTimestamp: o.unixTimestamp })); + + +export const inline_tests = () => { + const log = new Logger({ name: 'simple schema inline tests' }); + + // const PublicKeySchema = z.string().transform(PrivateKey.from); + const fielddecstr = '123'; + const field: Field = FieldSchemaDec.parse(fielddecstr); + log.info('Parsed field from dec encoding: ', fielddecstr, field.toString()); + try { + FieldSchemaDec.parse('abc'); + } catch (e) { + const err = e as z.ZodError; + log.debug('Caught error: ', err.message); + } + + const fieldhexstr = '0x123'; + const fieldhex: Field = FieldSchemaHex.parse(fieldhexstr); + log.info( + 'Parsed field from hex encoding: ', + fieldhexstr, + fieldhex.toString() + ); + try { + FieldSchemaHex.parse('0xzbc'); + } catch (e) { + const err = e as z.ZodError; + log.debug('Caught error: ', err.message); + } + + const fieldsencoded = ['123', '0x123']; + const fields: Field[] = FieldsSchema.parse(fieldsencoded); + log.info( + 'Parsed fields from encoded array: ', + fieldsencoded, + fields.map((f) => f.toString()) + ); + + const pubkeystr = 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL'; + const pubkey: PublicKey = PublicKeyB58Schema.parse(pubkeystr); + log.info('Parsed public key from base58: ', pubkeystr, pubkey.toBase58()); + try { + PublicKeyB58Schema.parse('abc'); + } catch (e) { + const err = e as z.ZodError; + log.debug('Caught error: ', err.message); + } + + // tests for unix timestamp + const unixTimestampStr = '123'; + const unixTimestamp: UnixTimestamp = UnixTimestampSchema.parse({ + unixTimestamp: unixTimestampStr + }); + log.info( + 'Parsed unix timestamp from dec encoding: ', + unixTimestampStr, + unixTimestamp.toFields() + ); + try { + UnixTimestampSchema.parse({ unixTimestamp: 'abc' }); + } catch (e) { + const err = e as z.ZodError; + log.debug('Caught error: ', err.message); + } + + const signature = SignatureSchema.parse({ + signature: + '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' + }); + log.info('Parsed signature: ', signature.toBase58()); + + try { + SignatureSchema.parse({ + signature: + 'mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' + }); + } catch (e) { + const err = e as z.ZodError; + log.debug('Caught error: ', err.message); + } +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts new file mode 100644 index 0000000..641e53e --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts @@ -0,0 +1,99 @@ +import { Struct, Field, PublicKey, Signature } from 'o1js'; +import { + UnixTimestamp, + UnixTimestampSchema, + PublicKeyB58Schema, + FieldSchemaDec, + FieldSchemaHex, + SignatureSchema +} from './simple.js'; +import { IssuerId, VCredId, VCredIdSchema, IssuerIdSchema } from './ids.js'; +import { Claims } from './claims.js'; +import { z } from 'zod'; + +export function VCredStructUnsigned(n: number) { + const ClaimsType = Claims(n); + + if (n <= 0 || n > ClaimsType.MAX_SIZE) { + // Adjust the limits as necessary. + throw new Error(`Invalid claims array size: ${n}`); + } + + const Fields = { + id: VCredId, + issuer: IssuerId, + issuanceDate: UnixTimestamp, + expirationDate: UnixTimestamp, + subject: PublicKey, + claims: ClaimsType, + credentialSchemaHash: Field + }; + + class BaseVCredStruct_ extends Struct(Fields) { + static Fields = Fields; + + public toFields() { + return [ + this.id, + ...this.issuer.toFields(), + this.issuanceDate, + this.expirationDate, + ...this.subject.toFields(), + ...this.claims.toFields(), + this.credentialSchemaHash + ]; + } + + static get dataSchema() { + return z.object({ + id: VCredIdSchema, + issuer: IssuerIdSchema, + issuanceDate: UnixTimestampSchema, + expirationDate: UnixTimestampSchema, + subject: PublicKeyB58Schema, + claims: ClaimsType.schema, + credentialSchemaHash: FieldSchemaDec.or(FieldSchemaHex) + }); + } + + static get schema() { + return BaseVCredStruct_.dataSchema.transform( + (data) => new BaseVCredStruct_(data) + ); + } + } + + return BaseVCredStruct_; +} + +export function VCredStruct(n: number) { + const BaseVCredStructType = VCredStructUnsigned(n); + + const Fields = { ...BaseVCredStructType.Fields, signature: Signature }; + + class VCredStruct_ extends Struct(Fields) { + static Fields = Fields; + + public contentToFields() { + return new BaseVCredStructType(this).toFields(); + } + + public toFields() { + return [...this.contentToFields(), ...this.signature.toFields()]; + } + + static get dataSchema() { + return BaseVCredStructType.dataSchema.extend({ + signature: SignatureSchema + }); + } + + static get schema() { + return VCredStruct_.dataSchema.transform( + (data) => new VCredStruct_(data) + ); + } + } + + return VCredStruct_; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 097f86c..50d876d 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,11 +1,106 @@ -import { Field, PrivateKey, verify } from "o1js"; +import { Field, PrivateKey, Provable, PublicKey, Signature, Struct, verify } from 'o1js'; +import { Logger } from 'tslog'; +import { z } from 'zod'; +import * as Simple from './data/simple.js'; +import * as Ids from './data/ids.js'; +import { IxRange } from './zkclaims/vcred-proof.js'; + +const log = new Logger({ name: 'index.ts prototyping' }); + +log.info('Happy path testing...'); + +log.info('========= Schemas ========='); + +// SimpleSchemas.inline_tests(); + + + +// /** +// * Represents an issuer with a public key. Future versions might replace this +// * with a more complex ID system, such as DIDs. +// */ +// export class IssuerId extends Struct({ +// pubkey: PublicKey +// }) { +// public toFields() { +// return this.pubkey.toFields(); +// } +// } + +// const IssuerIdSchema = PublicKeyB58Schema; +// type IssuerId = z.infer; + +log.info('Creating a new credential schema'); + +log.info('Registering the new credential schema'); + +log.info('Issuing a credential'); + +log.info('Delivering the credential to the holder '); + +log.info(' 1. simplest way possible'); + +log.info(' 2. (maybe later) on valid pkey proof '); + +log.info('========= Holder / Prover ========='); + +log.info('Requesting a credential'); + +log.info('Installing in the credential store'); + +log.info('(later) Requesting a resource access schema'); + +// // for example somthing akin to: +// [{ access: ["read"], +// , credentials: [ +// { schemaIdentificationHash: "" +// } ] +// , claimProofVerificationKeyHash: "" +// , expectedProofPublicOutput: "" +// , minValidRange: {"from", "to"} +// , nonRevocationProof: true // (later) +// }, +// ... +// ] +// }, +// { access: ["read","write"] +// , ... +// } +// ] +log.info('(later) searching for the proof path with resource access schema'); + +log.info('Building the proof as per the proof path'); + +log.info('Requesting access to the resource with the proof'); + +log.info('Disabling/deleting credential'); + +log.info('========= Verifier / Plugin ========='); + +log.info('Accessing schema registry'); + +log.info( + 'Assembling the config - \ + that includes a resource access schema' +); + +log.info('Setting up prover routes'); + +log.info('Verifying proofs'); + +log.info('Checking outputs validity'); + +log.info('Revocation proofs'); + +log.info(''); const p = PrivateKey.random(); const pk = p.toPublicKey(); - const pkf = pk.toFields(); - console.log(pkf.length); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts index 1c49448..a8c85cb 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/vcred-proof.ts @@ -13,8 +13,6 @@ import { Struct, CircuitString, UInt32, - CircuitValue, - arrayProp } from 'o1js'; import { __decorate, __metadata } from "tslib"; import { PackedUInt32Factory } from 'o1js-pack'; @@ -116,55 +114,55 @@ export class Claims extends Struct({ return this.claims.toFields(); } - static fromRecord(record: Map): Claims { - // Initialize arrays to hold indices and claim data. - let indicesArray: Field[] = []; - let claimsArray: Field[] = []; - let subjectsArray: Field[] = []; + // static fromRecord(record: Map): Claims { + // // Initialize arrays to hold indices and claim data. + // let indicesArray: Field[] = []; + // let claimsArray: Field[] = []; + // let subjectsArray: Field[] = []; - let claimIndex = 0; // To track the index of the claim. + // let claimIndex = 0; // To track the index of the claim. - // Iterate over the record entries. - record.forEach((claims, pubKey) => { + // // Iterate over the record entries. + // record.forEach((claims, pubKey) => { - const firstSubjectClaimIndex = claimIndex; + // const firstSubjectClaimIndex = claimIndex; - // Iterate over the claims associated with the public key. - claims.forEach((claimFields) => { - // Calculate the indices for this claim. - const firstIndex = claimIndex; - const lastIndex = claimIndex + claimFields.length - 1; + // // Iterate over the claims associated with the public key. + // claims.forEach((claimFields) => { + // // Calculate the indices for this claim. + // const firstIndex = claimIndex; + // const lastIndex = claimIndex + claimFields.length - 1; - const indices: IxRange = IxRange.fromNumbers(firstIndex, lastIndex); + // const indices: IxRange = IxRange.fromNumbers(firstIndex, lastIndex); - // Update the index for the next claim. - claimIndex = lastIndex + 1; + // // Update the index for the next claim. + // claimIndex = lastIndex + 1; - // Add the indices to the indices array. - indicesArray.push(indices); + // // Add the indices to the indices array. + // indicesArray.push(indices); - // Add the claim fields to the claims array. - claimsArray = claimsArray.concat(claimFields); + // // Add the claim fields to the claims array. + // claimsArray = claimsArray.concat(claimFields); - }); + // }); - // Add the subject to the subjects array. - const subject = new CredClaimSubject({ - pubKey: pubKey, - claimsRange: IxRange.fromNumbers(firstSubjectClaimIndex, claimIndex - 1) - }); + // // Add the subject to the subjects array. + // const subject = new CredClaimSubject({ + // pubKey: pubKey, + // claimsRange: IxRange.fromNumbers(firstSubjectClaimIndex, claimIndex - 1) + // }); - subjectsArray = subjectsArray.concat(subject.toFields()); - }); + // subjectsArray = subjectsArray.concat(subject.toFields()); + // }); - // Return the new Claims instance. - return new Claims({ - indices: CircuitString.fromFields(indicesArray), - claims: claimsCircuitString, - subjects: subjectsCircuitString - }); - } + // // Return the new Claims instance. + // return new Claims({ + // indices: CircuitString.fromFields(indicesArray), + // claims: claimsCircuitString, + // subjects: subjectsCircuitString + // }); + // } } /** @@ -190,6 +188,23 @@ export class CredentialSchemaHash extends Struct({ } } +/** + * Represents a unique identifier for a credential schema. + */ +export class CredTypeId extends Struct({ + credTypeId: Field +}) { + public toFields() { + return [this.credTypeId]; + } + + static fromCredInfo({credentialSchema, issuerPubkey } : {credentialSchema: Field[], issuerPubkey: PublicKey} ): CredTypeId { + return new CredTypeId({ + credTypeId: Poseidon.hash([...credentialSchema, ...issuerPubkey.toFields()]) + }); + } +} + /** * Represents a Verifiable Credential (VCred) with its associated data. */ @@ -198,8 +213,9 @@ export class VCredStruct extends Struct({ issuer: Issuer, issuanceDate: Field, // UTC timestamp expirationDate: Field, // UTC timestamp + subject: PublicKey, claims: Claims, - credentialSchema: CredentialSchemaHash, + credentialSchema: Field, signature: Signature }) { // without the signature - for the signature verification @@ -209,6 +225,7 @@ export class VCredStruct extends Struct({ ...this.issuer.toFields(), this.issuanceDate, this.expirationDate, + ...this.subject.toFields(), ...this.claims.toFields(), ...this.credentialSchema.toFields() ]; @@ -236,8 +253,8 @@ export class VCredValidationContext extends Struct({ * you have to know the salt used to create the claims hash. */ export class VCredValidationOutput extends Struct({ - // Hash combining hasshes of the issuer's public key and the credential schema. - identificationHash: Field, + // Hash combining the issuer's public key and the credential schema. + schemaIdentificationHash: Field, // Salted hash of the credential's claims. No attacks possible against simple claims "{age: 18}". saltedClaimsHash: Field }) {} @@ -310,13 +327,13 @@ export const ValidateVCredProgram = ZkProgram({ ); // Calculate hashes for credential identification and claims verification. - const identificationHash = Poseidon.hash([ - Poseidon.hash(cred.issuer.toFields()), - Poseidon.hash(cred.credentialSchema.toFields()) + const schemaIdentificationHash = Poseidon.hash([ + ...cred.issuer.toFields(), + ...cred.credentialSchema.toFields() ]); return new VCredValidationOutput({ - identificationHash, + schemaIdentificationHash, saltedClaimsHash: Poseidon.hash([ ...cred.claims.toFields(), claimsSalt diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts index acc779a..b48e001 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/zkclaim-proof-rollup.ts @@ -55,7 +55,7 @@ export const ValidateZkClaimProgram = ZkProgram({ // verify contexts publicInput.vCredIdentificationHash.assertEquals( - credProof.publicOutput.identificationHash + credProof.publicOutput.schemaIdentificationHash ); publicInput.validFrom.assertGreaterThanOrEqual( credProof.publicInput.validFrom From 61aab67b076de7762e0463d6277277f840fb288f Mon Sep 17 00:00:00 2001 From: adamczykm Date: Tue, 12 Mar 2024 14:36:15 +0100 Subject: [PATCH 13/34] Add claims and creds types function and tests for circuit level types. --- .../babel.config.cjs | 3 + .../jest-resolver.cjs | 21 + .../jest.config.js | 26 + .../package-lock.json | 7557 +++++++++++++---- .../package.json | 5 + .../src/bigint-serializer.cjs | 9 + .../src/data/claims.test.ts | 57 + .../src/data/claims.ts | 153 +- .../src/data/ids.ts | 27 +- .../src/data/simple.ts | 30 +- .../src/data/vcred.test.ts | 120 + .../src/data/vcred.ts | 29 +- .../src/helpers/debug.ts | 6 + .../src/helpers/utils.ts | 17 + .../src/index.ts | 1 + 15 files changed, 6572 insertions(+), 1489 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/babel.config.cjs create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/jest-resolver.cjs create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/jest.config.js create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/bigint-serializer.cjs create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.test.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/debug.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/babel.config.cjs b/minauth-plugins/minauth-verified-zkdocument-plugin/babel.config.cjs new file mode 100644 index 0000000..c74fb53 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/babel.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + presets: [['@babel/preset-env', { targets: { node: 'current' } }]], +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/jest-resolver.cjs b/minauth-plugins/minauth-verified-zkdocument-plugin/jest-resolver.cjs new file mode 100644 index 0000000..11c8fc2 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/jest-resolver.cjs @@ -0,0 +1,21 @@ +module.exports = (request, options) => { + return options.defaultResolver(request, { + ...options, + packageFilter: (pkg) => { + // When importing o1js, we specify the Node ESM import as Jest by default imports the web version + if (pkg.name === 'o1js') { + return { + ...pkg, + main: pkg.exports.node.import, + }; + } + if (pkg.name === 'node-fetch') { + return { ...pkg, main: pkg.main }; + } + return { + ...pkg, + main: pkg.module || pkg.main, + }; + }, + }); +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/jest.config.js b/minauth-plugins/minauth-verified-zkdocument-plugin/jest.config.js new file mode 100644 index 0000000..e414586 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/jest.config.js @@ -0,0 +1,26 @@ +/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */ +export default { + maxWorkers: 1, + snapshotSerializers: ['./src/bigint-serializer.cjs'], + verbose: true, + preset: 'ts-jest/presets/default-esm', + testEnvironment: 'node', + globals: { + 'ts-jest': { + useESM: true, + }, + }, + testTimeout: 1_000_000, + transform: { + '^.+\\.(t)s$': 'ts-jest', + '^.+\\.(j)s$': 'babel-jest', + }, + resolver: '/jest-resolver.cjs', + transformIgnorePatterns: [ + '/node_modules/(?!(tslib|o1js/node_modules/tslib))', + ], + modulePathIgnorePatterns: ['/build/'], + moduleNameMapper: { + '^(\\.{1,2}/.+)\\.js$': '$1', + }, +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json index f6135f1..5a13198 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package-lock.json @@ -19,16 +19,21 @@ "zod": "^3.22.2" }, "devDependencies": { + "@babel/core": "^7.24.0", + "@babel/preset-env": "^7.24.0", "@types/axios": "^0.14.*", "@types/express": "^4.17.17", + "@types/jest": "^29.5.12", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.8.0", "eslint": "^8.51.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-deprecation": "^2.0.0", "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.7.0", "nodemon": "^3.0.1", "prettier": "^3.0.3", + "ts-jest": "^29.1.2", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", "typescript": "^5.2.2" @@ -46,2072 +51,5926 @@ "node": ">=0.10.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">=12" + "node": ">=6.0.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "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" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=4" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "color-name": "1.1.3" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=0.8.0" } }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=4" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@babel/core": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" + "node": ">=6.9.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "dependencies": { + "yallist": "^3.0.2" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.0.tgz", + "integrity": "sha512-QAH+vfvts51BCsNZ2PhY6HAggnlS6omLLFTsIpeqZk/MmJ6cW7tgz5yRv0fMJThcr6FmbMrENh1RgrWPTYA76g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/@types/axios": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", - "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==", - "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dev": true, "dependencies": { - "axios": "*" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "devOptional": true, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.0.tgz", + "integrity": "sha512-efwOM90nCG6YeT8o3PCyBVSxRfmILxCNL+TNI8CGQl7a62M0Wd9VkV+XHwIlkOz1r4b+lxu6gBjdWiOMdUCrCQ==", + "dev": true, "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "devOptional": true, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, "dependencies": { - "@types/node": "*" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "devOptional": true, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", - "devOptional": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "devOptional": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, "dependencies": { - "@types/node": "*" + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/http-proxy-middleware": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz", - "integrity": "sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw==", - "deprecated": "This is a stub types definition. http-proxy-middleware provides its own type definitions, so you do not need this installed.", + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, "dependencies": { - "http-proxy-middleware": "*" + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/luxon": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", - "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "devOptional": true - }, - "node_modules/@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@types/qs": { - "version": "6.9.12", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", - "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==", - "devOptional": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "devOptional": true - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "devOptional": true, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "devOptional": true, - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@babel/core": "^7.0.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@babel/core": "^7.0.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@babel/types": "^7.22.5" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "@babel/types": "^7.22.5" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=6.9.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "node_modules/@babel/helpers": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", + "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "node": ">=6.9.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.9.0" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "color-convert": "^1.9.0" }, "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=4" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "dependencies": { + "color-name": "1.1.3" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=0.8.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "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" + "has-flag": "^3.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=4" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@babel/parser": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", + "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", "dev": true, "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", - "peer": true - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "dependencies": { - "ms": "2.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cachedir": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", - "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", - "peer": true, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "engines": { - "node": ">=6" + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@babel/helper-plugin-utils": "^7.8.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", "dev": true, "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" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=6.9.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">= 6" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cmd-ts": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/cmd-ts/-/cmd-ts-0.13.0.tgz", - "integrity": "sha512-nsnxf6wNIM/JAS7T/x/1JmbEsjH0a8tezXqqpaL0O6+eV0/aDEnRxwjxpu0VzDdRcaC1ixGSbRlUuf/IU59I4g==", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, "dependencies": { - "chalk": "^4.0.0", - "debug": "^4.3.4", - "didyoumean": "^1.2.2", - "strip-ansi": "^6.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">=7.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, "dependencies": { - "delayed-stream": "~1.0.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">= 0.8" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, "dependencies": { - "safe-buffer": "5.2.1" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, "dependencies": { - "ms": "2.1.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=6.0" + "node": ">=6.9.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">=0.4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/detect-gpu": { - "version": "5.0.38", - "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.38.tgz", - "integrity": "sha512-36QeGHSXYcJ/RfrnPEScR8GDprbXFG4ZhXsfVNVHztZr38+fRxgHnJl3CjYXXjbeRUhu3ZZBJh6Lg0A9v0Qd8A==", - "peer": true, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dev": true, "dependencies": { - "webgl-constants": "^1.1.1" + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "engines": { - "node": ">=0.3.1" + "node": ">=4" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", "dev": true, "dependencies": { - "path-type": "^4.0.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", "dev": true, "dependencies": { - "esutils": "^2.0.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, "dependencies": { - "safe-buffer": "^5.0.1" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/env-var": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/env-var/-/env-var-7.4.1.tgz", - "integrity": "sha512-H8Ga2SbXTQwt6MKEawWSvmxoH1+J6bnAXkuyE7eDvbGmrhIL2i+XGjzGM3DFHcJu8GY1zY9/AnBJY8uGQYPHiw==", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, "dependencies": { - "get-intrinsic": "^1.2.4" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@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" + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": ">=7.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-deprecation": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-2.0.0.tgz", - "integrity": "sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "^6.0.0", - "tslib": "^2.3.1", - "tsutils": "^3.21.0" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "typescript": "^4.2.4 || ^5.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" + "node": ">=6.9.0" }, "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { - "node": "*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", "dev": true, "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dev": true, "dependencies": { - "estraverse": "^5.1.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=0.10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", "dev": true, "dependencies": { - "estraverse": "^5.2.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, "engines": { - "node": ">=4.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.0.tgz", + "integrity": "sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dev": true, "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { - "node": ">= 0.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, "dependencies": { - "ms": "2.0.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=8.6.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" }, "engines": { - "node": ">= 6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", "dev": true, "dependencies": { - "reusify": "^1.0.4" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, "dependencies": { - "to-regex-range": "^5.0.1" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, "dependencies": { - "ms": "2.0.0" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", "dev": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", + "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.24.0", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", + "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==", + "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "dev": true, + "dependencies": { + "axios": "*" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "devOptional": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "devOptional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "devOptional": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "devOptional": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "devOptional": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-proxy-middleware": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz", + "integrity": "sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw==", + "deprecated": "This is a stub types definition. http-proxy-middleware provides its own type definitions, so you do not need this installed.", + "dependencies": { + "http-proxy-middleware": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "devOptional": true + }, + "node_modules/@types/node": { + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.12", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", + "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==", + "devOptional": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "devOptional": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "devOptional": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "devOptional": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.9.tgz", + "integrity": "sha512-BXIWIaO3MewbXWdJdIGDWZurv5OGJlFNo7oy20DpB3kWDVJLcY2NRypRsRUbRe5KMqSNLuOGnWTFQQtY5MAsRw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.0", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "peer": true + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cmd-ts": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/cmd-ts/-/cmd-ts-0.13.0.tgz", + "integrity": "sha512-nsnxf6wNIM/JAS7T/x/1JmbEsjH0a8tezXqqpaL0O6+eV0/aDEnRxwjxpu0VzDdRcaC1ixGSbRlUuf/IU59I4g==", + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "didyoumean": "^1.2.2", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-js-compat": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-gpu": { + "version": "5.0.38", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.38.tgz", + "integrity": "sha512-36QeGHSXYcJ/RfrnPEScR8GDprbXFG4ZhXsfVNVHztZr38+fRxgHnJl3CjYXXjbeRUhu3ZZBJh6Lg0A9v0Qd8A==", + "peer": true, + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.700", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.700.tgz", + "integrity": "sha512-40dqKQ3F7C8fbBEmjSeJ+qEHCKzPyrP9SkeIBZ3wSCUH9nhWStrDz030XlDzlhNhlul1Z0fz7TpDFnsIzo4Jtg==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/env-var": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/env-var/-/env-var-7.4.1.tgz", + "integrity": "sha512-H8Ga2SbXTQwt6MKEawWSvmxoH1+J6bnAXkuyE7eDvbGmrhIL2i+XGjzGM3DFHcJu8GY1zY9/AnBJY8uGQYPHiw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-deprecation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-2.0.0.tgz", + "integrity": "sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^6.0.0", + "tslib": "^2.3.1", + "tsutils": "^3.21.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "typescript": "^4.2.4 || ^5.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.2.tgz", + "integrity": "sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng==" + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "hasown": "^2.0.0" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=0.10.0" } }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "node": ">=6" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "engines": { - "node": ">= 0.6" + "node": ">=0.12.0" } }, - "node_modules/fp-ts": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.2.tgz", - "integrity": "sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng==" + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "engines": { - "node": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "peer": true, + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=8" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/istanbul-lib-instrument": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" } }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { - "is-glob": "^4.0.3" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=8" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" }, "engines": { - "node": "*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, "dependencies": { - "type-fest": "^0.20.2" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, "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" + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3" + "detect-newline": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, "dependencies": { - "es-define-property": "^1.0.0" + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, "engines": { - "node": ">= 0.4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, "dependencies": { - "function-bind": "^1.1.2" + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 0.4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 0.8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=8.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=12.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" }, "peerDependencies": { - "@types/express": "^4.17.13" + "jest-resolve": "*" }, "peerDependenciesMeta": { - "@types/express": { + "jest-resolve": { "optional": true } } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, "engines": { - "node": ">= 4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, "engines": { - "node": ">=0.8.19" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, "dependencies": { - "binary-extensions": "^2.0.0" + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, "dependencies": { - "is-extglob": "^2.1.1" + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "engines": { - "node": ">=0.12.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "engines": { - "node": ">=10" + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isomorphic-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", - "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", - "peer": true, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "dependencies": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/js-sha256": { @@ -2120,6 +5979,12 @@ "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==", "peer": true }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2132,12 +5997,30 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2211,6 +6094,24 @@ "json-buffer": "3.0.1" } }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2224,6 +6125,12 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2239,6 +6146,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -2269,6 +6182,12 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2299,12 +6218,36 @@ "node": ">=12" } }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2318,6 +6261,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2377,6 +6326,15 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/minauth": { "version": "0.10.1-alpha", "resolved": "https://registry.npmjs.org/minauth/-/minauth-0.10.1-alpha.tgz", @@ -2467,6 +6425,18 @@ } } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, "node_modules/nodemon": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", @@ -2562,6 +6532,18 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/o1js": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/o1js/-/o1js-0.16.2.tgz", @@ -2619,6 +6601,21 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -2666,6 +6663,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2678,6 +6684,24 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2756,6 +6780,12 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -2775,6 +6805,12 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -2786,6 +6822,79 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2822,6 +6931,32 @@ "node": ">=6.0.0" } }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -2830,6 +6965,19 @@ "node": ">= 0.6.0" } }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2862,6 +7010,22 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -2914,32 +7078,156 @@ "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, - "engines": { - "node": ">= 0.8" + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", + "peer": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "dependencies": { - "picomatch": "^2.2.1" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=8.10.0" + "node": ">=8" } }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", - "peer": true - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/resolve-from": { "version": "4.0.0", @@ -2950,6 +7238,15 @@ "node": ">=4" } }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3150,6 +7447,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -3162,6 +7465,12 @@ "node": ">=10" } }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -3171,6 +7480,52 @@ "node": ">=8" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -3179,6 +7534,33 @@ "node": ">= 0.8" } }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3199,6 +7581,15 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3222,6 +7613,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/synckit": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", @@ -3238,12 +7641,63 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3293,6 +7747,49 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-jest": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", + "integrity": "sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -3399,6 +7896,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3447,6 +7953,46 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -3455,6 +8001,36 @@ "node": ">= 0.8" } }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3491,6 +8067,30 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3499,6 +8099,15 @@ "node": ">= 0.8" } }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, "node_modules/webgl-constants": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", @@ -3542,12 +8151,51 @@ "node": ">= 8" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -3564,6 +8212,33 @@ "node": ">= 14" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/package.json b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json index c2a1449..ac15275 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/package.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/package.json @@ -26,16 +26,21 @@ "zod": "^3.22.2" }, "devDependencies": { + "@babel/core": "^7.24.0", + "@babel/preset-env": "^7.24.0", "@types/axios": "^0.14.*", "@types/express": "^4.17.17", + "@types/jest": "^29.5.12", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.8.0", "eslint": "^8.51.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-deprecation": "^2.0.0", "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.7.0", "nodemon": "^3.0.1", "prettier": "^3.0.3", + "ts-jest": "^29.1.2", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", "typescript": "^5.2.2" diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/bigint-serializer.cjs b/minauth-plugins/minauth-verified-zkdocument-plugin/src/bigint-serializer.cjs new file mode 100644 index 0000000..f2a48b0 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/bigint-serializer.cjs @@ -0,0 +1,9 @@ +module.exports = { + test(value) { + return typeof value === 'bigint'; + }, + print(value) { + return `BigInt(${value.toString()})`; + }, +}; + diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.test.ts new file mode 100644 index 0000000..4922b54 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.test.ts @@ -0,0 +1,57 @@ +import { Field } from "o1js"; +import { ClaimStruct, mkClaims } from "./claims.js"; + +describe('ClaimStruct', () => { + it('should create a claim with the correct length and values', () => { + const claimLength = 3; + const claimValues = [new Field(1), new Field(2), new Field(3)]; + const Claim = ClaimStruct(claimLength); + const claimInstance = new Claim(claimValues); + + expect(claimInstance.length.toBigInt()).toBe(BigInt(claimLength)); + expect(claimInstance.claimValue).toEqual(claimValues); + expect(claimInstance.toFields()).toEqual([new Field(claimLength), ...claimValues]); + }); + + it('should throw an error for mismatched length and values', () => { + const claimLength = 2; + const claimValues = [new Field(1), new Field(2), new Field(3)]; // Intentional mismatch in lengths + const Claim = ClaimStruct(claimLength); + expect(() => new Claim(claimValues)).toThrow() + }); +}); + +describe('Claims', () => { + it('should create Claims with correct structure', () => { + + const claim1 = new (ClaimStruct(1))([new Field(1)]); + const claim2 = new (ClaimStruct(2))([new Field(21), new Field(22)]); + const claims = [claim1, claim2]; + const claimsInstance = mkClaims(claims); + + expect(claimsInstance.count.toBigInt()).toBe(BigInt(2)); + + const asNumbers = claimsInstance.toFields().map(f => Number(f.toBigInt())); + + const expected = [2, 0, 1, 3, 1, 21, 22]; + + expect(asNumbers).toEqual(expected); + }); + + it('should retrieve correct claim data', () => { + const claim1 = new (ClaimStruct(1))([new Field(1)]); + const claim2 = new (ClaimStruct(2))([new Field(21), new Field(22)]); + const claims = [claim1, claim2]; + const claimsInstance = mkClaims(claims); + + const claim1Retrieved = claimsInstance.getClaim(new Field(0), [new Field(1)]); + const claim2Retrieved = claimsInstance.getClaim(new Field(1), [new Field(21), new Field(22)]); + + expect(claim1Retrieved).toHaveLength(1); + expect(claim1Retrieved[0].toBigInt()).toBe(BigInt(1)); + expect(claim2Retrieved).toHaveLength(2); + expect(claim2Retrieved[0].toBigInt()).toBe(BigInt(21)); + expect(claim2Retrieved[1].toBigInt()).toBe(BigInt(22)); + }); +} + ); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts index 78a9efb..7c06951 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts @@ -1,31 +1,154 @@ -import {Struct, Provable, Field} from "o1js" -import {z} from "zod" -import {FieldsSchema} from "./simple.js" +import { Struct, Provable, Field } from 'o1js'; +import { ZodTypeAny, z } from 'zod'; +import { FieldsSchema } from './simple.js'; +import { arraysAreEqual, ftn } from '../helpers/utils.js'; const CLAIMS_MAX_SIZE = 128; -export function Claims(n: number) { - if (n > CLAIMS_MAX_SIZE) { - throw new Error(`Claims size ${n} exceeds the maximum size ${CLAIMS_MAX_SIZE}`); +export interface IClaim { + length: Field; + claimValue: Field[]; + toFields(): Field[]; +} + +export interface IClaimClass { + new (claimValue: Field[]): IClaim; + fromFields(fields: Field[]): IClaim; + schema: z.ZodType; +} + +export interface IClaims { + count: Field; + packed: Field[]; + toFields(): Field[]; + getClaim(ix: Field, assert: Field[]): Field[]; +} + +export const ClaimStruct = (length: number): IClaimClass => { + class Claim_ + extends Struct({ + length: Field, + claimValue: Provable.Array(Field, length) + }) + implements IClaim + { + constructor(claimValue: Field[]) { + if (claimValue.length !== length) { + throw new Error(`Invalid claim array size: ${claimValue.length}`); + } + super({ length: new Field(length), claimValue }); + } + + public toFields() { + return [this.length, ...this.claimValue]; + } + + static fromFields(fields: Field[]) { + const length = Number(fields[0].toBigInt()); + if (fields.length !== length + 1) { + throw new Error(`Invalid claim array size: ${fields.length}`); + } + return new Claim_(fields.slice(1, length + 1)); + } + + static schema = z + .object({ + claimValue: FieldsSchema.length(length) + }) + .transform((o) => new Claim_(o.claimValue)); } - class Claims_ extends Struct({ - packed: Provable.Array(Field, n), - }) { + return Claim_ as IClaimClass; +}; + +export const mkClaimStruct = (flds: Field[]) => { + const n = flds.length; + return ClaimStruct(n).fromFields(flds); +}; + +export const computeClaimSizes = (claims: IClaim[]) => { + return claims.map(c => ftn(c.length)); +}; + +export const mkClaims = (claims: IClaim[]): IClaims => { + const size = computeClaimSizes(claims); + return Claims(size).fromClaims(claims); +}; + +export function Claims(claimSizes: number[]) { + if (claimSizes.length == 0) { + throw new Error('claimSizes must not be empty.'); + } + const claimCount = claimSizes.length; + // 0 (start index) + indices + claims + const totalSize = 1 + claimCount + claimSizes.reduce((a, v) => a + v, 0); + + if (totalSize > CLAIMS_MAX_SIZE) { + throw new Error( + `Total Claims size ${totalSize} exceeds the maximum size ${CLAIMS_MAX_SIZE}` + ); + } + + class Claims_ + extends Struct({ + count: Field, + packed: Provable.Array(Field, totalSize) + }) + implements IClaims + { static MAX_SIZE = CLAIMS_MAX_SIZE; public toFields() { - return this.packed; + return [this.count, ...this.packed]; + } + + static fromClaims(claims: IClaim[]) { + const receivedSizes = claims.map((c) => ftn(c.length)); + + if (!arraysAreEqual(receivedSizes, claimSizes)) { + throw new Error("'claims' array sizes are invalid"); + } + + let packed: Field[] = []; + // first push all locations + packed.push(new Field(0)); + for (let i = 0; i < claims.length; i++) { + const claimEndIx = packed[i].add(claims[i].length); + packed.push(claimEndIx); + } + // then push all values + for (const claim of claims) { + packed.push(...claim.claimValue); + } + + return new Claims_({ count: new Field(claims.length), packed }); } static get schema() { - return z.object({ - packed: FieldsSchema.length(n) - }).transform((o) => new Claims_({ packed: o.packed })); + const claimSchemas = claimSizes.map( + (size) => ClaimStruct(size).schema + ) as [ZodTypeAny, ...ZodTypeAny[]]; + return z + .tuple(claimSchemas) + .transform((claims) => Claims_.fromClaims(claims)); } - public claim(r :{firstFieldIx: number, lastFieldIx: number }): Field[] { - return this.packed.slice(r.firstFieldIx, r.lastFieldIx+1); + public getClaim(ix: Field, assert: Field[]): Field[] { + const i = Number(ix.toBigInt()); + const length = Number(this.packed[i + 1].sub(this.packed[i]).toBigInt()); + const c = Number(this.count.toBigInt()); + + const op = Provable.witness(Provable.Array(Field, length), () => { + const start = Number(this.packed[i].toBigInt()); + const next = Number(this.packed[i + 1].toBigInt()); + return this.packed.slice(c + 1 + start, c + 1 + next); + }); + + for (let j = 0; j < length; j++) { + op[j].assertEquals(assert[j]); + } + + return op; } } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts index 463e0ed..9ffa12b 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts @@ -7,24 +7,37 @@ import { Logger } from 'tslog'; import { z } from 'zod'; import * as SimpleSchemas from './simple.js'; -/** - * Represents an issuer with a public key. Future versions might replace this - * with a more complex ID system, such as DIDs. - */ -export class IssuerId extends Struct({ +export class PubKeyId extends Struct({ pubkey: PublicKey }) { public toFields() { return this.pubkey.toFields(); } } - -export const IssuerIdSchema = z +export const PubKeyIdSchema = z .object({ pubkey: SimpleSchemas.PublicKeyB58Schema }) .transform((o) => new IssuerId({ pubkey: o.pubkey })); +/** + * Represents an issuer with a public key. Future versions might replace this + * with a more complex ID system, such as DIDs. + */ +export class IssuerId extends PubKeyId {} + +export const IssuerIdSchema = PubKeyIdSchema; + + +/** + * Represents a subject with a public key. Future versions might replace this + * with a more complex ID system, such as DIDs. + */ +export class CredSubjectId extends PubKeyId {} + +export const CredSubjectIdSchema = PubKeyIdSchema; + + export class VCredId extends Struct({ id: Field }) { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts index 3507256..82f117f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts @@ -2,21 +2,25 @@ import { Field, PublicKey, Struct, Signature } from 'o1js'; import { Logger } from 'tslog'; import { z } from 'zod'; +export const FieldSchemaInt = z.number().int().transform((n) => new Field(BigInt(n))); +export const FieldSchemaBigInt = z.bigint().transform(Field); export const FieldSchemaDec = z.string().regex(/^\d+$/).transform(Field); export const FieldSchemaHex = z .string() .regex(/^(0x|0X)?[0-9a-fA-F]+$/) .transform((s) => Field(BigInt(s))); -export const FieldsSchema = z.array(z.union([FieldSchemaDec, FieldSchemaHex])); + +export const FieldSchema = z.union([FieldSchemaInt, FieldSchemaBigInt, FieldSchemaDec,FieldSchemaHex]); +export const FieldsSchema = z.array(FieldSchema); export const Base58Schema = z.string().regex(/^[A-HJ-NP-Za-km-z1-9]+$/); export const PublicKeyB58Schema = Base58Schema.length(55).transform( PublicKey.fromBase58 ); export const SignatureSchema = z .object({ - signature: Base58Schema.length(96) + signatureBase58: Base58Schema.length(96) }) - .transform((o) => Signature.fromBase58(o.signature)); + .transform((o) => Signature.fromBase58(o.signatureBase58)); export class UnixTimestamp extends Struct({ unixTimestamp: Field @@ -36,6 +40,16 @@ export const UnixTimestampSchema = z export const inline_tests = () => { const log = new Logger({ name: 'simple schema inline tests' }); + const fieldi = 123; + const f1: Field = FieldSchemaInt.parse(fieldi); + log.info('Parsed field from int encoding: ', fieldi, f1); + + + const fieldbigi = 123n; + const f2: Field = FieldSchemaBigInt.parse(fieldbigi); + log.info('Parsed field from big int encoding: ', fieldbigi, f2); + + // const PublicKeySchema = z.string().transform(PrivateKey.from); const fielddecstr = '123'; const field: Field = FieldSchemaDec.parse(fielddecstr); @@ -44,7 +58,7 @@ export const inline_tests = () => { FieldSchemaDec.parse('abc'); } catch (e) { const err = e as z.ZodError; - log.debug('Caught error: ', err.message); + log.debug('Valid error: ', err.message); } const fieldhexstr = '0x123'; @@ -58,7 +72,7 @@ export const inline_tests = () => { FieldSchemaHex.parse('0xzbc'); } catch (e) { const err = e as z.ZodError; - log.debug('Caught error: ', err.message); + log.debug('Valid error: ', err.message); } const fieldsencoded = ['123', '0x123']; @@ -76,7 +90,7 @@ export const inline_tests = () => { PublicKeyB58Schema.parse('abc'); } catch (e) { const err = e as z.ZodError; - log.debug('Caught error: ', err.message); + log.debug('Valid error: ', err.message); } // tests for unix timestamp @@ -93,7 +107,7 @@ export const inline_tests = () => { UnixTimestampSchema.parse({ unixTimestamp: 'abc' }); } catch (e) { const err = e as z.ZodError; - log.debug('Caught error: ', err.message); + log.debug('Valid error: ', err.message); } const signature = SignatureSchema.parse({ @@ -109,6 +123,6 @@ export const inline_tests = () => { }); } catch (e) { const err = e as z.ZodError; - log.debug('Caught error: ', err.message); + log.debug('Valid error: ', err.message); } }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts new file mode 100644 index 0000000..5fba61d --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts @@ -0,0 +1,120 @@ +import { Field, PrivateKey, Signature } from 'o1js'; +import { VCredStruct, VCredStructUnsigned } from './vcred.js'; // Update import path as needed +import { ClaimStruct, IClaim, mkClaims } from './claims.js'; // Import necessary dependencies +import { CredSubjectId, IssuerId, VCredId } from './ids.js'; +import { UnixTimestamp } from './simple.js'; + +describe('VCredStruct tests', () => { + const pk1 = PrivateKey.random().toPublicKey(); + const pk1s: string = pk1.toBase58(); + const pk2 = PrivateKey.random().toPublicKey(); + const pk2s = pk2.toBase58(); + + let claim1: IClaim; + let claim2: IClaim; + + const claim1s = { + claimValue: [1, 2, 3] + }; + const claim2s = { + claimValue: ['0x456', 0x789] + }; + + beforeAll(() => { + claim1 = ClaimStruct(3).schema.parse(claim1s); + claim2 = ClaimStruct(2).schema.parse(claim2s); + }); + + const ClaimSizes = [3, 2]; + const VCredStructUnsignedType = VCredStructUnsigned(ClaimSizes); + const VCredStructType = VCredStruct(ClaimSizes); + + const testData = () => { + return { + id: new VCredId({ id: new Field(123) }), + issuer: new IssuerId({ pubkey: pk1 }), + issuanceDate: new UnixTimestamp({ unixTimestamp: new Field(123123123) }), + expirationDate: new UnixTimestamp({ + unixTimestamp: new Field(223123123) + }), + subject: new CredSubjectId({ pubkey: pk2 }), + claims: mkClaims([claim1, claim2]), + credentialSchemaHash: new Field(789) + }; + }; + + describe('VCredStructUnsigned', () => { + it('should instantiate correctly with valid data', () => { + const instance = new VCredStructUnsignedType(testData()); + expect(instance).toBeInstanceOf(VCredStructUnsignedType); + expect(instance.toFields()).toEqual( + expect.arrayContaining([expect.any(Field)]) + ); + }); + + it('should parse from valid data with its zod schema', () => { + expect(VCredStructUnsignedType.dataSchema).toBeDefined(); + const validation = VCredStructUnsignedType.dataSchema.safeParse({ + id: { id: '123' }, + issuer: { pubkey: pk1s }, + issuanceDate: { unixTimestamp: '123123123' }, + expirationDate: { unixTimestamp: '223123123' }, + subject: { pubkey: pk2s }, + claims: [claim1s, claim2s], + credentialSchemaHash: '789' + }); + + if (!validation.success) { + console.log(validation.error); + } + + expect(validation.success).toBeTruthy(); + }); + }); + + describe('VCredStruct', () => { + const testDataSig = () => { + return { + id: new VCredId({ id: new Field(123) }), + issuer: new IssuerId({ pubkey: pk1 }), + issuanceDate: new UnixTimestamp({ + unixTimestamp: new Field(123123123) + }), + expirationDate: new UnixTimestamp({ + unixTimestamp: new Field(223123123) + }), + subject: new CredSubjectId({ pubkey: pk2 }), + claims: mkClaims([claim1, claim2]), + credentialSchemaHash: new Field(789), + signature: Signature.fromBase58('7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE') + }; + }; + + it('should instantiate correctly with valid data, including signature', () => { + const instance = new VCredStructType(testDataSig()); + expect(instance).toBeInstanceOf(VCredStructType); + expect(instance.toFields()).toEqual( + expect.arrayContaining([expect.any(Field)]) + ); + }); + + it('should have a valid schema including signature', () => { + expect(VCredStructType.dataSchema).toBeDefined(); + const validation = VCredStructType.schema.safeParse({ + id: { id: '123' }, + issuer: { pubkey: pk1s }, + issuanceDate: { unixTimestamp: '123123123' }, + expirationDate: { unixTimestamp: '223123123' }, + subject: { pubkey: pk2s }, + claims: [claim1s, claim2s], + credentialSchemaHash: '789', + signature: {signatureBase58: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE'} + }); + if(!validation.success){ + console.log(validation.error); + } + + expect(validation.success).toBeTruthy(); + }); + }); +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts index 641e53e..a3de797 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts @@ -1,30 +1,23 @@ -import { Struct, Field, PublicKey, Signature } from 'o1js'; +import { Struct, Field, Signature } from 'o1js'; import { UnixTimestamp, UnixTimestampSchema, - PublicKeyB58Schema, - FieldSchemaDec, - FieldSchemaHex, - SignatureSchema + SignatureSchema, + FieldSchema } from './simple.js'; -import { IssuerId, VCredId, VCredIdSchema, IssuerIdSchema } from './ids.js'; +import { IssuerId, VCredId, VCredIdSchema, IssuerIdSchema, CredSubjectId, CredSubjectIdSchema } from './ids.js'; import { Claims } from './claims.js'; import { z } from 'zod'; -export function VCredStructUnsigned(n: number) { - const ClaimsType = Claims(n); - - if (n <= 0 || n > ClaimsType.MAX_SIZE) { - // Adjust the limits as necessary. - throw new Error(`Invalid claims array size: ${n}`); - } +export function VCredStructUnsigned(claimSizes: number[]) { + const ClaimsType = Claims(claimSizes); const Fields = { id: VCredId, issuer: IssuerId, issuanceDate: UnixTimestamp, expirationDate: UnixTimestamp, - subject: PublicKey, + subject: CredSubjectId, claims: ClaimsType, credentialSchemaHash: Field }; @@ -50,9 +43,9 @@ export function VCredStructUnsigned(n: number) { issuer: IssuerIdSchema, issuanceDate: UnixTimestampSchema, expirationDate: UnixTimestampSchema, - subject: PublicKeyB58Schema, + subject: CredSubjectIdSchema, claims: ClaimsType.schema, - credentialSchemaHash: FieldSchemaDec.or(FieldSchemaHex) + credentialSchemaHash: FieldSchema }); } @@ -66,8 +59,8 @@ export function VCredStructUnsigned(n: number) { return BaseVCredStruct_; } -export function VCredStruct(n: number) { - const BaseVCredStructType = VCredStructUnsigned(n); +export function VCredStruct(claimSizes: number[]) { + const BaseVCredStructType = VCredStructUnsigned(claimSizes); const Fields = { ...BaseVCredStructType.Fields, signature: Signature }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/debug.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/debug.ts new file mode 100644 index 0000000..0f08f74 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/debug.ts @@ -0,0 +1,6 @@ +import { Logger, ILogObj } from 'tslog' + +export const dbgLog = new Logger({name: "debug"}) + +export const dbg = dbgLog.debug + diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts new file mode 100644 index 0000000..e8e070d --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts @@ -0,0 +1,17 @@ +import { Field } from 'o1js'; + +export const ftn = (fld: Field) => Number(fld.toBigInt()); + +export function arraysAreEqual(array1: T[], array2: T[]): boolean { + if (array1.length !== array2.length) { + return false; + } + + for (let i = 0; i < array1.length; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + + return true; + } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 50d876d..7b9bcb5 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -32,6 +32,7 @@ log.info('========= Schemas ========='); log.info('Creating a new credential schema'); + log.info('Registering the new credential schema'); log.info('Issuing a credential'); From b25b832c3282f2ae42ae38af93f7889aa7906def Mon Sep 17 00:00:00 2001 From: adamczykm Date: Thu, 14 Mar 2024 18:29:32 +0100 Subject: [PATCH 14/34] Add high-level types and transit schemas for claims and credentials. Add tests. --- .../src/claim.ts | 56 +++ .../src/credential.test.ts | 376 ++++++++++++++++++ .../src/credential.ts | 106 +++++ .../src/data/claims.ts | 28 +- .../src/data/simple.ts | 3 +- .../src/data/vcred.test.ts | 6 +- .../src/data/vcred.ts | 6 +- .../src/index.ts | 57 ++- 8 files changed, 596 insertions(+), 42 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts new file mode 100644 index 0000000..a648824 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts @@ -0,0 +1,56 @@ +import { CircuitString, Field, Poseidon } from 'o1js'; +import { z } from 'zod'; +import { ClaimStruct, IClaimStruct } from './data/claims.js'; +import { FieldsSchema } from './data/simple'; + +export const ClaimStandardSchema = z.object({ + standardId: z.string().min(2), + description: z.string(), + referenceToExternalStandard: z.string().optional(), + fieldsConversion: z.object({ + length: z.number().int().min(1), + description: z.string(), + codeExample: z.string() + }) +}); + +export type ClaimStandard = z.infer; + +export function ClaimSchema(valueSchema: z.ZodType) { + return z.object({ + name: z.string().min(1), + value: valueSchema, + fieldsValue: FieldsSchema, + standard: ClaimStandardSchema + }); +} + +export interface IClaim { + get name(): string; + get value(): V; + get fieldsValue(): Field[]; + get standard(): ClaimStandard; +} + +export const claimToStruct = (claim: IClaim): IClaimStruct => { + const l = claim.fieldsValue.length; + return ClaimStruct(l).fromFields(claim.fieldsValue); +}; + +export const claimStandardHash = (standard: ClaimStandard): Field => { + const idHash = Poseidon.hash( + CircuitString.fromString(standard.standardId).toFields() + ); + const optsHash = Poseidon.hash([ + new Field(BigInt(standard.fieldsConversion.length)) + ]); + return Poseidon.hash([idHash, optsHash]); +}; + +// ========================================== +// inline tests + +const TypeCheckerTestSchema = ClaimSchema(z.number()); +type TypeCheckerTestType = z.infer; +const typeCheckerTestValue = undefined as unknown as TypeCheckerTestType; +typeCheckerTestValue satisfies IClaim; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts new file mode 100644 index 0000000..e385a28 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts @@ -0,0 +1,376 @@ +import { Field } from 'o1js'; +import { + CredentialStandardSchema, + CredentialStandard, + CredentialSchema, + CredentialDataSchema, + checkCredentialStandardConformance +} from './credential.js'; + +describe('Credential creation and validation tests', () => { + let KnownUserCredential: CredentialStandard; + // credential data that adheres to the KnownUserCredential standard + // based on schema + let CredentialDataRaw1: { + claims: { + dateOfBirth: { + name: string; + value: string; + fieldsValue: number[]; + standard: typeof KnownUserCredential.schema.dateOfBirth; + }; + citizenship: { + name: string; + value: string; + fieldsValue: number[]; + standard: typeof KnownUserCredential.schema.citizenship; + }; + }; + id: { id: string }; + issuer: { pubkey: string }; + issuanceDate: { unixTimestamp: number }; + expirationDate: { unixTimestamp: number }; + subject: { pubkey: string }; + credentialSchemaHash: string; + }; + + let Credential1Raw: { + claims: { + dateOfBirth: { + name: string; + value: string; + fieldsValue: number[]; + standard: typeof KnownUserCredential.schema.dateOfBirth; + }; + citizenship: { + name: string; + value: string; + fieldsValue: number[]; + standard: typeof KnownUserCredential.schema.citizenship; + }; + }; + id: { id: string }; + issuer: { + pubkey: string; + }; + issuanceDate: { unixTimestamp: number }; + expirationDate: { unixTimestamp: number }; + subject: { + pubkey: string; + }; + credentialSchemaHash: string; + signature: { + signatureBase58: string; + }; + }; + + beforeEach(() => { + KnownUserCredential = { + standardId: 'eth.example.KnownUserCredential-v1.0', + description: + 'Credential that will be given to users after verification of documents.', + schema: { + dateOfBirth: { + standardId: 'dateOfBirth', + description: + 'Date of birth as stated on provided national id or a passport', + referenceToExternalStandard: + 'The format is described here https://www.w3.org/TR/xmlschema11-2/#dateTime', + fieldsConversion: { + length: 1, + description: + 'Converts the date to unix timestamp (seconds) and then to a single o1js Field.', + codeExample: + '// for example using `luxon.DateTime`\n return new Field(BigInt(cred.dateOfBirth.toUtc().toUnixInteger()));' + } + }, + citizenship: { + standardId: 'citizenship', + description: + 'Country citizenship as confirmed by verified documentation. Only single-country citizenships supported.', + referenceToExternalStandard: + 'The citizenship is in the form of a country code following the standard ISO 3166-1 alpha-3', + fieldsConversion: { + length: 3, + description: + 'Each of 3 letter is represented as a field using o1js.CircuitString.fromString', + codeExample: + 'o1js.CircuitString.fromString(cred.citizenship).toFields()' + } + } + } + }; + CredentialDataRaw1 = { + claims: { + dateOfBirth: { + name: 'dateOfBirth', + value: '1990-01-01T00:00:00Z', + fieldsValue: [631152000], + standard: KnownUserCredential.schema.dateOfBirth + }, + citizenship: { + name: 'citizenship', + value: 'USA', + fieldsValue: [0x5541, 0x5341, 0x0000], + standard: KnownUserCredential.schema.citizenship + } + }, + id: { id: '0x1234567890' }, + issuer: { + pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' + }, + issuanceDate: { unixTimestamp: 1710426864 }, + expirationDate: { unixTimestamp: 1720426864 }, + subject: { + pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' + }, + credentialSchemaHash: + '17162948422336679126313318026665558372573289127878826905197746632594425837153' + }; + + Credential1Raw = { + ...CredentialDataRaw1, + signature: { + signatureBase58: + '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' + } + }; + }); + + describe('CredentialStandardSchema Validation Tests', () => { + it('should validate a correct CredentialStandard object', () => { + // Perform validation on a valid CredentialStandard object + const result = CredentialStandardSchema.safeParse(KnownUserCredential); + + if (!result.success) { + console.log( + 'CredentialStandardSchema.safeParse(KnownUserCredential)', + result.error + ); + } + + // Expect success + expect(result.success).toBeTruthy(); + }); + + it('should detect invalid CredentialStandard objects', () => { + // Short standardId invalidates the CredentialStandard + let invalidCredentialStandardShortId = { + ...KnownUserCredential, + standardId: 'a' + }; + + // Empty description invalidates the CredentialStandard + let invalidCredentialStandardEmptyDescription = { + ...KnownUserCredential, + description: '' + }; + + // Empty fieldsConversion array in schema invalidates the CredentialStandard + let invalidCredentialStandardEmptyFieldsConversion = JSON.parse( + JSON.stringify(KnownUserCredential) + ); + invalidCredentialStandardEmptyFieldsConversion.schema.dateOfBirth.fieldsConversion.length = 0; + + // Empty schema invalidates the CredentialStandard + let invalidCredentialStandardEmptySchema = { + ...KnownUserCredential, + schema: {} + }; + + // Perform validation + const resultShortId = CredentialStandardSchema.safeParse( + invalidCredentialStandardShortId + ); + const resultEmptyDescription = CredentialStandardSchema.safeParse( + invalidCredentialStandardEmptyDescription + ); + const resultEmptyFieldsConversion = CredentialStandardSchema.safeParse( + invalidCredentialStandardEmptyFieldsConversion + ); + const resultEmptySchema = CredentialStandardSchema.safeParse( + invalidCredentialStandardEmptySchema + ); + + // Expect failure for each + expect(resultShortId.success).toBeFalsy(); + expect(resultEmptyDescription.success).toBeFalsy(); + expect(resultEmptyFieldsConversion.success).toBeFalsy(); + expect(resultEmptySchema.success).toBeFalsy(); + }); + }); + + describe('CredentialDataSchema and CredentialSchema Validation Tests', () => { + it('should validate correct CredentialData and Credential objects', () => { + // Perform validation on a valid CredentialData object + const resultData = CredentialDataSchema.safeParse(CredentialDataRaw1); + if (!resultData.success) { + console.log( + 'Perform validation on a valid CredentialData object', + resultData.error + ); + } + + // Perform validation on a valid Credential object + const result = CredentialSchema.safeParse(Credential1Raw); + + if (!result.success) { + console.log( + 'Perform validation on a valid Credential object', + result.error + ); + } + + // Expect success for both + expect(resultData.success).toBeTruthy(); + expect(result.success).toBeTruthy(); + }); + + it('should detect issues in invalid CredentialData and Credential objects', () => { + // Invalid CredentialData - missing claims + const invalidCredentialDataNoClaims = { + ...CredentialDataRaw1, + claims: {} + }; + expect(Object.entries(invalidCredentialDataNoClaims.claims).length).toBe( + 0 + ); + + // Invalid CredentialData - incorrect field value type + const invalidCredentialDataIncorrectFieldValue = JSON.parse( + JSON.stringify(CredentialDataRaw1) + ); + invalidCredentialDataIncorrectFieldValue.claims.dateOfBirth.fieldsValue = + 'not an array'; + + // Invalid Credential - missing signature + const invalidCredentialNoSignature: unknown & + Partial<{ signature: unknown }> = { + ...Credential1Raw + }; + delete invalidCredentialNoSignature.signature; + + // Invalid Credential - incorrect id format + const invalidCredentialIncorrectId = { + ...Credential1Raw, + id: { id: 'invalid format' } + }; + + // Perform validation + const resultNoClaims = CredentialDataSchema.safeParse( + invalidCredentialDataNoClaims + ); + const resultIncorrectFieldValue = CredentialDataSchema.safeParse( + invalidCredentialDataIncorrectFieldValue + ); + const resultNoSignature = CredentialSchema.safeParse( + invalidCredentialNoSignature + ); + const resultIncorrectId = CredentialSchema.safeParse( + invalidCredentialIncorrectId + ); + + // Expect failure for each invalid case + expect(resultNoClaims.success).toBeFalsy(); + expect(resultIncorrectFieldValue.success).toBeFalsy(); + expect(resultNoSignature.success).toBeFalsy(); + expect(resultIncorrectId.success).toBeFalsy(); + }); + }); + + describe('checkCredentialStandardConformance Function Tests', () => { + it('should confirm conformance for matching standard and credential', () => { + // Given a correct pair of Credential and CredentialStandard that are expected to match + const matchingCredential = CredentialSchema.parse(Credential1Raw); + const matchingStandard = KnownUserCredential; + + const isConformant = checkCredentialStandardConformance( + matchingCredential, + matchingStandard + ); + + // Expect the result to be true since the credential should conform to the standard + expect(isConformant).toBeTruthy(); + }); + + it('should detect non-conformance due to fields mismatch', () => { + interface Claim { + name: string; + value: string; + fieldsValue: number[]; // Adjusted to number[] since your fieldsValue seems to be an array of numbers + standard: any; // Use the actual expected type + } + + interface CredentialData { + claims: { + [key: string]: Claim; + }; + // Include other necessary fields from CredentialDataRaw1... + id: any; // Use the actual expected type + issuer: any; // Use the actual expected type + issuanceDate: any; // Use the actual expected type + expirationDate: any; // Use the actual expected type + subject: any; // Use the actual expected type + credentialSchemaHash: any; // Use the actual expected type + } + + let nonMatchingCredentialRaw: CredentialData = { ...CredentialDataRaw1 }; + // set citizenship field value to be a single field array + + delete nonMatchingCredentialRaw.claims.citizenship; + + nonMatchingCredentialRaw.claims.city = { + name: 'city', + value: 'New York', + fieldsValue: [0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b], + standard: KnownUserCredential.schema.citizenship + }; + + const result = CredentialSchema.safeParse(nonMatchingCredentialRaw); + + if (!result.success) { + console.log( + 'Should be able to parse the nonMatchingCredentialRaw', + result.error + ); + return; + } + + const nonMatchingCredential = result.data; + + expect(nonMatchingCredential.claims.citizenship).toBeUndefined(); + + // Call the function to check conformance + const isConformant = checkCredentialStandardConformance( + nonMatchingCredential, + KnownUserCredential + ); + + // Expect the result to be false since the credential fields do not match the standard specifications + expect(isConformant).toBeFalsy(); + }); + + it('should detect non-conformance due to fieldValues length mismatch', () => { + // Define a non-matching CredentialStandard and Credential by altering the fields + const matchingCredential = CredentialSchema.parse(Credential1Raw); + + let nonMatchingCredential = { + ...matchingCredential, + claims: { ...matchingCredential.claims } + }; + // set citizenship field value to be a single field array + nonMatchingCredential.claims.citizenship.fieldsValue = [ + new Field(0x5541) + ]; + + // Call the function to check conformance + const isConformant = checkCredentialStandardConformance( + nonMatchingCredential, + KnownUserCredential + ); + + // Expect the result to be false since the credential fields do not match the standard specifications + expect(isConformant).toBeFalsy(); + }); + }); +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts new file mode 100644 index 0000000..aa591ec --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -0,0 +1,106 @@ +import { CircuitString, Field, Poseidon } from 'o1js'; +import { z } from 'zod'; +import { + ClaimSchema, + ClaimStandard, + ClaimStandardSchema, + IClaim, + claimStandardHash +} from './claim.js'; +import { + CredSubjectIdSchema, + IssuerIdSchema, + VCredIdSchema +} from './data/ids.js'; +import { + FieldSchema, + SignatureSchema, + UnixTimestampSchema +} from './data/simple.js'; +import { arraysAreEqual } from './helpers/utils.js'; + +export const CredentialStandardSchema = z.object({ + standardId: z.string().min(2), + description: z.string().min(2), + schema: z.record(z.string().min(2), ClaimStandardSchema).refine( + (schema) => Object.keys(schema).length > 0, + { message: 'Must define at least one claim.' } + ) +}); + +export type CredentialStandard = z.infer; + +export const credentialStandardHash = (standard: CredentialStandard): Field => { + const idHash = Poseidon.hash( + CircuitString.fromString(standard.standardId).toFields() + ); + const schemaHash = Poseidon.hash( + Object.values(standard.schema).map(claimStandardHash) + ); + return Poseidon.hash([idHash, schemaHash]); +}; + +export const CredentialDataSchema = z.object({ + claims: z.record(z.string().min(1), ClaimSchema(z.unknown())).refine( + (claims) => Object.keys(claims).length > 0, + { message: 'Must define at least one claim.' } + ), + id: VCredIdSchema, + issuer: IssuerIdSchema, + issuanceDate: UnixTimestampSchema, + expirationDate: UnixTimestampSchema, + subject: CredSubjectIdSchema, + credentialSchemaHash: FieldSchema, +}); + +export const CredentialSchema = CredentialDataSchema.extend({ + signature: SignatureSchema +}); + +export type CredentialData = z.infer; + +export type Credential = z.infer; + + +export const checkCredentialStandardConformance = ( + credential: Credential, + standard: CredentialStandard +): boolean => { + // check credential fields presence + const claimNames = Object.keys(standard.schema); + const credentialClaimNames = Object.keys(credential.claims); + if (!arraysAreEqual(claimNames, credentialClaimNames)) { + return false; + } + + // check if the fieldValues have the necessary length + for (const [claimName, claimValue] of Object.entries(credential.claims)) { + const standardClaim = standard.schema[claimName]; + if ( + claimValue.fieldsValue.length !== standardClaim.fieldsConversion.length + ) { + return false; + } + } + return true; +}; + + + +// ========================================== +// inline tests + +let asd = undefined as unknown as ClaimStandard; + +let cred: CredentialStandard = { + standardId: 'personhood1', + description: 'Proves that subject is a person', + schema: { + name: asd + } +}; + +const TypeCheckerTestSchema = ClaimSchema(z.number()); +type TypeCheckerTestType = z.infer; +const typeCheckerTestValue = undefined as unknown as TypeCheckerTestType; +typeCheckerTestValue satisfies IClaim; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts index 7c06951..3e1157a 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts @@ -5,32 +5,32 @@ import { arraysAreEqual, ftn } from '../helpers/utils.js'; const CLAIMS_MAX_SIZE = 128; -export interface IClaim { - length: Field; - claimValue: Field[]; +export interface IClaimStruct { + get length(): Field; + get claimValue(): Field[]; toFields(): Field[]; } -export interface IClaimClass { - new (claimValue: Field[]): IClaim; - fromFields(fields: Field[]): IClaim; +export interface IClaimStructClass { + new (claimValue: Field[]): IClaimStruct; + fromFields(fields: Field[]): IClaimStruct; schema: z.ZodType; } -export interface IClaims { +export interface IFieldClaims { count: Field; packed: Field[]; toFields(): Field[]; getClaim(ix: Field, assert: Field[]): Field[]; } -export const ClaimStruct = (length: number): IClaimClass => { +export const ClaimStruct = (length: number): IClaimStructClass => { class Claim_ extends Struct({ length: Field, claimValue: Provable.Array(Field, length) }) - implements IClaim + implements IClaimStruct { constructor(claimValue: Field[]) { if (claimValue.length !== length) { @@ -58,7 +58,7 @@ export const ClaimStruct = (length: number): IClaimClass => { .transform((o) => new Claim_(o.claimValue)); } - return Claim_ as IClaimClass; + return Claim_ as IClaimStructClass; }; export const mkClaimStruct = (flds: Field[]) => { @@ -66,11 +66,11 @@ export const mkClaimStruct = (flds: Field[]) => { return ClaimStruct(n).fromFields(flds); }; -export const computeClaimSizes = (claims: IClaim[]) => { +export const computeClaimSizes = (claims: IClaimStruct[]) => { return claims.map(c => ftn(c.length)); }; -export const mkClaims = (claims: IClaim[]): IClaims => { +export const mkClaims = (claims: IClaimStruct[]): IFieldClaims => { const size = computeClaimSizes(claims); return Claims(size).fromClaims(claims); }; @@ -94,7 +94,7 @@ export function Claims(claimSizes: number[]) { count: Field, packed: Provable.Array(Field, totalSize) }) - implements IClaims + implements IFieldClaims { static MAX_SIZE = CLAIMS_MAX_SIZE; @@ -102,7 +102,7 @@ export function Claims(claimSizes: number[]) { return [this.count, ...this.packed]; } - static fromClaims(claims: IClaim[]) { + static fromClaims(claims: IClaimStruct[]) { const receivedSizes = claims.map((c) => ftn(c.length)); if (!arraysAreEqual(receivedSizes, claimSizes)) { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts index 82f117f..8e13a72 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts @@ -32,7 +32,7 @@ export class UnixTimestamp extends Struct({ export const UnixTimestampSchema = z .object({ - unixTimestamp: FieldSchemaDec + unixTimestamp: FieldSchemaDec.or(FieldSchemaInt).or(FieldSchemaBigInt) }) .transform((o) => new UnixTimestamp({ unixTimestamp: o.unixTimestamp })); @@ -44,7 +44,6 @@ export const inline_tests = () => { const f1: Field = FieldSchemaInt.parse(fieldi); log.info('Parsed field from int encoding: ', fieldi, f1); - const fieldbigi = 123n; const f2: Field = FieldSchemaBigInt.parse(fieldbigi); log.info('Parsed field from big int encoding: ', fieldbigi, f2); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts index 5fba61d..f8b0b20 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts @@ -1,6 +1,6 @@ import { Field, PrivateKey, Signature } from 'o1js'; import { VCredStruct, VCredStructUnsigned } from './vcred.js'; // Update import path as needed -import { ClaimStruct, IClaim, mkClaims } from './claims.js'; // Import necessary dependencies +import { ClaimStruct, IClaimStruct, mkClaims } from './claims.js'; // Import necessary dependencies import { CredSubjectId, IssuerId, VCredId } from './ids.js'; import { UnixTimestamp } from './simple.js'; @@ -10,8 +10,8 @@ describe('VCredStruct tests', () => { const pk2 = PrivateKey.random().toPublicKey(); const pk2s = pk2.toBase58(); - let claim1: IClaim; - let claim2: IClaim; + let claim1: IClaimStruct; + let claim2: IClaimStruct; const claim1s = { claimValue: [1, 2, 3] diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts index a3de797..ac9bf85 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts @@ -12,7 +12,7 @@ import { z } from 'zod'; export function VCredStructUnsigned(claimSizes: number[]) { const ClaimsType = Claims(claimSizes); - const Fields = { + const Data = { id: VCredId, issuer: IssuerId, issuanceDate: UnixTimestamp, @@ -22,8 +22,8 @@ export function VCredStructUnsigned(claimSizes: number[]) { credentialSchemaHash: Field }; - class BaseVCredStruct_ extends Struct(Fields) { - static Fields = Fields; + class BaseVCredStruct_ extends Struct(Data) { + static Fields = Data; public toFields() { return [ diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 7b9bcb5..34ebfb9 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,9 +1,5 @@ -import { Field, PrivateKey, Provable, PublicKey, Signature, Struct, verify } from 'o1js'; import { Logger } from 'tslog'; -import { z } from 'zod'; -import * as Simple from './data/simple.js'; -import * as Ids from './data/ids.js'; -import { IxRange } from './zkclaims/vcred-proof.js'; +import { CredentialStandard } from './credential'; const log = new Logger({ name: 'index.ts prototyping' }); @@ -30,18 +26,47 @@ log.info('========= Schemas ========='); // const IssuerIdSchema = PublicKeyB58Schema; // type IssuerId = z.infer; -log.info('Creating a new credential schema'); - - -log.info('Registering the new credential schema'); +log.info('Creating a new credential standard'); + +const KnownUserCredential: CredentialStandard = { + standardId: "eth.example.KnownUserCredential-v1.0", + description: "Credential that will be given to users after verification of documents.", + schema: { + dateOfBirth: { + standardId: "dateOfBirth", + description: "Date of birth as stated on provided national id or a passport", + referenceToExternalStandard: "The format is described here https://www.w3.org/TR/xmlschema11-2/#dateTime", + fieldsConversion: { + length: 1, + description: "Converts the date to unix timestamp (seconds) and then to a single o1js Field.", + codeExample: "// for example using `luxon.DateTime`\n return new Field(BigInt(cred.dateOfBirth.toUtc().toUnixInteger()));" + } + }, + citizenship: { + standardId: "citizenship", + description: "Country citizenship as confirmed by verified documentation. Only single-country citizenships supported.", + referenceToExternalStandard: "The citizenship is in the form of a country code following the standard ISO 3166-1 alpha-3", + fieldsConversion: { + length: 3, + description: "Each of 3 letter is represented as a field using o1js.CircuitString.fromString", + codeExample: "o1js.CircuitString.fromString(cred.citizenship).toFields()" + } + } + } +} + + +log.info('Registering the new credential standard - later'); log.info('Issuing a credential'); -log.info('Delivering the credential to the holder '); +log.info('1. Create credential'); -log.info(' 1. simplest way possible'); +log.info('2. Have it serialized'); -log.info(' 2. (maybe later) on valid pkey proof '); +log.info('3. Verify and sign'); + +log.info('4. Make it available to holder on access code.'); log.info('========= Holder / Prover ========='); @@ -97,11 +122,3 @@ log.info('Checking outputs validity'); log.info('Revocation proofs'); log.info(''); - -const p = PrivateKey.random(); - -const pk = p.toPublicKey(); - -const pkf = pk.toFields(); - -console.log(pkf.length); From e03d8d7cd7f20de3d3b44a695ea8a259a1d8b890 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Fri, 29 Mar 2024 22:25:47 +0100 Subject: [PATCH 15/34] Add two claims standards, fix couple of bugs, proceed with happy path flow --- .../src/claim.ts | 2 +- .../src/credential.test.ts | 12 +- .../src/credential.ts | 144 +++++++-- .../src/data/simple.ts | 6 + .../src/data/vcred.test.ts | 8 +- .../src/data/vcred.ts | 16 +- .../src/index.ts | 113 ++++--- .../src/issuer.ts | 33 ++ .../src/zkclaims/citizenship.ts | 299 ++++++++++++++++++ .../src/zkclaims/dateOfBirth.ts | 26 ++ 10 files changed, 568 insertions(+), 91 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts index a648824..28935ea 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts @@ -1,7 +1,7 @@ import { CircuitString, Field, Poseidon } from 'o1js'; import { z } from 'zod'; import { ClaimStruct, IClaimStruct } from './data/claims.js'; -import { FieldsSchema } from './data/simple'; +import { FieldsSchema } from './data/simple.js'; export const ClaimStandardSchema = z.object({ standardId: z.string().min(2), diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts index e385a28..dc2c5a1 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts @@ -3,8 +3,8 @@ import { CredentialStandardSchema, CredentialStandard, CredentialSchema, - CredentialDataSchema, - checkCredentialStandardConformance + checkCredentialStandardConformance, + CredentialDataSchema } from './credential.js'; describe('Credential creation and validation tests', () => { @@ -31,7 +31,7 @@ describe('Credential creation and validation tests', () => { issuanceDate: { unixTimestamp: number }; expirationDate: { unixTimestamp: number }; subject: { pubkey: string }; - credentialSchemaHash: string; + credentialStandardHash: string; }; let Credential1Raw: { @@ -58,7 +58,7 @@ describe('Credential creation and validation tests', () => { subject: { pubkey: string; }; - credentialSchemaHash: string; + credentialStandardHash: string; signature: { signatureBase58: string; }; @@ -124,7 +124,7 @@ describe('Credential creation and validation tests', () => { subject: { pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' }, - credentialSchemaHash: + credentialStandardHash: '17162948422336679126313318026665558372573289127878826905197746632594425837153' }; @@ -311,7 +311,7 @@ describe('Credential creation and validation tests', () => { issuanceDate: any; // Use the actual expected type expirationDate: any; // Use the actual expected type subject: any; // Use the actual expected type - credentialSchemaHash: any; // Use the actual expected type + credentialStandardHash: any; // Use the actual expected type } let nonMatchingCredentialRaw: CredentialData = { ...CredentialDataRaw1 }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts index aa591ec..c346aa3 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -1,66 +1,98 @@ -import { CircuitString, Field, Poseidon } from 'o1js'; +import { CircuitString, Field, Poseidon, PrivateKey } from 'o1js'; +import * as o1js from 'o1js'; import { z } from 'zod'; import { ClaimSchema, - ClaimStandard, ClaimStandardSchema, IClaim, claimStandardHash } from './claim.js'; import { + CredSubjectId, CredSubjectIdSchema, IssuerIdSchema, VCredIdSchema } from './data/ids.js'; import { FieldSchema, + SignatureB58, SignatureSchema, UnixTimestampSchema } from './data/simple.js'; import { arraysAreEqual } from './helpers/utils.js'; +import { Issuer } from './issuer.js'; +import { VCredStruct, VCredStructUnsigned } from './data/vcred.js'; +import { Logger } from 'tslog'; + +const log = new Logger({ name: 'credential.ts' }); + +// =============== Credential Trasit Types ================== + +// ---------------- Credential Standard ---------------- export const CredentialStandardSchema = z.object({ standardId: z.string().min(2), description: z.string().min(2), - schema: z.record(z.string().min(2), ClaimStandardSchema).refine( - (schema) => Object.keys(schema).length > 0, - { message: 'Must define at least one claim.' } - ) + schema: z + .record(z.string().min(2), ClaimStandardSchema) + .refine((schema) => Object.keys(schema).length > 0, { + message: 'Must define at least one claim.' + }) }); export type CredentialStandard = z.infer; -export const credentialStandardHash = (standard: CredentialStandard): Field => { - const idHash = Poseidon.hash( - CircuitString.fromString(standard.standardId).toFields() - ); - const schemaHash = Poseidon.hash( - Object.values(standard.schema).map(claimStandardHash) - ); - return Poseidon.hash([idHash, schemaHash]); -}; +// ---------------- Credential Data ---------------- export const CredentialDataSchema = z.object({ - claims: z.record(z.string().min(1), ClaimSchema(z.unknown())).refine( - (claims) => Object.keys(claims).length > 0, - { message: 'Must define at least one claim.' } - ), + claims: z + .record(z.string().min(1), ClaimSchema(z.unknown())) + .refine((claims) => Object.keys(claims).length > 0, { + message: 'Must define at least one claim.' + }), id: VCredIdSchema, issuer: IssuerIdSchema, issuanceDate: UnixTimestampSchema, expirationDate: UnixTimestampSchema, subject: CredSubjectIdSchema, - credentialSchemaHash: FieldSchema, + credentialStandardHash: FieldSchema }); +export type CredentialData = z.infer; + +// ---------------- Credential ---------------- + export const CredentialSchema = CredentialDataSchema.extend({ signature: SignatureSchema }); -export type CredentialData = z.infer; - export type Credential = z.infer; +// =============== To fields-encoded types =============== + +export const mkStructCredentialUnsigned = (credential: CredentialData) => { + log.debug('Entering mkStructCredentialUnsigned...', credential); + return VCredStructUnsigned( + Object.values(credential.claims).map((claim) => claim.fieldsValue.length) + ).schema.parse({ + ...credential, + claims: Object.values(credential.claims).map((claim) => ({ + claimValue: claim.fieldsValue + })) + }); +}; + +// signed version +export const mkStructCredential = (credential: Credential) => { + return VCredStruct( + Object.values(credential.claims).map((claim) => claim.fieldsValue.length) + ).schema.parse({ + ...credential, + claims: Object.values(credential.claims).map((claim) => ({ + claimValue: claim.fieldsValue + })) + }); +}; export const checkCredentialStandardConformance = ( credential: Credential, @@ -85,20 +117,68 @@ export const checkCredentialStandardConformance = ( return true; }; +export const credentialStandardHash = (standard: CredentialStandard): Field => { + const idHash = Poseidon.hash( + CircuitString.fromString(standard.standardId).toFields() + ); + const schemaHash = Poseidon.hash( + Object.values(standard.schema).map(claimStandardHash) + ); + return Poseidon.hash([idHash, schemaHash]); +}; +export const verifyAndIssueCredential = + ( + standard: CredentialStandard, + credentialData: CredentialData, + subject: CredSubjectId, + issuer: Issuer + ) => + (privateKey: PrivateKey) => { + // get fields for the signature + log.debug('Entering verifyAndIssueCredential...'); + + log.debug('Converting the credential data to o1js fields.'); + const flds = mkStructCredentialUnsigned(credentialData).toFields(); + + log.debug('Creating signature for the fields data'); + const signature: SignatureB58 = SignatureSchema.parse( + o1js.Signature.create(privateKey, flds).toBase58() + ); + + // create the credential + + log.debug('Parsing the credential with the signature'); + const credential = CredentialSchema.parse({ + ...credentialData, + signature + }); + + // check if the credential conforms to the standard + log.debug('Checking credential standard conformance...'); + const check = checkCredentialStandardConformance(credential, standard); + if (!check) { + throw new Error('Credential does not conform to standard'); + } -// ========================================== -// inline tests + // additional assertions + // issuer pubkey matches the private key + if (!issuer.pubkey.equals(privateKey.toPublicKey())) { + throw new Error('Issuer pubkey does not match the private key'); + } -let asd = undefined as unknown as ClaimStandard; + // credential subject public key matches the given subject public key + if (!credential.subject.pubkey.equals(subject.pubkey)) { + throw new Error('Subject does not match the credential subject'); + } -let cred: CredentialStandard = { - standardId: 'personhood1', - description: 'Proves that subject is a person', - schema: { - name: asd - } -}; + return { + credential + }; + }; + +// ========================================== +// inline tests const TypeCheckerTestSchema = ClaimSchema(z.number()); type TypeCheckerTestType = z.infer; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts index 8e13a72..ecf55cf 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts @@ -2,6 +2,10 @@ import { Field, PublicKey, Struct, Signature } from 'o1js'; import { Logger } from 'tslog'; import { z } from 'zod'; +const hexViaFieldBigInt = (x: number | bigint | string) => { + return '0x' + (new Field(x)).toBigInt().toString(16); +} + export const FieldSchemaInt = z.number().int().transform((n) => new Field(BigInt(n))); export const FieldSchemaBigInt = z.bigint().transform(Field); export const FieldSchemaDec = z.string().regex(/^\d+$/).transform(Field); @@ -22,6 +26,8 @@ export const SignatureSchema = z }) .transform((o) => Signature.fromBase58(o.signatureBase58)); +export type SignatureB58 = z.infer; + export class UnixTimestamp extends Struct({ unixTimestamp: Field }) { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts index f8b0b20..98924ef 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts @@ -39,7 +39,7 @@ describe('VCredStruct tests', () => { }), subject: new CredSubjectId({ pubkey: pk2 }), claims: mkClaims([claim1, claim2]), - credentialSchemaHash: new Field(789) + credentialStandardHash: new Field(789) }; }; @@ -61,7 +61,7 @@ describe('VCredStruct tests', () => { expirationDate: { unixTimestamp: '223123123' }, subject: { pubkey: pk2s }, claims: [claim1s, claim2s], - credentialSchemaHash: '789' + credentialStandardHash: '789' }); if (!validation.success) { @@ -85,7 +85,7 @@ describe('VCredStruct tests', () => { }), subject: new CredSubjectId({ pubkey: pk2 }), claims: mkClaims([claim1, claim2]), - credentialSchemaHash: new Field(789), + credentialStandardHash: new Field(789), signature: Signature.fromBase58('7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE') }; }; @@ -107,7 +107,7 @@ describe('VCredStruct tests', () => { expirationDate: { unixTimestamp: '223123123' }, subject: { pubkey: pk2s }, claims: [claim1s, claim2s], - credentialSchemaHash: '789', + credentialStandardHash: '789', signature: {signatureBase58: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE'} }); if(!validation.success){ diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts index ac9bf85..57c92de 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts @@ -19,21 +19,21 @@ export function VCredStructUnsigned(claimSizes: number[]) { expirationDate: UnixTimestamp, subject: CredSubjectId, claims: ClaimsType, - credentialSchemaHash: Field + credentialStandardHash: Field }; class BaseVCredStruct_ extends Struct(Data) { static Fields = Data; - public toFields() { + public toFields(): Field[] { return [ - this.id, + ...this.id.toFields(), ...this.issuer.toFields(), - this.issuanceDate, - this.expirationDate, + ...this.issuanceDate.toFields(), + ...this.expirationDate.toFields(), ...this.subject.toFields(), ...this.claims.toFields(), - this.credentialSchemaHash + ...this.credentialStandardHash.toFields() ]; } @@ -45,7 +45,7 @@ export function VCredStructUnsigned(claimSizes: number[]) { expirationDate: UnixTimestampSchema, subject: CredSubjectIdSchema, claims: ClaimsType.schema, - credentialSchemaHash: FieldSchema + credentialStandardHash: FieldSchema }); } @@ -85,7 +85,7 @@ export function VCredStruct(claimSizes: number[]) { return VCredStruct_.dataSchema.transform( (data) => new VCredStruct_(data) ); - } + } } return VCredStruct_; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 34ebfb9..8835053 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,30 +1,34 @@ import { Logger } from 'tslog'; -import { CredentialStandard } from './credential'; +import { Credential, CredentialData, CredentialDataSchema, CredentialStandard, credentialStandardHash, verifyAndIssueCredential } from './credential.js'; +import { CircuitString, Field, PrivateKey } from 'o1js'; +import { CredSubjectId, CredSubjectIdSchema, IssuerIdSchema, VCredIdSchema } from './data/ids.js'; +import { Issuer, IssuerSchema } from './issuer.js'; +import * as DateOfBirth from './zkclaims/dateOfBirth.js'; +import * as Citizenship from './zkclaims/citizenship.js'; +import { DateTime } from 'luxon'; +import { UnixTimestampSchema } from './data/simple.js'; const log = new Logger({ name: 'index.ts prototyping' }); log.info('Happy path testing...'); -log.info('========= Schemas ========='); -// SimpleSchemas.inline_tests(); +log.info('========= Preliminary data ========='); +/** Provisinal function to provide a subject of a credential */ +const mkCredentialSubject = () => { + const privateKey = PrivateKey.random(); + const pubkey = privateKey.toPublicKey().toBase58(); + const r: CredSubjectId = CredSubjectIdSchema.parse({ pubkey }); + + return { privateKey, subject: r }; +} +const { privateKey: subjectPrivateKey, subject } = mkCredentialSubject(); -// /** -// * Represents an issuer with a public key. Future versions might replace this -// * with a more complex ID system, such as DIDs. -// */ -// export class IssuerId extends Struct({ -// pubkey: PublicKey -// }) { -// public toFields() { -// return this.pubkey.toFields(); -// } -// } -// const IssuerIdSchema = PublicKeyB58Schema; -// type IssuerId = z.infer; +log.info('========= Issuer ========='); + log.info('Creating a new credential standard'); @@ -32,46 +36,75 @@ const KnownUserCredential: CredentialStandard = { standardId: "eth.example.KnownUserCredential-v1.0", description: "Credential that will be given to users after verification of documents.", schema: { - dateOfBirth: { - standardId: "dateOfBirth", - description: "Date of birth as stated on provided national id or a passport", - referenceToExternalStandard: "The format is described here https://www.w3.org/TR/xmlschema11-2/#dateTime", - fieldsConversion: { - length: 1, - description: "Converts the date to unix timestamp (seconds) and then to a single o1js Field.", - codeExample: "// for example using `luxon.DateTime`\n return new Field(BigInt(cred.dateOfBirth.toUtc().toUnixInteger()));" - } - }, - citizenship: { - standardId: "citizenship", - description: "Country citizenship as confirmed by verified documentation. Only single-country citizenships supported.", - referenceToExternalStandard: "The citizenship is in the form of a country code following the standard ISO 3166-1 alpha-3", - fieldsConversion: { - length: 3, - description: "Each of 3 letter is represented as a field using o1js.CircuitString.fromString", - codeExample: "o1js.CircuitString.fromString(cred.citizenship).toFields()" - } - } + dateOfBirth: DateOfBirth.schema, + citizenship: Citizenship.schema } } - log.info('Registering the new credential standard - later'); + +log.info('Creating a new issuer'); + +const createIssuer = () => { + const privateKey = PrivateKey.random(); + const pubkey = privateKey.toPublicKey().toBase58(); + const issuer: Issuer = IssuerSchema.parse({id: {pubkey}}) + return {privateKey, issuer}; +} + +const {privateKey: issuerPrivateKey, issuer} = createIssuer(); + + log.info('Issuing a credential'); log.info('1. Create credential'); -log.info('2. Have it serialized'); +// provisional function to create a credential data +// use it to create a sensible helper function +const mkCredentialData = () => { + // throw new Error('Not implemented'); + const data: CredentialData = { + id: VCredIdSchema.parse({id: "123"}), + subject, + issuer: issuer.id, + claims: { + dateOfBirth: DateOfBirth.mkDateOfBirthClaim(DateTime.now()), + citizenship: Citizenship.mkCitizenshipClaim("USA") + }, + issuanceDate: UnixTimestampSchema.parse({ + unixTimestamp: DateTime.now().toUTC().toUnixInteger() + }), + expirationDate: UnixTimestampSchema.parse({ + unixTimestamp: DateTime.now().plus({years: 1}).toUTC().toUnixInteger() + }), + credentialStandardHash: credentialStandardHash(KnownUserCredential) + } + return data; +}; -log.info('3. Verify and sign'); +const credentialData: CredentialData = mkCredentialData(); -log.info('4. Make it available to holder on access code.'); +log.info('2. Verify and sign'); + +const {credential: verifiedCredential} = verifyAndIssueCredential( + KnownUserCredential, + credentialData, + subject, + issuer +)(issuerPrivateKey); + +log.info('3. Make it available to holder on access code.'); + +// create a custom plugin route where this credential can be accessed when +// given id and signature matching the subject log.info('========= Holder / Prover ========='); log.info('Requesting a credential'); +// access the custom route - assume the knowledge of the document id + log.info('Installing in the credential store'); log.info('(later) Requesting a resource access schema'); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts new file mode 100644 index 0000000..e940a6d --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts @@ -0,0 +1,33 @@ +import { z } from 'zod'; +import { IssuerId, IssuerIdSchema } from './data/ids.js'; + +interface IssuerProps { + id: IssuerId; +} + +export class Issuer { + id: IssuerId; + constructor(props: IssuerProps) { + Object.assign(this, props); + } + + get pubkey() { + return this.id.pubkey; + } +} + +// to be extended later +export const IssuerSchema = z.object({ + id: IssuerIdSchema +}).transform((d) => new Issuer(d)); + + + + + + + +// type-checker level assertion to keep the schema and the interface in sync +type IssuerData = z.infer; +const issuerData = undefined as unknown as IssuerData; +issuerData satisfies IssuerProps; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts new file mode 100644 index 0000000..7fa4576 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts @@ -0,0 +1,299 @@ +import { CircuitString } from 'o1js'; +import { IClaim } from 'src/claim'; + +const CODE_LENGTH = 3; + +export const schema = { + standardId: 'citizenship', + description: + 'Country citizenship as confirmed by verified documentation. Only single-country citizenships supported.', + referenceToExternalStandard: + 'The citizenship is in the form of a country code following the standard ISO 3166-1 alpha-3', + fieldsConversion: { + length: CODE_LENGTH, + description: + 'Each of 3 letter is represented as a field using o1js.CircuitString.fromString', + codeExample: `o1js.CircuitString.fromString(cred.citizenship).toFields().slice(0, ${CODE_LENGTH})` + } +}; + +export const mkCitizenshipClaim = (name: string): IClaim => { + const code = nameToCode.get(name); + + // if the name is not a valid country name, return an error + if (!code) { + throw new Error(`Invalid country name ${name}`); + } + + return { + name: 'citizenship', + value: code, + fieldsValue: CircuitString.fromString(code).toFields().slice(0, CODE_LENGTH), + standard: schema + }; +}; + + +// ISO 3166-1 alpha-3 codes +const CODES = { + ABW: 'Aruba', + AFG: 'Afghanistan', + AGO: 'Angola', + AIA: 'Anguilla', + ALA: 'Åland Islands', + ALB: 'Albania', + AND: 'Andorra', + ARE: 'United Arab Emirates', + ARG: 'Argentina', + ARM: 'Armenia', + ASM: 'American Samoa', + ATA: 'Antarctica', + ATF: 'French Southern Territories', + ATG: 'Antigua and Barbuda', + AUS: 'Australia', + AUT: 'Austria', + AZE: 'Azerbaijan', + BDI: 'Burundi', + BEL: 'Belgium', + BEN: 'Benin', + BES: 'Bonaire, Sint Eustatius and Saba', + BFA: 'Burkina Faso', + BGD: 'Bangladesh', + BGR: 'Bulgaria', + BHR: 'Bahrain', + BHS: 'Bahamas', + BIH: 'Bosnia and Herzegovina', + BLM: 'Saint Barthélemy', + BLR: 'Belarus', + BLZ: 'Belize', + BMU: 'Bermuda', + BOL: 'Bolivia, Plurinational State of', + BRA: 'Brazil', + BRB: 'Barbados', + BRN: 'Brunei Darussalam', + BTN: 'Bhutan', + BVT: 'Bouvet Island', + BWA: 'Botswana', + CAF: 'Central African Republic', + CAN: 'Canada', + CCK: 'Cocos (Keeling) Islands', + CHE: 'Switzerland', + CHL: 'Chile', + CHN: 'China', + CIV: "Côte d'Ivoire", + CMR: 'Cameroon', + COD: 'Congo, Democratic Republic of the', + COG: 'Congo', + COK: 'Cook Islands', + COL: 'Colombia', + COM: 'Comoros', + CPV: 'Cabo Verde', + CRI: 'Costa Rica', + CUB: 'Cuba', + CUW: 'Curaçao', + CXR: 'Christmas Island', + CYM: 'Cayman Islands', + CYP: 'Cyprus', + CZE: 'Czechia', + DEU: 'Germany', + DJI: 'Djibouti', + DMA: 'Dominica', + DNK: 'Denmark', + DOM: 'Dominican Republic', + DZA: 'Algeria', + ECU: 'Ecuador', + EGY: 'Egypt', + ERI: 'Eritrea', + ESH: 'Western Sahara', + ESP: 'Spain', + EST: 'Estonia', + ETH: 'Ethiopia', + FIN: 'Finland', + FJI: 'Fiji', + FLK: 'Falkland Islands (Malvinas)', + FRA: 'France', + FRO: 'Faroe Islands', + FSM: 'Micronesia, Federated States of', + GAB: 'Gabon', + GBR: 'United Kingdom of Great Britain and Northern Ireland', + GEO: 'Georgia', + GGY: 'Guernsey', + GHA: 'Ghana', + GIB: 'Gibraltar', + GIN: 'Guinea', + GLP: 'Guadeloupe', + GMB: 'Gambia', + GNB: 'Guinea-Bissau', + GNQ: 'Equatorial Guinea', + GRC: 'Greece', + GRD: 'Grenada', + GRL: 'Greenland', + GTM: 'Guatemala', + GUF: 'French Guiana', + GUM: 'Guam', + GUY: 'Guyana', + HKG: 'Hong Kong', + HMD: 'Heard Island and McDonald Islands', + HND: 'Honduras', + HRV: 'Croatia', + HTI: 'Haiti', + HUN: 'Hungary', + IDN: 'Indonesia', + IMN: 'Isle of Man', + IND: 'India', + IOT: 'British Indian Ocean Territory', + IRL: 'Ireland', + IRN: 'Iran, Islamic Republic of', + IRQ: 'Iraq', + ISL: 'Iceland', + ISR: 'Israel', + ITA: 'Italy', + JAM: 'Jamaica', + JEY: 'Jersey', + JOR: 'Jordan', + JPN: 'Japan', + KAZ: 'Kazakhstan', + KEN: 'Kenya', + KGZ: 'Kyrgyzstan', + KHM: 'Cambodia', + KIR: 'Kiribati', + KNA: 'Saint Kitts and Nevis', + KOR: 'Korea, Republic of', + KWT: 'Kuwait', + LAO: "Lao People's Democratic Republic", + LBN: 'Lebanon', + LBR: 'Liberia', + LBY: 'Libya', + LCA: 'Saint Lucia', + LIE: 'Liechtenstein', + LKA: 'Sri Lanka', + LSO: 'Lesotho', + LTU: 'Lithuania', + LUX: 'Luxembourg', + LVA: 'Latvia', + MAC: 'Macao', + MAF: 'Saint Martin (French part)', + MAR: 'Morocco', + MCO: 'Monaco', + MDA: 'Moldova, Republic of', + MDG: 'Madagascar', + MDV: 'Maldives', + MEX: 'Mexico', + MHL: 'Marshall Islands', + MKD: 'North Macedonia', + MLI: 'Mali', + MLT: 'Malta', + MMR: 'Myanmar', + MNE: 'Montenegro', + MNG: 'Mongolia', + MNP: 'Northern Mariana Islands', + MOZ: 'Mozambique', + MRT: 'Mauritania', + MSR: 'Montserrat', + MTQ: 'Martinique', + MUS: 'Mauritius', + MWI: 'Malawi', + MYS: 'Malaysia', + MYT: 'Mayotte', + NAM: 'Namibia', + NCL: 'New Caledonia', + NER: 'Niger', + NFK: 'Norfolk Island', + NGA: 'Nigeria', + NIC: 'Nicaragua', + NIU: 'Niue', + NLD: 'Netherlands, Kingdom of the', + NOR: 'Norway', + NPL: 'Nepal', + NRU: 'Nauru', + NZL: 'New Zealand', + OMN: 'Oman', + PAK: 'Pakistan', + PAN: 'Panama', + PCN: 'Pitcairn', + PER: 'Peru', + PHL: 'Philippines', + PLW: 'Palau', + PNG: 'Papua New Guinea', + POL: 'Poland', + PRI: 'Puerto Rico', + PRK: "Korea, Democratic People's Republic of", + PRT: 'Portugal', + PRY: 'Paraguay', + PSE: 'Palestine, State of', + PYF: 'French Polynesia', + QAT: 'Qatar', + REU: 'Réunion', + ROU: 'Romania', + RUS: 'Russian Federation', + RWA: 'Rwanda', + SAU: 'Saudi Arabia', + SDN: 'Sudan', + SEN: 'Senegal', + SGP: 'Singapore', + SGS: 'South Georgia and the South Sandwich Islands', + SHN: 'Saint Helena, Ascension and Tristan da Cunha', + SJM: 'Svalbard and Jan Mayen', + SLB: 'Solomon Islands', + SLE: 'Sierra Leone', + SLV: 'El Salvador', + SMR: 'San Marino', + SOM: 'Somalia', + SPM: 'Saint Pierre and Miquelon', + SRB: 'Serbia', + SSD: 'South Sudan', + STP: 'Sao Tome and Principe', + SUR: 'Suriname', + SVK: 'Slovakia', + SVN: 'Slovenia', + SWE: 'Sweden', + SWZ: 'Eswatini', + SXM: 'Sint Maarten (Dutch part)', + SYC: 'Seychelles', + SYR: 'Syrian Arab Republic', + TCA: 'Turks and Caicos Islands', + TCD: 'Chad', + TGO: 'Togo', + THA: 'Thailand', + TJK: 'Tajikistan', + TKL: 'Tokelau', + TKM: 'Turkmenistan', + TLS: 'Timor-Leste', + TON: 'Tonga', + TTO: 'Trinidad and Tobago', + TUN: 'Tunisia', + TUR: 'Türkiye', + TUV: 'Tuvalu', + TWN: 'Taiwan, Province of China', + TZA: 'Tanzania, United Republic of', + UGA: 'Uganda', + UKR: 'Ukraine', + UMI: 'United States Minor Outlying Islands', + URY: 'Uruguay', + USA: 'United States of America', + UZB: 'Uzbekistan', + VAT: 'Holy See', + VCT: 'Saint Vincent and the Grenadines', + VEN: 'Venezuela, Bolivarian Republic of', + VGB: 'Virgin Islands (British)', + VIR: 'Virgin Islands (U.S.)', + VNM: 'Viet Nam', + VUT: 'Vanuatu', + WLF: 'Wallis and Futuna', + WSM: 'Samoa', + YEM: 'Yemen', + ZAF: 'South Africa', + ZMB: 'Zambia', + ZWE: 'Zimbabwe' +}; + +const mkNameToCodeMap = () => { + const nameToCode = new Map(); + for (const [code, name] of Object.entries(CODES)) { + nameToCode.set(name, code); + nameToCode.set(code, code); + } + return nameToCode; +}; + +const nameToCode = mkNameToCodeMap(); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts new file mode 100644 index 0000000..b6e151b --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts @@ -0,0 +1,26 @@ +import { DateTime } from 'luxon'; +import { Field } from 'o1js'; +import { IClaim } from 'src/claim'; + +export const schema = { + standardId: 'dateOfBirth', + description: 'Date of birth as stated on provided national id or a passport', + referenceToExternalStandard: + 'The format is described here https://www.w3.org/TR/xmlschema11-2/#dateTime', + fieldsConversion: { + length: 1, + description: + 'Converts the date to unix timestamp (seconds) and then to a single o1js Field.', + codeExample: + '// for example using `luxon.DateTime`\n return new Field(BigInt(cred.dateOfBirth.toUtc().toUnixInteger()));' + } +}; + +export const mkDateOfBirthClaim = (dt: DateTime) : IClaim => { + return { + name: 'dateOfBirth', + value: dt, + fieldsValue: [new Field(dt.toUTC().toUnixInteger())], + standard: schema + }; +} From cbaba55f984a64669c3b93863994f6d4929bdecf Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 30 Mar 2024 15:48:59 +0100 Subject: [PATCH 16/34] Reorganize data types #1 --- .../src/claim.ts | 24 +-- .../src/data/o1js/claim.ts | 164 ++++++++++++++++++ .../src/data/o1js/common.ts | 35 ++++ .../src/data/o1js/ids.ts | 57 ++++++ .../src/data/o1js/vcred.ts | 89 ++++++++++ .../src/data/simple.ts | 105 +---------- .../src/data/transit/common.ts | 63 +++++++ .../src/data/transit/cred.ts | 98 +++++++++++ 8 files changed, 517 insertions(+), 118 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/common.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts index 28935ea..db0bee1 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts @@ -2,28 +2,8 @@ import { CircuitString, Field, Poseidon } from 'o1js'; import { z } from 'zod'; import { ClaimStruct, IClaimStruct } from './data/claims.js'; import { FieldsSchema } from './data/simple.js'; +import { ClaimSchema_, ClaimStandard } from './data/transit-cred.js'; -export const ClaimStandardSchema = z.object({ - standardId: z.string().min(2), - description: z.string(), - referenceToExternalStandard: z.string().optional(), - fieldsConversion: z.object({ - length: z.number().int().min(1), - description: z.string(), - codeExample: z.string() - }) -}); - -export type ClaimStandard = z.infer; - -export function ClaimSchema(valueSchema: z.ZodType) { - return z.object({ - name: z.string().min(1), - value: valueSchema, - fieldsValue: FieldsSchema, - standard: ClaimStandardSchema - }); -} export interface IClaim { get name(): string; @@ -50,7 +30,7 @@ export const claimStandardHash = (standard: ClaimStandard): Field => { // ========================================== // inline tests -const TypeCheckerTestSchema = ClaimSchema(z.number()); +const TypeCheckerTestSchema = ClaimSchema_(z.number()); type TypeCheckerTestType = z.infer; const typeCheckerTestValue = undefined as unknown as TypeCheckerTestType; typeCheckerTestValue satisfies IClaim; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts new file mode 100644 index 0000000..eed1c32 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts @@ -0,0 +1,164 @@ +import { Struct, Provable, Field } from 'o1js'; +import { ZodTypeAny, z } from 'zod'; +import { arraysAreEqual, ftn } from '../../helpers/utils.js'; +import { FieldsSchema } from './common.js'; +import { Claim } from '../transit/cred.js'; + +const CLAIMS_MAX_SIZE = 128; + +export interface IClaimStruct { + get length(): Field; + get claimValue(): Field[]; + toFields(): Field[]; +} + +export function mkClaimStruct(claim: Claim): IClaimStruct; +export function mkClaimStruct(flds: Field[]): IClaimStruct; + +export function mkClaimStruct(claim: Claim | Field[]): IClaimStruct { + if (Array.isArray(claim)) { + return ClaimStruct(claim.length).fromFields(claim); + } else { + return ClaimStruct(claim.fieldsValue.length).fromFields(claim.fieldsValue.map(s => new Field(s))); + } +} + +export interface IClaimStructClass { + new (claimValue: Field[]): IClaimStruct; + fromFields(fields: Field[]): IClaimStruct; + schema: z.ZodType; +} + +export interface IFieldClaims { + count: Field; + packed: Field[]; + toFields(): Field[]; + getClaim(ix: Field, assert: Field[]): Field[]; +} + +export const ClaimStruct = (length: number): IClaimStructClass => { + class Claim_ + extends Struct({ + length: Field, + claimValue: Provable.Array(Field, length) + }) + implements IClaimStruct + { + constructor(claimValue: Field[]) { + if (claimValue.length !== length) { + throw new Error(`Invalid claim array size: ${claimValue.length}`); + } + super({ length: new Field(length), claimValue }); + } + + public toFields() { + return [this.length, ...this.claimValue]; + } + + static fromFields(fields: Field[]) { + const length = Number(fields[0].toBigInt()); + if (fields.length !== length + 1) { + throw new Error(`Invalid claim array size: ${fields.length}`); + } + return new Claim_(fields.slice(1, length + 1)); + } + + static schema = z + .object({ + claimValue: FieldsSchema.length(length) + }) + .transform((o) => new Claim_(o.claimValue)); + } + + return Claim_ as IClaimStructClass; +}; + + +export const computeClaimSizes = (claims: IClaimStruct[]) => { + return claims.map(c => ftn(c.length)); +}; + +export const mkClaims = (claims: IClaimStruct[]): IFieldClaims => { + const size = computeClaimSizes(claims); + return Claims(size).fromClaims(claims); +}; + +export function Claims(claimSizes: number[]) { + if (claimSizes.length == 0) { + throw new Error('claimSizes must not be empty.'); + } + const claimCount = claimSizes.length; + // 0 (start index) + indices + claims + const totalSize = 1 + claimCount + claimSizes.reduce((a, v) => a + v, 0); + + if (totalSize > CLAIMS_MAX_SIZE) { + throw new Error( + `Total Claims size ${totalSize} exceeds the maximum size ${CLAIMS_MAX_SIZE}` + ); + } + + class Claims_ + extends Struct({ + count: Field, + packed: Provable.Array(Field, totalSize) + }) + implements IFieldClaims + { + static MAX_SIZE = CLAIMS_MAX_SIZE; + + public toFields() { + return [this.count, ...this.packed]; + } + + static fromClaims(claims: IClaimStruct[]) { + const receivedSizes = claims.map((c) => ftn(c.length)); + + if (!arraysAreEqual(receivedSizes, claimSizes)) { + throw new Error("'claims' array sizes are invalid"); + } + + let packed: Field[] = []; + // first push all locations + packed.push(new Field(0)); + for (let i = 0; i < claims.length; i++) { + const claimEndIx = packed[i].add(claims[i].length); + packed.push(claimEndIx); + } + // then push all values + for (const claim of claims) { + packed.push(...claim.claimValue); + } + + return new Claims_({ count: new Field(claims.length), packed }); + } + + static get schema() { + const claimSchemas = claimSizes.map( + (size) => ClaimStruct(size).schema + ) as [ZodTypeAny, ...ZodTypeAny[]]; + return z + .tuple(claimSchemas) + .transform((claims) => Claims_.fromClaims(claims)); + } + + public getClaim(ix: Field, assert: Field[]): Field[] { + const i = Number(ix.toBigInt()); + const length = Number(this.packed[i + 1].sub(this.packed[i]).toBigInt()); + const c = Number(this.count.toBigInt()); + + const op = Provable.witness(Provable.Array(Field, length), () => { + const start = Number(this.packed[i].toBigInt()); + const next = Number(this.packed[i + 1].toBigInt()); + return this.packed.slice(c + 1 + start, c + 1 + next); + }); + + for (let j = 0; j < length; j++) { + op[j].assertEquals(assert[j]); + } + + return op; + } + } + + return Claims_; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/common.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/common.ts new file mode 100644 index 0000000..67c6c77 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/common.ts @@ -0,0 +1,35 @@ +import { z } from "zod"; +import { Signature, Field, PublicKey, Struct } from "o1js" +import * as T from "../transit/common.js"; +import { DateTime } from "luxon"; + +export const FieldSchema = T.FieldSchema.transform(Field); + +export const FieldsSchema = z.array(FieldSchema); + +export const PublicKeySchema = T.PublicKeyB58Schema.transform(PublicKey.fromBase58); + +export const SignatureSchema = T.SignatureSchema.transform(Signature.fromBase58); + +export const UnixTimestampFieldSchema = T.DateTimeSchema.transform((dt) => { + const dt2 = dt || ""; + const ts = DateTime.fromISO(dt2) + if (!ts.isValid) { + throw new Error(`Invalid timestamp: ${dt}`) + } + const seconds = ts.toUTC().toUnixInteger(); + + return new Field(seconds); +}) + +export class UnixTimestamp extends Struct({ + unixTimestamp: Field +}) { + static fromTransit(t: unknown) { + const unixTimestamp = UnixTimestampFieldSchema.parse(t); + return new UnixTimestamp({ unixTimestamp }); + } + public toFields() { + return [this.unixTimestamp] + } +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts new file mode 100644 index 0000000..ae2d6f3 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts @@ -0,0 +1,57 @@ +import * as z from 'zod'; +import * as S from './common.js'; +import { Field, PublicKey, Struct } from 'o1js'; +import * as T from '../transit/cred.js'; + +// =============== IDs =============== + +export const PubKeyIdSchema = z.object({ + pubkey: S.PublicKeySchema +}); + +export type PubKeyId = z.infer; + +export const IssuerIdSchema = PubKeyIdSchema; + +export class IssuerId extends Struct({ + pubkey: PublicKey +}) { + static fromTransit(t: T.IssuerId) { + const pubkey = S.PublicKeySchema.parse(t); + return new IssuerId({pubkey}); + } + + public toFields() { + return this.pubkey.toFields(); + } +} + +export const CredSubjectIdSchema = PubKeyIdSchema; + +export class CredSubjectId extends Struct({ + pubkey: PublicKey +}) { + static fromTransit(t: T.CredSubjectId) { + const pubkey = S.PublicKeySchema.parse(t); + return new CredSubjectId({pubkey}); + } + + public toFields() { + return this.pubkey.toFields(); + } +} + +export class VCredId extends Struct({ + id: Field +}) { + static fromTransit(t: T.VCredId) { + const id = S.FieldSchema.parse(t); + return new VCredId({id}); + } + + public toFields() { + return this.id.toFields(); + } +} + + diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts new file mode 100644 index 0000000..515ba04 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -0,0 +1,89 @@ +import { Struct, Field, Signature } from 'o1js'; +import { + SignatureSchema, + FieldSchema, + UnixTimestamp +} from './common.js'; +import { Claims, mkClaimStruct, mkClaims } from './claim.js'; +import { CredSubjectId, IssuerId, VCredId } from './ids.js'; +import { Credential, CredentialData } from '../transit/cred.js'; + +export function VCredStructUnsigned(claimSizes: number[]) { + const ClaimsType = Claims(claimSizes); + + const Data = { + id: VCredId, + issuer: IssuerId, + issuanceDate: UnixTimestamp, + expirationDate: UnixTimestamp, + subject: CredSubjectId, + claims: ClaimsType, + credentialStandardHash: Field + }; + + class BaseVCredStruct_ extends Struct(Data) { + static Fields = Data; + + public toFields(): Field[] { + return [ + ...this.id.toFields(), + ...this.issuer.toFields(), + ...this.issuanceDate.toFields(), + ...this.expirationDate.toFields(), + ...this.subject.toFields(), + ...this.claims.toFields(), + ...this.credentialStandardHash.toFields() + ]; + } + + static fromTransit(t: CredentialData): BaseVCredStruct_ { + const id = VCredId.fromTransit(t.id); + const issuer = IssuerId.fromTransit(t.issuer); + const issuanceDate = UnixTimestamp.fromTransit(t.issuanceDate); + const expirationDate = UnixTimestamp.fromTransit(t.expirationDate); + const subject = CredSubjectId.fromTransit(t.subject); + const claims = mkClaims(Object.values(t.claims).map(mkClaimStruct)); + const credentialStandardHash = FieldSchema.parse(t.credentialStandardHash); + + return new BaseVCredStruct_({ + id, + issuer, + issuanceDate, + expirationDate, + subject, + claims, + credentialStandardHash + }); + } + } + + return BaseVCredStruct_; +} + +export function VCredStruct(claimSizes: number[]) { + const BaseVCredStructType = VCredStructUnsigned(claimSizes); + + const Fields = { ...BaseVCredStructType.Fields, signature: Signature }; + + class VCredStruct_ extends Struct(Fields) { + static Fields = Fields; + + public contentToFields() { + return new BaseVCredStructType(this).toFields(); + } + + public toFields() { + return [...this.contentToFields(), ...this.signature.toFields()]; + } + + static fromTransit(t: Credential): VCredStruct_ { + const base = BaseVCredStructType.fromTransit(t); + const signature = SignatureSchema.parse(t.signature); + + return new VCredStruct_({ ...base, signature }); + } + + } + + return VCredStruct_; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts index ecf55cf..6b3307f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts @@ -6,25 +6,27 @@ const hexViaFieldBigInt = (x: number | bigint | string) => { return '0x' + (new Field(x)).toBigInt().toString(16); } -export const FieldSchemaInt = z.number().int().transform((n) => new Field(BigInt(n))); -export const FieldSchemaBigInt = z.bigint().transform(Field); -export const FieldSchemaDec = z.string().regex(/^\d+$/).transform(Field); +export const FieldSchemaInt = z.number().int().transform(hexViaFieldBigInt); +export const FieldSchemaBigInt = z.bigint().transform(hexViaFieldBigInt); +export const FieldSchemaDec = z.string().regex(/^\d+$/).transform(hexViaFieldBigInt); export const FieldSchemaHex = z .string() .regex(/^(0x|0X)?[0-9a-fA-F]+$/) - .transform((s) => Field(BigInt(s))); + .transform((x) => hexViaFieldBigInt(BigInt(x))); -export const FieldSchema = z.union([FieldSchemaInt, FieldSchemaBigInt, FieldSchemaDec,FieldSchemaHex]); +export const FieldSchema = z.union([FieldSchemaInt, FieldSchemaBigInt, FieldSchemaDec, FieldSchemaHex]); export const FieldsSchema = z.array(FieldSchema); export const Base58Schema = z.string().regex(/^[A-HJ-NP-Za-km-z1-9]+$/); export const PublicKeyB58Schema = Base58Schema.length(55).transform( - PublicKey.fromBase58 + // to ensure o1js.PublicKey parsing + (x) => PublicKey.fromBase58(x).toBase58() ); export const SignatureSchema = z .object({ signatureBase58: Base58Schema.length(96) }) - .transform((o) => Signature.fromBase58(o.signatureBase58)); + // to ensure o1js.Signature parsing + .transform((o) => {return {signatureBase58: Signature.fromBase58(o.signatureBase58).toBase58()}}); export type SignatureB58 = z.infer; @@ -42,92 +44,3 @@ export const UnixTimestampSchema = z }) .transform((o) => new UnixTimestamp({ unixTimestamp: o.unixTimestamp })); - -export const inline_tests = () => { - const log = new Logger({ name: 'simple schema inline tests' }); - - const fieldi = 123; - const f1: Field = FieldSchemaInt.parse(fieldi); - log.info('Parsed field from int encoding: ', fieldi, f1); - - const fieldbigi = 123n; - const f2: Field = FieldSchemaBigInt.parse(fieldbigi); - log.info('Parsed field from big int encoding: ', fieldbigi, f2); - - - // const PublicKeySchema = z.string().transform(PrivateKey.from); - const fielddecstr = '123'; - const field: Field = FieldSchemaDec.parse(fielddecstr); - log.info('Parsed field from dec encoding: ', fielddecstr, field.toString()); - try { - FieldSchemaDec.parse('abc'); - } catch (e) { - const err = e as z.ZodError; - log.debug('Valid error: ', err.message); - } - - const fieldhexstr = '0x123'; - const fieldhex: Field = FieldSchemaHex.parse(fieldhexstr); - log.info( - 'Parsed field from hex encoding: ', - fieldhexstr, - fieldhex.toString() - ); - try { - FieldSchemaHex.parse('0xzbc'); - } catch (e) { - const err = e as z.ZodError; - log.debug('Valid error: ', err.message); - } - - const fieldsencoded = ['123', '0x123']; - const fields: Field[] = FieldsSchema.parse(fieldsencoded); - log.info( - 'Parsed fields from encoded array: ', - fieldsencoded, - fields.map((f) => f.toString()) - ); - - const pubkeystr = 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL'; - const pubkey: PublicKey = PublicKeyB58Schema.parse(pubkeystr); - log.info('Parsed public key from base58: ', pubkeystr, pubkey.toBase58()); - try { - PublicKeyB58Schema.parse('abc'); - } catch (e) { - const err = e as z.ZodError; - log.debug('Valid error: ', err.message); - } - - // tests for unix timestamp - const unixTimestampStr = '123'; - const unixTimestamp: UnixTimestamp = UnixTimestampSchema.parse({ - unixTimestamp: unixTimestampStr - }); - log.info( - 'Parsed unix timestamp from dec encoding: ', - unixTimestampStr, - unixTimestamp.toFields() - ); - try { - UnixTimestampSchema.parse({ unixTimestamp: 'abc' }); - } catch (e) { - const err = e as z.ZodError; - log.debug('Valid error: ', err.message); - } - - const signature = SignatureSchema.parse({ - signature: - '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' - }); - log.info('Parsed signature: ', signature.toBase58()); - - try { - SignatureSchema.parse({ - signature: - 'mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' - }); - } catch (e) { - const err = e as z.ZodError; - log.debug('Valid error: ', err.message); - } -}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts new file mode 100644 index 0000000..6b671c8 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts @@ -0,0 +1,63 @@ +/** + * This file contains the data definitions that are in serialized + * and human-readable form. + */ + +import { DateTime } from 'luxon'; +import { Field, PublicKey, Signature } from 'o1js'; +import { z } from 'zod'; + +// ========= parse field-like values ========= + +// the "output" value is a hexadecimally encoded string +const hexViaFieldBigInt = (x: number | bigint | string) => { + return '0x' + (new Field(x)).toBigInt().toString(16); +} + +export const FieldSchemaInt = z.number().int().transform(hexViaFieldBigInt); +export const FieldSchemaBigInt = z.bigint().transform(hexViaFieldBigInt); +export const FieldSchemaDec = z.string().regex(/^\d+$/).transform(hexViaFieldBigInt); +export const FieldSchemaHex = z + .string() + .regex(/^(0x|0X)?[0-9a-fA-F]+$/) + .transform((x) => hexViaFieldBigInt(BigInt(x))); + +export const FieldSchema = z.union([FieldSchemaInt, FieldSchemaBigInt, FieldSchemaDec, FieldSchemaHex]); +export const FieldsSchema = z.array(FieldSchema); + +// ========= Base58 string schemas ========= + +export const Base58Schema = z.string().regex(/^[A-HJ-NP-Za-km-z1-9]+$/); +export const PublicKeyB58Schema = Base58Schema.length(55).transform( + // to ensure o1js.PublicKey parsing + (x) => PublicKey.fromBase58(x).toBase58() +); +export const SignatureSchema = Base58Schema.length(96) + // to ensure o1js.Signature parsing + .transform((o) => Signature.fromBase58(o).toBase58()); + + +// ========= date and time ========= + +// ISO 8601-compliant datetime string from int +const fromInt = (x: number) => { + if (x < 0) { + throw new Error('Unix timestamp must be positive'); + } + let d: DateTime + if (x > 100000000000) { + // milliseconds since epoch + d = DateTime.fromMillis(x); + } + else { + // seconds since epoch + d = DateTime.fromSeconds(x); + } + return d.toISO(); +} + + +export const JsDateSchema = z.string().datetime({ offset: true }).transform((x) => DateTime.fromJSDate(new Date(x)).toISO()); +export const UnixTimestampSchema = z.number().int().transform(fromInt); + +export const DateTimeSchema = z.union([JsDateSchema, UnixTimestampSchema]); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts new file mode 100644 index 0000000..58341cf --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts @@ -0,0 +1,98 @@ +import z from 'zod'; +import * as S from './common.js'; + +// =============== IDs =============== + +export const PubKeyIdSchema = z.object({ + pubkey: S.PublicKeyB58Schema +}); + +export type PubKeyId = z.infer; + +export const IssuerIdSchema = PubKeyIdSchema; + +export type IssuerId = PubKeyId; + +export const CredSubjectIdSchema = PubKeyIdSchema; + +export type CredSubjectId = PubKeyId; + +export const VCredIdSchema = S.FieldSchema; + +export type VCredId = z.infer; + +// =============== Claim =============== + +export const ClaimStandardSchema = z.object({ + standardId: z.string().min(2), + description: z.string(), + referenceToExternalStandard: z.string().optional(), + fieldsConversion: z.object({ + length: z.number().int().min(1), + description: z.string(), + codeExample: z.string() + }) +}); + +export type ClaimStandard = z.infer; + +export const ClaimSchema = z.object({ + name: z.string().min(1), + value: z.unknown(), + fieldsValue: S.FieldsSchema, + standard: ClaimStandardSchema +}); + +export type Claim = z.infer; + +export function ClaimSchema_(valueSchema: z.ZodType) { + return z.object({ + name: z.string().min(1), + value: valueSchema, + fieldsValue: S.FieldsSchema, + standard: ClaimStandardSchema + }); +} + + +// =============== Credential =============== + +// ---------------- Credential Standard ---------------- + +export const CredentialStandardSchema = z.object({ + standardId: z.string().min(2), + description: z.string().min(2), + schema: z + .record(z.string().min(2), ClaimStandardSchema) + .refine((schema) => Object.keys(schema).length > 0, { + message: 'Must define at least one claim.' + }) +}); + +export type CredentialStandard = z.infer; + +// ---------------- Credential Data ---------------- + +export const CredentialDataSchema = z.object({ + claims: z + .record(z.string().min(1), ClaimSchema) + .refine((claims) => Object.keys(claims).length > 0, { + message: 'Must define at least one claim.' + }), + id: VCredIdSchema, + issuer: IssuerIdSchema, + issuanceDate: S.DateTimeSchema, + expirationDate: S.DateTimeSchema, + subject: CredSubjectIdSchema, + credentialStandardHash: S.FieldSchema +}); + +export type CredentialData = z.infer; + +// ---------------- Credential ---------------- + +export const CredentialSchema = CredentialDataSchema.extend({ + signature: S.SignatureSchema +}); + +export type Credential = z.infer; From 2cfe1c10d63566c4cd25318ea82f50f0f28fc9b4 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 30 Mar 2024 16:35:12 +0100 Subject: [PATCH 17/34] Reorganize data types #2 --- .../src/claim.ts | 26 +-- .../src/credential.ts | 109 +----------- .../src/data/claims.ts | 156 ------------------ .../src/data/ids.ts | 79 --------- .../src/data/{ => o1js}/claims.test.ts | 0 .../src/data/{ => o1js}/vcred.test.ts | 0 .../src/data/o1js/vcred.ts | 50 +++++- .../src/data/simple.ts | 46 ------ .../src/data/vcred.ts | 92 ----------- .../src/index.ts | 22 +-- .../src/issuer.ts | 7 +- .../src/zkclaims/citizenship.ts | 7 +- .../src/zkclaims/dateOfBirth.ts | 9 +- 13 files changed, 70 insertions(+), 533 deletions(-) delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts rename minauth-plugins/minauth-verified-zkdocument-plugin/src/data/{ => o1js}/claims.test.ts (100%) rename minauth-plugins/minauth-verified-zkdocument-plugin/src/data/{ => o1js}/vcred.test.ts (100%) delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts index db0bee1..6134649 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/claim.ts @@ -1,21 +1,5 @@ import { CircuitString, Field, Poseidon } from 'o1js'; -import { z } from 'zod'; -import { ClaimStruct, IClaimStruct } from './data/claims.js'; -import { FieldsSchema } from './data/simple.js'; -import { ClaimSchema_, ClaimStandard } from './data/transit-cred.js'; - - -export interface IClaim { - get name(): string; - get value(): V; - get fieldsValue(): Field[]; - get standard(): ClaimStandard; -} - -export const claimToStruct = (claim: IClaim): IClaimStruct => { - const l = claim.fieldsValue.length; - return ClaimStruct(l).fromFields(claim.fieldsValue); -}; +import { ClaimStandard } from './data/transit/cred'; export const claimStandardHash = (standard: ClaimStandard): Field => { const idHash = Poseidon.hash( @@ -26,11 +10,3 @@ export const claimStandardHash = (standard: ClaimStandard): Field => { ]); return Poseidon.hash([idHash, optsHash]); }; - -// ========================================== -// inline tests - -const TypeCheckerTestSchema = ClaimSchema_(z.number()); -type TypeCheckerTestType = z.infer; -const typeCheckerTestValue = undefined as unknown as TypeCheckerTestType; -typeCheckerTestValue satisfies IClaim; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts index c346aa3..d88bd00 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -1,98 +1,15 @@ import { CircuitString, Field, Poseidon, PrivateKey } from 'o1js'; import * as o1js from 'o1js'; -import { z } from 'zod'; -import { - ClaimSchema, - ClaimStandardSchema, - IClaim, - claimStandardHash -} from './claim.js'; -import { - CredSubjectId, - CredSubjectIdSchema, - IssuerIdSchema, - VCredIdSchema -} from './data/ids.js'; -import { - FieldSchema, - SignatureB58, - SignatureSchema, - UnixTimestampSchema -} from './data/simple.js'; import { arraysAreEqual } from './helpers/utils.js'; -import { Issuer } from './issuer.js'; -import { VCredStruct, VCredStructUnsigned } from './data/vcred.js'; import { Logger } from 'tslog'; +import { CredSubjectId, Credential, CredentialData, CredentialSchema, CredentialStandard } from './data/transit/cred.js'; +import { claimStandardHash } from './claim.js'; +import { mkVCredStruct } from './data/o1js/vcred.js'; +import { SignatureSchema } from './data/transit/common.js'; +import { Issuer } from './issuer.js'; const log = new Logger({ name: 'credential.ts' }); -// =============== Credential Trasit Types ================== - -// ---------------- Credential Standard ---------------- - -export const CredentialStandardSchema = z.object({ - standardId: z.string().min(2), - description: z.string().min(2), - schema: z - .record(z.string().min(2), ClaimStandardSchema) - .refine((schema) => Object.keys(schema).length > 0, { - message: 'Must define at least one claim.' - }) -}); - -export type CredentialStandard = z.infer; - -// ---------------- Credential Data ---------------- - -export const CredentialDataSchema = z.object({ - claims: z - .record(z.string().min(1), ClaimSchema(z.unknown())) - .refine((claims) => Object.keys(claims).length > 0, { - message: 'Must define at least one claim.' - }), - id: VCredIdSchema, - issuer: IssuerIdSchema, - issuanceDate: UnixTimestampSchema, - expirationDate: UnixTimestampSchema, - subject: CredSubjectIdSchema, - credentialStandardHash: FieldSchema -}); - -export type CredentialData = z.infer; - -// ---------------- Credential ---------------- - -export const CredentialSchema = CredentialDataSchema.extend({ - signature: SignatureSchema -}); - -export type Credential = z.infer; - -// =============== To fields-encoded types =============== - -export const mkStructCredentialUnsigned = (credential: CredentialData) => { - log.debug('Entering mkStructCredentialUnsigned...', credential); - return VCredStructUnsigned( - Object.values(credential.claims).map((claim) => claim.fieldsValue.length) - ).schema.parse({ - ...credential, - claims: Object.values(credential.claims).map((claim) => ({ - claimValue: claim.fieldsValue - })) - }); -}; - -// signed version -export const mkStructCredential = (credential: Credential) => { - return VCredStruct( - Object.values(credential.claims).map((claim) => claim.fieldsValue.length) - ).schema.parse({ - ...credential, - claims: Object.values(credential.claims).map((claim) => ({ - claimValue: claim.fieldsValue - })) - }); -}; export const checkCredentialStandardConformance = ( credential: Credential, @@ -139,10 +56,10 @@ export const verifyAndIssueCredential = log.debug('Entering verifyAndIssueCredential...'); log.debug('Converting the credential data to o1js fields.'); - const flds = mkStructCredentialUnsigned(credentialData).toFields(); + const flds = mkVCredStruct(credentialData).toFields(); log.debug('Creating signature for the fields data'); - const signature: SignatureB58 = SignatureSchema.parse( + const signature = SignatureSchema.parse( o1js.Signature.create(privateKey, flds).toBase58() ); @@ -163,12 +80,12 @@ export const verifyAndIssueCredential = // additional assertions // issuer pubkey matches the private key - if (!issuer.pubkey.equals(privateKey.toPublicKey())) { + if (issuer.pubkey !== privateKey.toPublicKey().toBase58()) { throw new Error('Issuer pubkey does not match the private key'); } // credential subject public key matches the given subject public key - if (!credential.subject.pubkey.equals(subject.pubkey)) { + if (credential.subject.pubkey !== subject.pubkey) { throw new Error('Subject does not match the credential subject'); } @@ -176,11 +93,3 @@ export const verifyAndIssueCredential = credential }; }; - -// ========================================== -// inline tests - -const TypeCheckerTestSchema = ClaimSchema(z.number()); -type TypeCheckerTestType = z.infer; -const typeCheckerTestValue = undefined as unknown as TypeCheckerTestType; -typeCheckerTestValue satisfies IClaim; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts deleted file mode 100644 index 3e1157a..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { Struct, Provable, Field } from 'o1js'; -import { ZodTypeAny, z } from 'zod'; -import { FieldsSchema } from './simple.js'; -import { arraysAreEqual, ftn } from '../helpers/utils.js'; - -const CLAIMS_MAX_SIZE = 128; - -export interface IClaimStruct { - get length(): Field; - get claimValue(): Field[]; - toFields(): Field[]; -} - -export interface IClaimStructClass { - new (claimValue: Field[]): IClaimStruct; - fromFields(fields: Field[]): IClaimStruct; - schema: z.ZodType; -} - -export interface IFieldClaims { - count: Field; - packed: Field[]; - toFields(): Field[]; - getClaim(ix: Field, assert: Field[]): Field[]; -} - -export const ClaimStruct = (length: number): IClaimStructClass => { - class Claim_ - extends Struct({ - length: Field, - claimValue: Provable.Array(Field, length) - }) - implements IClaimStruct - { - constructor(claimValue: Field[]) { - if (claimValue.length !== length) { - throw new Error(`Invalid claim array size: ${claimValue.length}`); - } - super({ length: new Field(length), claimValue }); - } - - public toFields() { - return [this.length, ...this.claimValue]; - } - - static fromFields(fields: Field[]) { - const length = Number(fields[0].toBigInt()); - if (fields.length !== length + 1) { - throw new Error(`Invalid claim array size: ${fields.length}`); - } - return new Claim_(fields.slice(1, length + 1)); - } - - static schema = z - .object({ - claimValue: FieldsSchema.length(length) - }) - .transform((o) => new Claim_(o.claimValue)); - } - - return Claim_ as IClaimStructClass; -}; - -export const mkClaimStruct = (flds: Field[]) => { - const n = flds.length; - return ClaimStruct(n).fromFields(flds); -}; - -export const computeClaimSizes = (claims: IClaimStruct[]) => { - return claims.map(c => ftn(c.length)); -}; - -export const mkClaims = (claims: IClaimStruct[]): IFieldClaims => { - const size = computeClaimSizes(claims); - return Claims(size).fromClaims(claims); -}; - -export function Claims(claimSizes: number[]) { - if (claimSizes.length == 0) { - throw new Error('claimSizes must not be empty.'); - } - const claimCount = claimSizes.length; - // 0 (start index) + indices + claims - const totalSize = 1 + claimCount + claimSizes.reduce((a, v) => a + v, 0); - - if (totalSize > CLAIMS_MAX_SIZE) { - throw new Error( - `Total Claims size ${totalSize} exceeds the maximum size ${CLAIMS_MAX_SIZE}` - ); - } - - class Claims_ - extends Struct({ - count: Field, - packed: Provable.Array(Field, totalSize) - }) - implements IFieldClaims - { - static MAX_SIZE = CLAIMS_MAX_SIZE; - - public toFields() { - return [this.count, ...this.packed]; - } - - static fromClaims(claims: IClaimStruct[]) { - const receivedSizes = claims.map((c) => ftn(c.length)); - - if (!arraysAreEqual(receivedSizes, claimSizes)) { - throw new Error("'claims' array sizes are invalid"); - } - - let packed: Field[] = []; - // first push all locations - packed.push(new Field(0)); - for (let i = 0; i < claims.length; i++) { - const claimEndIx = packed[i].add(claims[i].length); - packed.push(claimEndIx); - } - // then push all values - for (const claim of claims) { - packed.push(...claim.claimValue); - } - - return new Claims_({ count: new Field(claims.length), packed }); - } - - static get schema() { - const claimSchemas = claimSizes.map( - (size) => ClaimStruct(size).schema - ) as [ZodTypeAny, ...ZodTypeAny[]]; - return z - .tuple(claimSchemas) - .transform((claims) => Claims_.fromClaims(claims)); - } - - public getClaim(ix: Field, assert: Field[]): Field[] { - const i = Number(ix.toBigInt()); - const length = Number(this.packed[i + 1].sub(this.packed[i]).toBigInt()); - const c = Number(this.count.toBigInt()); - - const op = Provable.witness(Provable.Array(Field, length), () => { - const start = Number(this.packed[i].toBigInt()); - const next = Number(this.packed[i + 1].toBigInt()); - return this.packed.slice(c + 1 + start, c + 1 + next); - }); - - for (let j = 0; j < length; j++) { - op[j].assertEquals(assert[j]); - } - - return op; - } - } - - return Claims_; -} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts deleted file mode 100644 index 9ffa12b..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/ids.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { - Field, - PublicKey, - Struct, -} from 'o1js'; -import { Logger } from 'tslog'; -import { z } from 'zod'; -import * as SimpleSchemas from './simple.js'; - -export class PubKeyId extends Struct({ - pubkey: PublicKey -}) { - public toFields() { - return this.pubkey.toFields(); - } -} -export const PubKeyIdSchema = z - .object({ - pubkey: SimpleSchemas.PublicKeyB58Schema - }) - .transform((o) => new IssuerId({ pubkey: o.pubkey })); - -/** - * Represents an issuer with a public key. Future versions might replace this - * with a more complex ID system, such as DIDs. - */ -export class IssuerId extends PubKeyId {} - -export const IssuerIdSchema = PubKeyIdSchema; - - -/** - * Represents a subject with a public key. Future versions might replace this - * with a more complex ID system, such as DIDs. - */ -export class CredSubjectId extends PubKeyId {} - -export const CredSubjectIdSchema = PubKeyIdSchema; - - -export class VCredId extends Struct({ - id: Field -}) { - public toFields() { - return this.id.toFields(); - } -} - -export const VCredIdSchema = z - .object({ - id: z.union([SimpleSchemas.FieldSchemaDec, SimpleSchemas.FieldSchemaHex]) - }) - .transform((o) => new VCredId({ id: o.id })); - -export const inline_tests = () => { - const log = new Logger({ name: 'simple schema inline tests' }); - - const issuer = IssuerIdSchema.parse({ - pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' - }); - log.info('Parsed issuer: ', issuer.toFields()); - - try { - IssuerIdSchema.parse({ pubkey: 'abc' }); - } catch (e) { - const err = e as z.ZodError; - log.debug('Caught error: ', err.message); - } - - const vcredid = VCredIdSchema.parse({ id: '123' }); - log.info('Parsed vcredid: ', vcredid.toFields()); - - try { - VCredIdSchema.parse({ id: 'abc' }); - } catch (e) { - const err = e as z.ZodError; - log.debug('Caught error: ', err.message); - } -}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts similarity index 100% rename from minauth-plugins/minauth-verified-zkdocument-plugin/src/data/claims.test.ts rename to minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts similarity index 100% rename from minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.test.ts rename to minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index 515ba04..41db56d 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -1,13 +1,26 @@ import { Struct, Field, Signature } from 'o1js'; +import { SignatureSchema, FieldSchema, UnixTimestamp } from './common.js'; import { - SignatureSchema, - FieldSchema, - UnixTimestamp -} from './common.js'; -import { Claims, mkClaimStruct, mkClaims } from './claim.js'; + Claims, + IFieldClaims, + mkClaimStruct, + mkClaims +} from './claim.js'; import { CredSubjectId, IssuerId, VCredId } from './ids.js'; import { Credential, CredentialData } from '../transit/cred.js'; +export interface IVCredStruct { + id: VCredId; + issuer: IssuerId; + issuanceDate: UnixTimestamp; + expirationDate: UnixTimestamp; + subject: CredSubjectId; + claims: IFieldClaims; + credentialStandardHash: Field; + toFields(): Field[]; + signature?: Signature; +} + export function VCredStructUnsigned(claimSizes: number[]) { const ClaimsType = Claims(claimSizes); @@ -21,7 +34,7 @@ export function VCredStructUnsigned(claimSizes: number[]) { credentialStandardHash: Field }; - class BaseVCredStruct_ extends Struct(Data) { + class BaseVCredStruct_ extends Struct(Data) implements IVCredStruct { static Fields = Data; public toFields(): Field[] { @@ -43,7 +56,9 @@ export function VCredStructUnsigned(claimSizes: number[]) { const expirationDate = UnixTimestamp.fromTransit(t.expirationDate); const subject = CredSubjectId.fromTransit(t.subject); const claims = mkClaims(Object.values(t.claims).map(mkClaimStruct)); - const credentialStandardHash = FieldSchema.parse(t.credentialStandardHash); + const credentialStandardHash = FieldSchema.parse( + t.credentialStandardHash + ); return new BaseVCredStruct_({ id, @@ -65,7 +80,7 @@ export function VCredStruct(claimSizes: number[]) { const Fields = { ...BaseVCredStructType.Fields, signature: Signature }; - class VCredStruct_ extends Struct(Fields) { + class VCredStruct_ extends Struct(Fields) implements IVCredStruct { static Fields = Fields; public contentToFields() { @@ -82,8 +97,25 @@ export function VCredStruct(claimSizes: number[]) { return new VCredStruct_({ ...base, signature }); } - } return VCredStruct_; } + +export function mkVCredStruct(credentialData: CredentialData): IVCredStruct; +export function mkVCredStruct(credential: Credential): IVCredStruct; + +export function mkVCredStruct(credential: Credential | CredentialData): IVCredStruct { + // credential has a signature as opposed to credentialData + const claims = credential.claims; + + const claimSizes = Object.values(claims).map( + (claim) => claim.fieldsValue.length + ); + + if ('signature' in credential) { + return VCredStruct(claimSizes).fromTransit(credential); + } else { + return VCredStructUnsigned(claimSizes).fromTransit(credential); + } +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts deleted file mode 100644 index 6b3307f..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/simple.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Field, PublicKey, Struct, Signature } from 'o1js'; -import { Logger } from 'tslog'; -import { z } from 'zod'; - -const hexViaFieldBigInt = (x: number | bigint | string) => { - return '0x' + (new Field(x)).toBigInt().toString(16); -} - -export const FieldSchemaInt = z.number().int().transform(hexViaFieldBigInt); -export const FieldSchemaBigInt = z.bigint().transform(hexViaFieldBigInt); -export const FieldSchemaDec = z.string().regex(/^\d+$/).transform(hexViaFieldBigInt); -export const FieldSchemaHex = z - .string() - .regex(/^(0x|0X)?[0-9a-fA-F]+$/) - .transform((x) => hexViaFieldBigInt(BigInt(x))); - -export const FieldSchema = z.union([FieldSchemaInt, FieldSchemaBigInt, FieldSchemaDec, FieldSchemaHex]); -export const FieldsSchema = z.array(FieldSchema); -export const Base58Schema = z.string().regex(/^[A-HJ-NP-Za-km-z1-9]+$/); -export const PublicKeyB58Schema = Base58Schema.length(55).transform( - // to ensure o1js.PublicKey parsing - (x) => PublicKey.fromBase58(x).toBase58() -); -export const SignatureSchema = z - .object({ - signatureBase58: Base58Schema.length(96) - }) - // to ensure o1js.Signature parsing - .transform((o) => {return {signatureBase58: Signature.fromBase58(o.signatureBase58).toBase58()}}); - -export type SignatureB58 = z.infer; - -export class UnixTimestamp extends Struct({ - unixTimestamp: Field -}) { - public toFields() { - return this.unixTimestamp.toFields(); - } -} - -export const UnixTimestampSchema = z - .object({ - unixTimestamp: FieldSchemaDec.or(FieldSchemaInt).or(FieldSchemaBigInt) - }) - .transform((o) => new UnixTimestamp({ unixTimestamp: o.unixTimestamp })); - diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts deleted file mode 100644 index 57c92de..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/vcred.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Struct, Field, Signature } from 'o1js'; -import { - UnixTimestamp, - UnixTimestampSchema, - SignatureSchema, - FieldSchema -} from './simple.js'; -import { IssuerId, VCredId, VCredIdSchema, IssuerIdSchema, CredSubjectId, CredSubjectIdSchema } from './ids.js'; -import { Claims } from './claims.js'; -import { z } from 'zod'; - -export function VCredStructUnsigned(claimSizes: number[]) { - const ClaimsType = Claims(claimSizes); - - const Data = { - id: VCredId, - issuer: IssuerId, - issuanceDate: UnixTimestamp, - expirationDate: UnixTimestamp, - subject: CredSubjectId, - claims: ClaimsType, - credentialStandardHash: Field - }; - - class BaseVCredStruct_ extends Struct(Data) { - static Fields = Data; - - public toFields(): Field[] { - return [ - ...this.id.toFields(), - ...this.issuer.toFields(), - ...this.issuanceDate.toFields(), - ...this.expirationDate.toFields(), - ...this.subject.toFields(), - ...this.claims.toFields(), - ...this.credentialStandardHash.toFields() - ]; - } - - static get dataSchema() { - return z.object({ - id: VCredIdSchema, - issuer: IssuerIdSchema, - issuanceDate: UnixTimestampSchema, - expirationDate: UnixTimestampSchema, - subject: CredSubjectIdSchema, - claims: ClaimsType.schema, - credentialStandardHash: FieldSchema - }); - } - - static get schema() { - return BaseVCredStruct_.dataSchema.transform( - (data) => new BaseVCredStruct_(data) - ); - } - } - - return BaseVCredStruct_; -} - -export function VCredStruct(claimSizes: number[]) { - const BaseVCredStructType = VCredStructUnsigned(claimSizes); - - const Fields = { ...BaseVCredStructType.Fields, signature: Signature }; - - class VCredStruct_ extends Struct(Fields) { - static Fields = Fields; - - public contentToFields() { - return new BaseVCredStructType(this).toFields(); - } - - public toFields() { - return [...this.contentToFields(), ...this.signature.toFields()]; - } - - static get dataSchema() { - return BaseVCredStructType.dataSchema.extend({ - signature: SignatureSchema - }); - } - - static get schema() { - return VCredStruct_.dataSchema.transform( - (data) => new VCredStruct_(data) - ); - } - } - - return VCredStruct_; -} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 8835053..9cf012f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,12 +1,12 @@ import { Logger } from 'tslog'; -import { Credential, CredentialData, CredentialDataSchema, CredentialStandard, credentialStandardHash, verifyAndIssueCredential } from './credential.js'; -import { CircuitString, Field, PrivateKey } from 'o1js'; -import { CredSubjectId, CredSubjectIdSchema, IssuerIdSchema, VCredIdSchema } from './data/ids.js'; +import { PrivateKey } from 'o1js'; import { Issuer, IssuerSchema } from './issuer.js'; import * as DateOfBirth from './zkclaims/dateOfBirth.js'; import * as Citizenship from './zkclaims/citizenship.js'; import { DateTime } from 'luxon'; -import { UnixTimestampSchema } from './data/simple.js'; +import { DateTimeSchema, FieldSchema } from './data/transit/common.js'; +import { CredSubjectId, CredSubjectIdSchema, CredentialData, CredentialStandard, VCredIdSchema } from './data/transit/cred.js'; +import { credentialStandardHash, verifyAndIssueCredential } from './credential.js'; const log = new Logger({ name: 'index.ts prototyping' }); @@ -65,20 +65,16 @@ log.info('1. Create credential'); const mkCredentialData = () => { // throw new Error('Not implemented'); const data: CredentialData = { - id: VCredIdSchema.parse({id: "123"}), - subject, + id: VCredIdSchema.parse("1"), + subject: CredSubjectIdSchema.parse(subject), issuer: issuer.id, claims: { dateOfBirth: DateOfBirth.mkDateOfBirthClaim(DateTime.now()), citizenship: Citizenship.mkCitizenshipClaim("USA") }, - issuanceDate: UnixTimestampSchema.parse({ - unixTimestamp: DateTime.now().toUTC().toUnixInteger() - }), - expirationDate: UnixTimestampSchema.parse({ - unixTimestamp: DateTime.now().plus({years: 1}).toUTC().toUnixInteger() - }), - credentialStandardHash: credentialStandardHash(KnownUserCredential) + issuanceDate: DateTimeSchema.parse(DateTime.now().toISO()), + expirationDate: DateTimeSchema.parse(DateTime.now().plus({years: 1}).toISO()), + credentialStandardHash: FieldSchema.parse(credentialStandardHash(KnownUserCredential).toString()) } return data; }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts index e940a6d..02dc571 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { IssuerId, IssuerIdSchema } from './data/ids.js'; +import { IssuerId, IssuerIdSchema } from './data/transit/cred'; interface IssuerProps { id: IssuerId; @@ -22,11 +22,6 @@ export const IssuerSchema = z.object({ }).transform((d) => new Issuer(d)); - - - - - // type-checker level assertion to keep the schema and the interface in sync type IssuerData = z.infer; const issuerData = undefined as unknown as IssuerData; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts index 7fa4576..af13c42 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts @@ -1,5 +1,6 @@ import { CircuitString } from 'o1js'; -import { IClaim } from 'src/claim'; +import { FieldSchema } from 'src/data/transit/common'; +import { Claim } from 'src/data/transit/cred'; const CODE_LENGTH = 3; @@ -17,7 +18,7 @@ export const schema = { } }; -export const mkCitizenshipClaim = (name: string): IClaim => { +export const mkCitizenshipClaim = (name: string): Claim => { const code = nameToCode.get(name); // if the name is not a valid country name, return an error @@ -28,7 +29,7 @@ export const mkCitizenshipClaim = (name: string): IClaim => { return { name: 'citizenship', value: code, - fieldsValue: CircuitString.fromString(code).toFields().slice(0, CODE_LENGTH), + fieldsValue: CircuitString.fromString(code).toFields().slice(0, CODE_LENGTH).map((x) => FieldSchema.parse(x.toString())), standard: schema }; }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts index b6e151b..6c26f84 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts @@ -1,6 +1,7 @@ import { DateTime } from 'luxon'; import { Field } from 'o1js'; -import { IClaim } from 'src/claim'; +import { FieldSchema } from 'src/data/transit/common'; +import { Claim } from 'src/data/transit/cred'; export const schema = { standardId: 'dateOfBirth', @@ -16,11 +17,11 @@ export const schema = { } }; -export const mkDateOfBirthClaim = (dt: DateTime) : IClaim => { +export const mkDateOfBirthClaim = (dt: DateTime) : Claim => { return { name: 'dateOfBirth', - value: dt, - fieldsValue: [new Field(dt.toUTC().toUnixInteger())], + value: dt.toISO(), + fieldsValue: [ FieldSchema.parse((new Field(dt.toUTC().toUnixInteger())).toString())], standard: schema }; } From 85968cf4909d9154b87f3ecb89dd052d997dc761 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sun, 31 Mar 2024 17:14:11 +0200 Subject: [PATCH 18/34] Fix tests. --- .../src/data/o1js/claim.ts | 41 ++-- .../src/data/o1js/claims.test.ts | 2 +- .../src/data/o1js/ids.ts | 8 +- .../src/data/o1js/vcred.test.ts | 108 ++++++--- .../src/data/o1js/vcred.ts | 6 + .../src/data/transit/common.ts | 2 +- .../transit/cred.test.ts} | 227 +++++++++--------- 7 files changed, 209 insertions(+), 185 deletions(-) rename minauth-plugins/minauth-verified-zkdocument-plugin/src/{credential.test.ts => data/transit/cred.test.ts} (66%) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts index eed1c32..d8bee18 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts @@ -1,5 +1,4 @@ import { Struct, Provable, Field } from 'o1js'; -import { ZodTypeAny, z } from 'zod'; import { arraysAreEqual, ftn } from '../../helpers/utils.js'; import { FieldsSchema } from './common.js'; import { Claim } from '../transit/cred.js'; @@ -26,7 +25,6 @@ export function mkClaimStruct(claim: Claim | Field[]): IClaimStruct { export interface IClaimStructClass { new (claimValue: Field[]): IClaimStruct; fromFields(fields: Field[]): IClaimStruct; - schema: z.ZodType; } export interface IFieldClaims { @@ -56,18 +54,13 @@ export const ClaimStruct = (length: number): IClaimStructClass => { } static fromFields(fields: Field[]) { - const length = Number(fields[0].toBigInt()); - if (fields.length !== length + 1) { - throw new Error(`Invalid claim array size: ${fields.length}`); - } - return new Claim_(fields.slice(1, length + 1)); + return new Claim_(fields); + } + + static fromTransit(t: Claim) { + return new Claim_(FieldsSchema.parse(t.fieldsValue)); } - static schema = z - .object({ - claimValue: FieldsSchema.length(length) - }) - .transform((o) => new Claim_(o.claimValue)); } return Claim_ as IClaimStructClass; @@ -83,6 +76,7 @@ export const mkClaims = (claims: IClaimStruct[]): IFieldClaims => { return Claims(size).fromClaims(claims); }; + export function Claims(claimSizes: number[]) { if (claimSizes.length == 0) { throw new Error('claimSizes must not be empty.'); @@ -110,6 +104,15 @@ export function Claims(claimSizes: number[]) { return [this.count, ...this.packed]; } + static fromTransit(claims: Claim[]) { + const receivedSizes = claims.map((c) => (c.fieldsValue.length)); + + if (!arraysAreEqual(receivedSizes, claimSizes)) { + throw new Error("'claims' array sizes are invalid"); + } + return Claims(receivedSizes).fromClaims(claims.map(mkClaimStruct)); + } + static fromClaims(claims: IClaimStruct[]) { const receivedSizes = claims.map((c) => ftn(c.length)); @@ -132,15 +135,6 @@ export function Claims(claimSizes: number[]) { return new Claims_({ count: new Field(claims.length), packed }); } - static get schema() { - const claimSchemas = claimSizes.map( - (size) => ClaimStruct(size).schema - ) as [ZodTypeAny, ...ZodTypeAny[]]; - return z - .tuple(claimSchemas) - .transform((claims) => Claims_.fromClaims(claims)); - } - public getClaim(ix: Field, assert: Field[]): Field[] { const i = Number(ix.toBigInt()); const length = Number(this.packed[i + 1].sub(this.packed[i]).toBigInt()); @@ -162,3 +156,8 @@ export function Claims(claimSizes: number[]) { return Claims_; } + +export function mkClaimStructs(claims: Claim[]): IFieldClaims { + const claimSizes = claims.map((c) => c.fieldsValue.length); + return Claims(claimSizes).fromTransit(claims); +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts index 4922b54..625316b 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts @@ -1,5 +1,5 @@ import { Field } from "o1js"; -import { ClaimStruct, mkClaims } from "./claims.js"; +import { ClaimStruct, mkClaims } from "./claim.js"; describe('ClaimStruct', () => { it('should create a claim with the correct length and values', () => { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts index ae2d6f3..65ff272 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/ids.ts @@ -17,8 +17,8 @@ export class IssuerId extends Struct({ pubkey: PublicKey }) { static fromTransit(t: T.IssuerId) { - const pubkey = S.PublicKeySchema.parse(t); - return new IssuerId({pubkey}); + const pubkey = PubKeyIdSchema.parse(t); + return new IssuerId(pubkey); } public toFields() { @@ -32,8 +32,8 @@ export class CredSubjectId extends Struct({ pubkey: PublicKey }) { static fromTransit(t: T.CredSubjectId) { - const pubkey = S.PublicKeySchema.parse(t); - return new CredSubjectId({pubkey}); + const pubkey = PubKeyIdSchema.parse(t); + return new CredSubjectId(pubkey); } public toFields() { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts index 98924ef..3815cb2 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts @@ -1,8 +1,9 @@ import { Field, PrivateKey, Signature } from 'o1js'; -import { VCredStruct, VCredStructUnsigned } from './vcred.js'; // Update import path as needed -import { ClaimStruct, IClaimStruct, mkClaims } from './claims.js'; // Import necessary dependencies +import { IVCredStruct, VCredStruct, VCredStructUnsigned, mkVCredStruct } from './vcred.js'; // Update import path as needed +import { IClaimStruct, mkClaimStruct, mkClaims } from './claim.js'; // Import necessary dependencies import { CredSubjectId, IssuerId, VCredId } from './ids.js'; -import { UnixTimestamp } from './simple.js'; +import { UnixTimestamp } from './common.js'; +import { Claim, Credential, CredentialData, CredentialStandard } from '../transit/cred.js'; describe('VCredStruct tests', () => { const pk1 = PrivateKey.random().toPublicKey(); @@ -10,19 +11,51 @@ describe('VCredStruct tests', () => { const pk2 = PrivateKey.random().toPublicKey(); const pk2s = pk2.toBase58(); - let claim1: IClaimStruct; - let claim2: IClaimStruct; - - const claim1s = { - claimValue: [1, 2, 3] + // dummy standard + const DummyStandard: CredentialStandard = { + standardId: 'dummy', + description: 'Dummy standard', + schema: { + claim1: { + standardId: 'dummy', + description: 'Dummy claim 1', + fieldsConversion: { + length: 1, + description: 'Dummy claim 1', + codeExample: '' + } + }, + claim2:{ + standardId: 'dummy', + description: 'Dummy claim 2', + fieldsConversion: { + length: 2, + description: 'Dummy claim 2', + codeExample: '' + } + } + } + }; + const claim1s: Claim = { + name: 'claim1', + value: '0x123', + fieldsValue: ["0x123"], + standard: DummyStandard.schema.claim1 }; const claim2s = { - claimValue: ['0x456', 0x789] + name: 'claim2', + value: '0x456,0x789', + fieldsValue: ["0x456", "0x789"], + standard: DummyStandard.schema.claim2 }; + let claim1: IClaimStruct; + let claim2: IClaimStruct; + + beforeAll(() => { - claim1 = ClaimStruct(3).schema.parse(claim1s); - claim2 = ClaimStruct(2).schema.parse(claim2s); + claim1 = mkClaimStruct(claim1s); + claim2 = mkClaimStruct(claim2s); }); const ClaimSizes = [3, 2]; @@ -33,9 +66,9 @@ describe('VCredStruct tests', () => { return { id: new VCredId({ id: new Field(123) }), issuer: new IssuerId({ pubkey: pk1 }), - issuanceDate: new UnixTimestamp({ unixTimestamp: new Field(123123123) }), + issuanceDate: new UnixTimestamp({ unixTimestamp: new Field(1711897450) }), expirationDate: new UnixTimestamp({ - unixTimestamp: new Field(223123123) + unixTimestamp: new Field(1721897450) }), subject: new CredSubjectId({ pubkey: pk2 }), claims: mkClaims([claim1, claim2]), @@ -52,23 +85,21 @@ describe('VCredStruct tests', () => { ); }); - it('should parse from valid data with its zod schema', () => { - expect(VCredStructUnsignedType.dataSchema).toBeDefined(); - const validation = VCredStructUnsignedType.dataSchema.safeParse({ - id: { id: '123' }, + it('should parse from credential data transit type', () => { + const data: CredentialData = { + id: '123', issuer: { pubkey: pk1s }, - issuanceDate: { unixTimestamp: '123123123' }, - expirationDate: { unixTimestamp: '223123123' }, + issuanceDate: '1711897450', + expirationDate: '1721897450', subject: { pubkey: pk2s }, - claims: [claim1s, claim2s], + claims: { + claim1: claim1s, + claim2: claim2s + }, credentialStandardHash: '789' - }); - - if (!validation.success) { - console.log(validation.error); } - - expect(validation.success).toBeTruthy(); + const res: IVCredStruct = mkVCredStruct(data) + expect(res).toBeDefined(); }); }); @@ -99,22 +130,21 @@ describe('VCredStruct tests', () => { }); it('should have a valid schema including signature', () => { - expect(VCredStructType.dataSchema).toBeDefined(); - const validation = VCredStructType.schema.safeParse({ - id: { id: '123' }, + const cred: Credential = { + id: '123', issuer: { pubkey: pk1s }, - issuanceDate: { unixTimestamp: '123123123' }, - expirationDate: { unixTimestamp: '223123123' }, + issuanceDate: '1711897450', + expirationDate: '1721897450', subject: { pubkey: pk2s }, - claims: [claim1s, claim2s], + claims: { + claim1: claim1s, + claim2: claim2s + }, credentialStandardHash: '789', - signature: {signatureBase58: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE'} - }); - if(!validation.success){ - console.log(validation.error); - } - - expect(validation.success).toBeTruthy(); + signature: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' + }; + const res: IVCredStruct = mkVCredStruct(cred) + expect(res).toBeDefined(); }); }); }); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index 41db56d..ee87da2 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -8,6 +8,9 @@ import { } from './claim.js'; import { CredSubjectId, IssuerId, VCredId } from './ids.js'; import { Credential, CredentialData } from '../transit/cred.js'; +import { ILogObj, Logger } from 'tslog'; + +const log = new Logger({name: 'data/o1js/vcred'}); export interface IVCredStruct { id: VCredId; @@ -107,11 +110,14 @@ export function mkVCredStruct(credential: Credential): IVCredStruct; export function mkVCredStruct(credential: Credential | CredentialData): IVCredStruct { // credential has a signature as opposed to credentialData + log.debug("Creating VCredStruct from credential transit data.") + log.debug('credential', credential); const claims = credential.claims; const claimSizes = Object.values(claims).map( (claim) => claim.fieldsValue.length ); + log.debug('claimSizes', claimSizes); if ('signature' in credential) { return VCredStruct(claimSizes).fromTransit(credential); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts index 6b671c8..425779e 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts @@ -58,6 +58,6 @@ const fromInt = (x: number) => { export const JsDateSchema = z.string().datetime({ offset: true }).transform((x) => DateTime.fromJSDate(new Date(x)).toISO()); -export const UnixTimestampSchema = z.number().int().transform(fromInt); +export const UnixTimestampSchema = z.coerce.number().int().transform(fromInt); export const DateTimeSchema = z.union([JsDateSchema, UnixTimestampSchema]); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts similarity index 66% rename from minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts rename to minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts index dc2c5a1..ba53c6a 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts @@ -1,11 +1,5 @@ -import { Field } from 'o1js'; -import { - CredentialStandardSchema, - CredentialStandard, - CredentialSchema, - checkCredentialStandardConformance, - CredentialDataSchema -} from './credential.js'; +// import { Field } from 'o1js'; +import { CredentialDataSchema, CredentialSchema, CredentialStandard, CredentialStandardSchema } from './cred.js'; describe('Credential creation and validation tests', () => { let KnownUserCredential: CredentialStandard; @@ -26,10 +20,10 @@ describe('Credential creation and validation tests', () => { standard: typeof KnownUserCredential.schema.citizenship; }; }; - id: { id: string }; + id: string; issuer: { pubkey: string }; - issuanceDate: { unixTimestamp: number }; - expirationDate: { unixTimestamp: number }; + issuanceDate: number; + expirationDate: number; subject: { pubkey: string }; credentialStandardHash: string; }; @@ -49,19 +43,17 @@ describe('Credential creation and validation tests', () => { standard: typeof KnownUserCredential.schema.citizenship; }; }; - id: { id: string }; + id: string; issuer: { pubkey: string; }; - issuanceDate: { unixTimestamp: number }; - expirationDate: { unixTimestamp: number }; + issuanceDate: number; + expirationDate: number; subject: { pubkey: string; }; credentialStandardHash: string; - signature: { - signatureBase58: string; - }; + signature: string; }; beforeEach(() => { @@ -115,12 +107,12 @@ describe('Credential creation and validation tests', () => { standard: KnownUserCredential.schema.citizenship } }, - id: { id: '0x1234567890' }, + id: '0x1234567890', issuer: { pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' }, - issuanceDate: { unixTimestamp: 1710426864 }, - expirationDate: { unixTimestamp: 1720426864 }, + issuanceDate: 1710426864, + expirationDate: 1720426864, subject: { pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' }, @@ -130,10 +122,7 @@ describe('Credential creation and validation tests', () => { Credential1Raw = { ...CredentialDataRaw1, - signature: { - signatureBase58: - '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' - } + signature: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' }; }); @@ -278,99 +267,99 @@ describe('Credential creation and validation tests', () => { }); }); - describe('checkCredentialStandardConformance Function Tests', () => { - it('should confirm conformance for matching standard and credential', () => { - // Given a correct pair of Credential and CredentialStandard that are expected to match - const matchingCredential = CredentialSchema.parse(Credential1Raw); - const matchingStandard = KnownUserCredential; - - const isConformant = checkCredentialStandardConformance( - matchingCredential, - matchingStandard - ); - - // Expect the result to be true since the credential should conform to the standard - expect(isConformant).toBeTruthy(); - }); - - it('should detect non-conformance due to fields mismatch', () => { - interface Claim { - name: string; - value: string; - fieldsValue: number[]; // Adjusted to number[] since your fieldsValue seems to be an array of numbers - standard: any; // Use the actual expected type - } - - interface CredentialData { - claims: { - [key: string]: Claim; - }; - // Include other necessary fields from CredentialDataRaw1... - id: any; // Use the actual expected type - issuer: any; // Use the actual expected type - issuanceDate: any; // Use the actual expected type - expirationDate: any; // Use the actual expected type - subject: any; // Use the actual expected type - credentialStandardHash: any; // Use the actual expected type - } - - let nonMatchingCredentialRaw: CredentialData = { ...CredentialDataRaw1 }; - // set citizenship field value to be a single field array - - delete nonMatchingCredentialRaw.claims.citizenship; - - nonMatchingCredentialRaw.claims.city = { - name: 'city', - value: 'New York', - fieldsValue: [0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b], - standard: KnownUserCredential.schema.citizenship - }; - - const result = CredentialSchema.safeParse(nonMatchingCredentialRaw); - - if (!result.success) { - console.log( - 'Should be able to parse the nonMatchingCredentialRaw', - result.error - ); - return; - } - - const nonMatchingCredential = result.data; - - expect(nonMatchingCredential.claims.citizenship).toBeUndefined(); - - // Call the function to check conformance - const isConformant = checkCredentialStandardConformance( - nonMatchingCredential, - KnownUserCredential - ); - - // Expect the result to be false since the credential fields do not match the standard specifications - expect(isConformant).toBeFalsy(); - }); - - it('should detect non-conformance due to fieldValues length mismatch', () => { - // Define a non-matching CredentialStandard and Credential by altering the fields - const matchingCredential = CredentialSchema.parse(Credential1Raw); - - let nonMatchingCredential = { - ...matchingCredential, - claims: { ...matchingCredential.claims } - }; - // set citizenship field value to be a single field array - nonMatchingCredential.claims.citizenship.fieldsValue = [ - new Field(0x5541) - ]; - - // Call the function to check conformance - const isConformant = checkCredentialStandardConformance( - nonMatchingCredential, - KnownUserCredential - ); - - // Expect the result to be false since the credential fields do not match the standard specifications - expect(isConformant).toBeFalsy(); - }); - }); + // describe('checkCredentialStandardConformance Function Tests', () => { + // it('should confirm conformance for matching standard and credential', () => { + // // Given a correct pair of Credential and CredentialStandard that are expected to match + // const matchingCredential = CredentialSchema.parse(Credential1Raw); + // const matchingStandard = KnownUserCredential; + + // const isConformant = checkCredentialStandardConformance( + // matchingCredential, + // matchingStandard + // ); + + // // Expect the result to be true since the credential should conform to the standard + // expect(isConformant).toBeTruthy(); + // }); + + // it('should detect non-conformance due to fields mismatch', () => { + // interface Claim { + // name: string; + // value: string; + // fieldsValue: number[]; // Adjusted to number[] since your fieldsValue seems to be an array of numbers + // standard: any; // Use the actual expected type + // } + + // interface CredentialData { + // claims: { + // [key: string]: Claim; + // }; + // // Include other necessary fields from CredentialDataRaw1... + // id: any; // Use the actual expected type + // issuer: any; // Use the actual expected type + // issuanceDate: any; // Use the actual expected type + // expirationDate: any; // Use the actual expected type + // subject: any; // Use the actual expected type + // credentialStandardHash: any; // Use the actual expected type + // } + + // let nonMatchingCredentialRaw: CredentialData = { ...CredentialDataRaw1 }; + // // set citizenship field value to be a single field array + + // delete nonMatchingCredentialRaw.claims.citizenship; + + // nonMatchingCredentialRaw.claims.city = { + // name: 'city', + // value: 'New York', + // fieldsValue: [0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b], + // standard: KnownUserCredential.schema.citizenship + // }; + + // const result = CredentialSchema.safeParse(nonMatchingCredentialRaw); + + // if (!result.success) { + // console.log( + // 'Should be able to parse the nonMatchingCredentialRaw', + // result.error + // ); + // return; + // } + + // const nonMatchingCredential = result.data; + + // expect(nonMatchingCredential.claims.citizenship).toBeUndefined(); + + // // Call the function to check conformance + // const isConformant = checkCredentialStandardConformance( + // nonMatchingCredential, + // KnownUserCredential + // ); + + // // Expect the result to be false since the credential fields do not match the standard specifications + // expect(isConformant).toBeFalsy(); + // }); + + // it('should detect non-conformance due to fieldValues length mismatch', () => { + // // Define a non-matching CredentialStandard and Credential by altering the fields + // const matchingCredential = CredentialSchema.parse(Credential1Raw); + + // let nonMatchingCredential = { + // ...matchingCredential, + // claims: { ...matchingCredential.claims } + // }; + // // set citizenship field value to be a single field array + // nonMatchingCredential.claims.citizenship.fieldsValue = [ + // new Field(0x5541) + // ]; + + // // Call the function to check conformance + // const isConformant = checkCredentialStandardConformance( + // nonMatchingCredential, + // KnownUserCredential + // ); + + // // Expect the result to be false since the credential fields do not match the standard specifications + // expect(isConformant).toBeFalsy(); + // }); + // }); }); From 1e80e07bca7a4fa961e0e2f9345f2c1c6519bce9 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sun, 31 Mar 2024 21:47:39 +0200 Subject: [PATCH 19/34] Improve issuer interface, make index.ts run with no issues. --- .../src/credential.ts | 22 +++++------ .../src/index.ts | 9 +++-- .../src/issuer.ts | 39 ++++++++++++++++--- .../src/zkclaims/citizenship.ts | 4 +- .../{dateOfBirth.ts => date-of-birth.ts} | 4 +- 5 files changed, 52 insertions(+), 26 deletions(-) rename minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/{dateOfBirth.ts => date-of-birth.ts} (88%) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts index d88bd00..f08a967 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -1,12 +1,10 @@ -import { CircuitString, Field, Poseidon, PrivateKey } from 'o1js'; +import { CircuitString, Field, Poseidon } from 'o1js'; import * as o1js from 'o1js'; import { arraysAreEqual } from './helpers/utils.js'; import { Logger } from 'tslog'; -import { CredSubjectId, Credential, CredentialData, CredentialSchema, CredentialStandard } from './data/transit/cred.js'; +import { CredSubjectId, Credential, CredentialData, CredentialSchema, CredentialStandard, IssuerId } from './data/transit/cred.js'; import { claimStandardHash } from './claim.js'; import { mkVCredStruct } from './data/o1js/vcred.js'; -import { SignatureSchema } from './data/transit/common.js'; -import { Issuer } from './issuer.js'; const log = new Logger({ name: 'credential.ts' }); @@ -49,9 +47,9 @@ export const verifyAndIssueCredential = standard: CredentialStandard, credentialData: CredentialData, subject: CredSubjectId, - issuer: Issuer - ) => - (privateKey: PrivateKey) => { + issuer: IssuerId, + sign: (flds: Field[]) => o1js.Signature, + ) => { // get fields for the signature log.debug('Entering verifyAndIssueCredential...'); @@ -59,16 +57,14 @@ export const verifyAndIssueCredential = const flds = mkVCredStruct(credentialData).toFields(); log.debug('Creating signature for the fields data'); - const signature = SignatureSchema.parse( - o1js.Signature.create(privateKey, flds).toBase58() - ); + const signature = sign(flds); // create the credential log.debug('Parsing the credential with the signature'); const credential = CredentialSchema.parse({ ...credentialData, - signature + signature: signature.toBase58() }); // check if the credential conforms to the standard @@ -80,8 +76,8 @@ export const verifyAndIssueCredential = // additional assertions // issuer pubkey matches the private key - if (issuer.pubkey !== privateKey.toPublicKey().toBase58()) { - throw new Error('Issuer pubkey does not match the private key'); + if (!signature.verify(o1js.PublicKey.fromBase58(issuer.pubkey), flds).equals(true)) { + throw new Error('Issuer pubkey does not match the private key used for the signature'); } // credential subject public key matches the given subject public key diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 9cf012f..b0b7abb 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,7 +1,7 @@ import { Logger } from 'tslog'; -import { PrivateKey } from 'o1js'; +import { PrivateKey, Signature } from 'o1js'; import { Issuer, IssuerSchema } from './issuer.js'; -import * as DateOfBirth from './zkclaims/dateOfBirth.js'; +import * as DateOfBirth from './zkclaims/date-of-birth.js'; import * as Citizenship from './zkclaims/citizenship.js'; import { DateTime } from 'luxon'; import { DateTimeSchema, FieldSchema } from './data/transit/common.js'; @@ -87,8 +87,9 @@ const {credential: verifiedCredential} = verifyAndIssueCredential( KnownUserCredential, credentialData, subject, - issuer -)(issuerPrivateKey); + issuer, + (flds) => Signature.create(issuerPrivateKey, flds) +) log.info('3. Make it available to holder on access code.'); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts index 02dc571..e08a5da 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/issuer.ts @@ -1,10 +1,23 @@ import { z } from 'zod'; -import { IssuerId, IssuerIdSchema } from './data/transit/cred'; +import { + CredSubjectId, + CredentialData, + CredentialStandard, + IssuerId, + IssuerIdSchema +} from './data/transit/cred.js'; +import { verifyAndIssueCredential } from './credential.js'; +import { Field, Signature } from 'o1js'; interface IssuerProps { id: IssuerId; } +/** + The issuer of credentials. + + TODO. The private key is not included in the issuer object. It is expected in some operations done withing the `sign` callback functions. Eventually there should be a safer way to do it so that it does not leaves some hardened enclave. + */ export class Issuer { id: IssuerId; constructor(props: IssuerProps) { @@ -14,13 +27,29 @@ export class Issuer { get pubkey() { return this.id.pubkey; } + + verifyAndIssue( + credentialStandard: CredentialStandard, + credentialData: CredentialData, + subject: CredSubjectId, + sign: (flds: Field[]) => Signature + ) { + return verifyAndIssueCredential( + credentialStandard, + credentialData, + subject, + this.id, + sign + ); + } } // to be extended later -export const IssuerSchema = z.object({ - id: IssuerIdSchema -}).transform((d) => new Issuer(d)); - +export const IssuerSchema = z + .object({ + id: IssuerIdSchema + }) + .transform((d) => new Issuer(d)); // type-checker level assertion to keep the schema and the interface in sync type IssuerData = z.infer; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts index af13c42..b500243 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts @@ -1,6 +1,6 @@ import { CircuitString } from 'o1js'; -import { FieldSchema } from 'src/data/transit/common'; -import { Claim } from 'src/data/transit/cred'; +import { FieldSchema } from '../data/transit/common.js'; +import { Claim } from '../data/transit/cred.js'; const CODE_LENGTH = 3; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/date-of-birth.ts similarity index 88% rename from minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts rename to minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/date-of-birth.ts index 6c26f84..6757c94 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/dateOfBirth.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/date-of-birth.ts @@ -1,7 +1,7 @@ import { DateTime } from 'luxon'; import { Field } from 'o1js'; -import { FieldSchema } from 'src/data/transit/common'; -import { Claim } from 'src/data/transit/cred'; +import { Claim } from '../data/transit/cred.js'; +import { FieldSchema } from '../data/transit/common.js'; export const schema = { standardId: 'dateOfBirth', From 7b753502e55cea9dbadab36484d493e5bf3af977 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Mon, 1 Apr 2024 00:04:39 +0200 Subject: [PATCH 20/34] Add credential store and tests. --- .../src/credential-store.test.ts | 182 ++++++++++++++++++ .../src/credential-store.ts | 99 ++++++++++ .../src/index.ts | 4 +- .../src/zkclaims/citizenship.ts | 4 +- .../src/zkclaims/date-of-birth.ts | 4 +- 5 files changed, 287 insertions(+), 6 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts new file mode 100644 index 0000000..c9f7a5a --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts @@ -0,0 +1,182 @@ +import { Field, PrivateKey, Signature } from "o1js"; +import { CredentialStore, IStorage } from "./credential-store.js"; +import { CredSubjectIdSchema, Credential, CredentialData, CredentialStandard, IssuerIdSchema, PubKeyId, PubKeyIdSchema, VCredIdSchema } from "./data/transit/cred.js"; +import { Issuer, IssuerSchema } from "./issuer.js"; +import * as DateOfBirth from './zkclaims/date-of-birth.js'; +import * as Citizenship from './zkclaims/citizenship.js'; +import { DateTime } from "luxon"; +import { DateTimeSchema, FieldSchema } from "./data/transit/common.js"; +import { credentialStandardHash, verifyAndIssueCredential } from "./credential.js"; +import { ILogObj, Logger } from 'tslog'; +import { claimStandardHash } from "./claim.js"; + +const log = new Logger({ + name: 'credential-store-test.ts' +}); + +class MockStorage implements IStorage { + private store: Record = {}; + + async getItem(key: string): Promise { + const r = this.store[key] || null; + log.debug(`getItem(${key}) = ${r}`); + return r; + } + + async setItem(key: string, value: string): Promise { + log.debug(`setItem(${key}, ${value})`); + this.store[key] = value; + } + + async removeItem(key: string): Promise { + log.debug(`removeItem(${key})`); + delete this.store[key]; + } + + async clear(): Promise { + log.debug(`clear()`); + this.store = {}; + } +} + +const prepareTestDataCredential = (): {credential: Credential} => { + + const KnownUserCredential: CredentialStandard = { + standardId: "eth.example.KnownUserCredential-v1.0", + description: "Credential that will be given to users after verification of documents.", + schema: { + dateOfBirth: DateOfBirth.standard, + citizenship: Citizenship.standard, + } + } + + const createEntity = () => { + const privateKey = PrivateKey.random(); + const pubkeyId: PubKeyId = PubKeyIdSchema.parse({ pubkey: privateKey.toPublicKey().toBase58() }); + const sign: (flds: Field[]) => Signature = (flds: Field[]) => Signature.create(privateKey, flds) + return { sign, pubkeyId }; + } + + const { sign: signIssuer, pubkeyId: issuerId } = createEntity(); + const { sign: signSubject, pubkeyId: subjectId } = createEntity(); + + + // throw new Error('Not implemented'); + const data: CredentialData = { + id: VCredIdSchema.parse("1"), + subject: CredSubjectIdSchema.parse(subjectId), + issuer: IssuerIdSchema.parse(issuerId), + claims: { + dateOfBirth: DateOfBirth.mkDateOfBirthClaim(DateTime.now()), + citizenship: Citizenship.mkCitizenshipClaim("USA") + }, + issuanceDate: DateTimeSchema.parse(DateTime.now().toISO()), + expirationDate: DateTimeSchema.parse(DateTime.now().plus({ years: 1 }).toISO()), + credentialStandardHash: FieldSchema.parse(credentialStandardHash(KnownUserCredential).toString()) + } + + const {credential} = verifyAndIssueCredential( + KnownUserCredential, + data, + subjectId, + issuerId, + signIssuer + ) + + return { + credential + } +}; + + +describe('CredentialStore Tests', () => { + let storage: MockStorage; + let credentialStore: CredentialStore; + let credential: Credential; + + beforeAll(() => { + credential = prepareTestDataCredential().credential; + }); + + beforeEach(() => { + storage = new MockStorage(); + credentialStore = new CredentialStore('testCredentials', storage); + }); + + it('successfully adds a valid credential', async () => { + await credentialStore.addCredential(credential); + + // Verify the credential was stored + const storedCredentialJson = await storage.getItem('testCredentials'); + expect(storedCredentialJson).not.toBeNull(); + + const storedCredentials = JSON.parse(storedCredentialJson || '{}'); + expect(storedCredentials[credential.id]).toEqual(credential); + }); + + it('retrieves an existing credential by ID', async () => { + // Manually add the credential to the mock storage to simulate existing data + await storage.setItem('testCredentials', JSON.stringify({ [credential.id]: credential })); + + const retrieved = await credentialStore.getCredential(credential.id); + expect(retrieved).toEqual(credential); + }); + + it('successfully removes an existing credential by ID', async () => { + await credentialStore.addCredential(credential); // Assume `credential` is already defined + await credentialStore.removeCredential(credential.id); + + const storedCredential = await credentialStore.getCredential(credential.id); + expect(storedCredential).toBeNull(); + }); + + it('performs gracefully when trying to remove a non-existing credential ID', async () => { + expect(async () => { + await credentialStore.removeCredential('nonExistingId'); + }).not.toThrow(); + }); + + it('returns all credentials for a given issuer', async () => { + log.debug('== test: it returns all credentials for a given issuer'); + await credentialStore.addCredential(credential); // Assume `credential` is correctly defined + + const credentials = await credentialStore.findCredentialsByIssuer(credential.issuer); + expect(credentials).toEqual(expect.arrayContaining([credential])); + }); + + it('returns an empty array if no credentials match the given issuer', async () => { + const credentials = await credentialStore.findCredentialsByIssuer({pubkey:'nonExistingIssuer'}); + expect(credentials).toEqual([]); + }); + + it('returns credentials that match a given issuer ID and all specified claim standard IDs', async () => { + await credentialStore.addCredential(credential); // Assume `credential` is correctly defined + const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + const matchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards); + expect(matchedCredentials.length).toBe(1); + expect(matchedCredentials[0].id).toEqual(credential.id); + }); + + it('returns credentials that match a given issuer ID and all specified claim standard IDs #2', async () => { + await credentialStore.addCredential(credential); // Assume `credential` is correctly defined + const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + const matchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards.slice(0, 1)); + expect(matchedCredentials.length).toBe(1); + expect(matchedCredentials[0].id).toEqual(credential.id); + }); + + it('handles cases where some credentials do not contain any of the specified claim standards', async () => { + let standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + standards[1] = new Field(999); // Intentionally set to a non-matching standard hash + const unmatchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards); + expect(unmatchedCredentials.length).toBe(0); + }); + + it('returns an empty array if no credentials match the criteria', async () => { + const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + const issuerId = { pubkey: PrivateKey.random().toPublicKey().toBase58() } + const noMatch = await credentialStore.findCredentialsByClaimStandards(issuerId, standards); + expect(noMatch.length).toBe(0); + }); + +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts new file mode 100644 index 0000000..84a2234 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts @@ -0,0 +1,99 @@ +import { Field } from 'o1js'; +import { claimStandardHash } from './claim'; +import { Credential, CredentialSchema, IssuerId } from './data/transit/cred'; + +export interface IStorage { + /** + * Retrieves an item from the storage. + * @param key The key of the item to retrieve. + * @returns The item's value if found, otherwise null. + */ + getItem(key: string): Promise; + /** + * Stores an item in the storage. + * @param key The key under which to store the item. + * @param value The value of the item to store. + */ + setItem(key: string, value: string): Promise; + /** + * Removes an item from the storage. + * @param key The key of the item to remove. + */ + removeItem(key: string): Promise; + /** + * Clears all items from the storage. + */ + clear(): Promise; +} + +export class CredentialStore { + constructor( + private storageKey: string, + private storage: IStorage + ) {} + + async addCredential(credential: Credential): Promise { + // Validate the credential against the schema + const result = CredentialSchema.safeParse(credential); + if (!result.success) { + throw new Error(`Invalid credential: ${result.error}`); + } + + // Retrieve the existing credentials, add the new one, then save back + const credentials = await this.getAllCredentials(); + credentials[credential.id] = credential; + await this.saveCredentials(credentials); + } + + async getCredential(credentialId: string): Promise { + const credentials = await this.getAllCredentials(); + return credentials[credentialId] || null; + } + + private async getAllCredentials(): Promise> { + const credentialsString = await this.storage.getItem(this.storageKey); + if (credentialsString) { + return JSON.parse(credentialsString); + } + return {}; + } + + private async saveCredentials( + credentials: Record + ): Promise { + const credentialsString = JSON.stringify(credentials); + await this.storage.setItem(this.storageKey, credentialsString); + } + + async findCredentialsByIssuer(issuerId: IssuerId): Promise { + const allCredentials = await this.getAllCredentials(); + const r = Object.values(allCredentials).filter( + (cred) => cred.issuer.pubkey === issuerId.pubkey + ); + return r; + } + + async findCredentialsByClaimStandards( + issuerId: IssuerId, + claimStandardHashes: Field[] + ): Promise { + + const hashesstring = claimStandardHashes.map((h) => h.toString()); + + const credentialsByIssuer = await this.findCredentialsByIssuer(issuerId); + return credentialsByIssuer.filter((credential) => { + const claimStandards = Object.values(credential.claims).map( + (claim) => claimStandardHash(claim.standard).toString() + ); + return hashesstring.every((h) => claimStandards.includes(h)); + }); + } + + async removeCredential(credentialId: string): Promise { + const credentials = await this.getAllCredentials(); + if (credentials[credentialId]) { + delete credentials[credentialId]; + await this.saveCredentials(credentials); + } + } +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index b0b7abb..2cfebc8 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -36,8 +36,8 @@ const KnownUserCredential: CredentialStandard = { standardId: "eth.example.KnownUserCredential-v1.0", description: "Credential that will be given to users after verification of documents.", schema: { - dateOfBirth: DateOfBirth.schema, - citizenship: Citizenship.schema + dateOfBirth: DateOfBirth.standard, + citizenship: Citizenship.standard } } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts index b500243..9b6b67f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts @@ -4,7 +4,7 @@ import { Claim } from '../data/transit/cred.js'; const CODE_LENGTH = 3; -export const schema = { +export const standard = { standardId: 'citizenship', description: 'Country citizenship as confirmed by verified documentation. Only single-country citizenships supported.', @@ -30,7 +30,7 @@ export const mkCitizenshipClaim = (name: string): Claim => { name: 'citizenship', value: code, fieldsValue: CircuitString.fromString(code).toFields().slice(0, CODE_LENGTH).map((x) => FieldSchema.parse(x.toString())), - standard: schema + standard }; }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/date-of-birth.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/date-of-birth.ts index 6757c94..ba9c004 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/date-of-birth.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/date-of-birth.ts @@ -3,7 +3,7 @@ import { Field } from 'o1js'; import { Claim } from '../data/transit/cred.js'; import { FieldSchema } from '../data/transit/common.js'; -export const schema = { +export const standard = { standardId: 'dateOfBirth', description: 'Date of birth as stated on provided national id or a passport', referenceToExternalStandard: @@ -22,6 +22,6 @@ export const mkDateOfBirthClaim = (dt: DateTime) : Claim => { name: 'dateOfBirth', value: dt.toISO(), fieldsValue: [ FieldSchema.parse((new Field(dt.toUTC().toUnixInteger())).toString())], - standard: schema + standard }; } From 81fc59cc5ef06c095a651953d68f966c07046964 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Wed, 17 Apr 2024 21:25:53 +0200 Subject: [PATCH 21/34] Add conceptual overview of preparing credential proofs. --- .../src/circuit/vcred-proof.ts | 0 .../src/credential-store.test.ts | 123 +----------------- .../src/credential-store.ts | 30 +++++ .../src/credential.ts | 2 +- .../src/index.ts | 120 ++++++++++++++++- 5 files changed, 151 insertions(+), 124 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts new file mode 100644 index 0000000..e69de29 diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts index c9f7a5a..a5f393d 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts @@ -1,45 +1,18 @@ import { Field, PrivateKey, Signature } from "o1js"; -import { CredentialStore, IStorage } from "./credential-store.js"; import { CredSubjectIdSchema, Credential, CredentialData, CredentialStandard, IssuerIdSchema, PubKeyId, PubKeyIdSchema, VCredIdSchema } from "./data/transit/cred.js"; -import { Issuer, IssuerSchema } from "./issuer.js"; import * as DateOfBirth from './zkclaims/date-of-birth.js'; import * as Citizenship from './zkclaims/citizenship.js'; import { DateTime } from "luxon"; import { DateTimeSchema, FieldSchema } from "./data/transit/common.js"; import { credentialStandardHash, verifyAndIssueCredential } from "./credential.js"; import { ILogObj, Logger } from 'tslog'; -import { claimStandardHash } from "./claim.js"; -const log = new Logger({ +export const log = new Logger({ name: 'credential-store-test.ts' }); -class MockStorage implements IStorage { - private store: Record = {}; - async getItem(key: string): Promise { - const r = this.store[key] || null; - log.debug(`getItem(${key}) = ${r}`); - return r; - } - - async setItem(key: string, value: string): Promise { - log.debug(`setItem(${key}, ${value})`); - this.store[key] = value; - } - - async removeItem(key: string): Promise { - log.debug(`removeItem(${key})`); - delete this.store[key]; - } - - async clear(): Promise { - log.debug(`clear()`); - this.store = {}; - } -} - -const prepareTestDataCredential = (): {credential: Credential} => { +export const prepareTestDataCredential = (): {credential: Credential} => { const KnownUserCredential: CredentialStandard = { standardId: "eth.example.KnownUserCredential-v1.0", @@ -58,7 +31,7 @@ const prepareTestDataCredential = (): {credential: Credential} => { } const { sign: signIssuer, pubkeyId: issuerId } = createEntity(); - const { sign: signSubject, pubkeyId: subjectId } = createEntity(); + const { sign: _, pubkeyId: subjectId } = createEntity(); // throw new Error('Not implemented'); @@ -89,94 +62,4 @@ const prepareTestDataCredential = (): {credential: Credential} => { }; -describe('CredentialStore Tests', () => { - let storage: MockStorage; - let credentialStore: CredentialStore; - let credential: Credential; - - beforeAll(() => { - credential = prepareTestDataCredential().credential; - }); - - beforeEach(() => { - storage = new MockStorage(); - credentialStore = new CredentialStore('testCredentials', storage); - }); - - it('successfully adds a valid credential', async () => { - await credentialStore.addCredential(credential); - - // Verify the credential was stored - const storedCredentialJson = await storage.getItem('testCredentials'); - expect(storedCredentialJson).not.toBeNull(); - - const storedCredentials = JSON.parse(storedCredentialJson || '{}'); - expect(storedCredentials[credential.id]).toEqual(credential); - }); - it('retrieves an existing credential by ID', async () => { - // Manually add the credential to the mock storage to simulate existing data - await storage.setItem('testCredentials', JSON.stringify({ [credential.id]: credential })); - - const retrieved = await credentialStore.getCredential(credential.id); - expect(retrieved).toEqual(credential); - }); - - it('successfully removes an existing credential by ID', async () => { - await credentialStore.addCredential(credential); // Assume `credential` is already defined - await credentialStore.removeCredential(credential.id); - - const storedCredential = await credentialStore.getCredential(credential.id); - expect(storedCredential).toBeNull(); - }); - - it('performs gracefully when trying to remove a non-existing credential ID', async () => { - expect(async () => { - await credentialStore.removeCredential('nonExistingId'); - }).not.toThrow(); - }); - - it('returns all credentials for a given issuer', async () => { - log.debug('== test: it returns all credentials for a given issuer'); - await credentialStore.addCredential(credential); // Assume `credential` is correctly defined - - const credentials = await credentialStore.findCredentialsByIssuer(credential.issuer); - expect(credentials).toEqual(expect.arrayContaining([credential])); - }); - - it('returns an empty array if no credentials match the given issuer', async () => { - const credentials = await credentialStore.findCredentialsByIssuer({pubkey:'nonExistingIssuer'}); - expect(credentials).toEqual([]); - }); - - it('returns credentials that match a given issuer ID and all specified claim standard IDs', async () => { - await credentialStore.addCredential(credential); // Assume `credential` is correctly defined - const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); - const matchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards); - expect(matchedCredentials.length).toBe(1); - expect(matchedCredentials[0].id).toEqual(credential.id); - }); - - it('returns credentials that match a given issuer ID and all specified claim standard IDs #2', async () => { - await credentialStore.addCredential(credential); // Assume `credential` is correctly defined - const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); - const matchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards.slice(0, 1)); - expect(matchedCredentials.length).toBe(1); - expect(matchedCredentials[0].id).toEqual(credential.id); - }); - - it('handles cases where some credentials do not contain any of the specified claim standards', async () => { - let standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); - standards[1] = new Field(999); // Intentionally set to a non-matching standard hash - const unmatchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards); - expect(unmatchedCredentials.length).toBe(0); - }); - - it('returns an empty array if no credentials match the criteria', async () => { - const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); - const issuerId = { pubkey: PrivateKey.random().toPublicKey().toBase58() } - const noMatch = await credentialStore.findCredentialsByClaimStandards(issuerId, standards); - expect(noMatch.length).toBe(0); - }); - -}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts index 84a2234..2368e05 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts @@ -1,6 +1,11 @@ import { Field } from 'o1js'; import { claimStandardHash } from './claim'; import { Credential, CredentialSchema, IssuerId } from './data/transit/cred'; +import { ILogObj, Logger } from 'tslog'; + +export const log = new Logger({ + name: 'credential-store.ts' +}); export interface IStorage { /** @@ -97,3 +102,28 @@ export class CredentialStore { } } } + +export class MockStorage implements IStorage { + private store: Record = {}; + + async getItem(key: string): Promise { + const r = this.store[key] || null; + log.debug(`getItem(${key}) = ${r}`); + return r; + } + + async setItem(key: string, value: string): Promise { + log.debug(`setItem(${key}, ${value})`); + this.store[key] = value; + } + + async removeItem(key: string): Promise { + log.debug(`removeItem(${key})`); + delete this.store[key]; + } + + async clear(): Promise { + log.debug(`clear()`); + this.store = {}; + } +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts index f08a967..7d09be8 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -49,7 +49,7 @@ export const verifyAndIssueCredential = subject: CredSubjectId, issuer: IssuerId, sign: (flds: Field[]) => o1js.Signature, - ) => { + ): { credential: Credential} => { // get fields for the signature log.debug('Entering verifyAndIssueCredential...'); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 2cfebc8..de4aeed 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,12 +1,14 @@ import { Logger } from 'tslog'; -import { PrivateKey, Signature } from 'o1js'; +import { Field, PrivateKey, Signature, Struct, UInt64, ZkProgram } from 'o1js'; import { Issuer, IssuerSchema } from './issuer.js'; import * as DateOfBirth from './zkclaims/date-of-birth.js'; import * as Citizenship from './zkclaims/citizenship.js'; import { DateTime } from 'luxon'; import { DateTimeSchema, FieldSchema } from './data/transit/common.js'; -import { CredSubjectId, CredSubjectIdSchema, CredentialData, CredentialStandard, VCredIdSchema } from './data/transit/cred.js'; +import { CredSubjectId, CredSubjectIdSchema, Credential, CredentialData, CredentialStandard, VCredIdSchema } from './data/transit/cred.js'; import { credentialStandardHash, verifyAndIssueCredential } from './credential.js'; +import { CredentialStore, MockStorage } from './credential-store.js'; +import { VCredStruct } from './data/o1js/vcred.js'; const log = new Logger({ name: 'index.ts prototyping' }); @@ -83,7 +85,7 @@ const credentialData: CredentialData = mkCredentialData(); log.info('2. Verify and sign'); -const {credential: verifiedCredential} = verifyAndIssueCredential( +const { credential: verifiedCredential }: { credential: Credential } = verifyAndIssueCredential( KnownUserCredential, credentialData, subject, @@ -104,8 +106,120 @@ log.info('Requesting a credential'); log.info('Installing in the credential store'); +const credentialStore = new CredentialStore("mock-store", new MockStorage()) + +await credentialStore.addCredential(verifiedCredential); + +const credential = await credentialStore.getCredential(verifiedCredential.id); + +if (!credential) { + throw new Error('Credential not found'); +} + + + + log.info('(later) Requesting a resource access schema'); +// The verifier can ask for a specific proof via something like this: + +// 1. Secret input of a private key matching the subject pubkey +// 2. Matching issuer +// 3. Matching credential standard hash +// 4. datetime validity + +// 5. claim proofs + + +// lets start with the credential validity and standard proofs + +/** + + publicinputs: + - validity range + - signatureChallenge (for proving that the prover is the subject) + - credentialtypeId = hash (credentialStandardHash , issuer) + - proverIsSubject: Bool -- if the prover is the subject, proved via solving the signature challenge + - hasSubjectPubkey: Bool -- if `SubjectPubkey` contains the subject pubkey + + privateinputs: + - SubjectPrivkey: Privkey -- if `proverIsSubject` is true, contains the subject privkey + - credentialData: CredentialData -- the credential data + + publicOutputs: + - credentialHash: Field -- hash of the credential data + - SubjectPubkey: Pubkey -- if `hasSubjectPubkey` is true, contains the subject pubkey + + +---------- + +methods: + + base prove + + restrict validity range of exising proof + + more ? + + +*/ + +// then how to prove the claim proofs? + + +/** + + publicinputs: + - credentialHash: Field -- hash of the credential data + - claimIndex + - operand: Field -- the operand to compare with + + privateinputs: + - credentialData: CredentialData -- the credential data + - claimData -- to +*/ + +// lets first assume fixed size + + +class VCred extends VCredStruct([1]) {} + +class ClaimProofPublicInput extends Struct({ + credentialHash: Field, + claimIndex: Field, + operand: Field +}) {} + +class ClaimProofSecretInput extends Struct({ + credential: VCred +}) {} + +class ClaimProofOutput extends Struct({ + claimCode: Field +}) {} + +const Program = ZkProgram({ + name: 'VCredProof', + publicInput: ClaimProofPublicInput, + publicOutput: ClaimProofOutput, + methods: { + prove: { + privateInputs: [ClaimProofSecretInput], + method(publicInput: ClaimProofPublicInput, secretInput: ClaimProofSecretInput): ClaimProofOutput { + const claimSlice = secretInput.credential.claims.toFields().slice(5,10) + const claim = secretInput.credential.claims.getClaim(publicInput.claimIndex, claimSlice); + + UInt64.from(claim[0]).assertGreaterThan(UInt64.from(publicInput.operand)); + + return new ClaimProofOutput({ claimCode: new Field(1) }); + } + } + } +}); + +await Program.compile(); + + // // for example somthing akin to: // [{ access: ["read"], // , credentials: [ From c78b9ebab636b30f7293cca17b9ccb48974e160a Mon Sep 17 00:00:00 2001 From: adamczykm Date: Thu, 18 Apr 2024 17:53:10 +0200 Subject: [PATCH 22/34] Starting refactor of provable claims structure. --- .../src/credential-store.ts | 4 +- .../src/data/o1js/claim.ts | 102 ++++++++++++++++-- .../src/data/o1js/vcred.ts | 69 +++++++++++- .../src/data/transit/cred.ts | 12 ++- .../src/helpers/utils.ts | 33 ++++-- .../src/index.ts | 67 ++++++++++-- 6 files changed, 250 insertions(+), 37 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts index 2368e05..931f5e1 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.ts @@ -1,6 +1,6 @@ import { Field } from 'o1js'; -import { claimStandardHash } from './claim'; -import { Credential, CredentialSchema, IssuerId } from './data/transit/cred'; +import { claimStandardHash } from './claim.js'; +import { Credential, CredentialSchema, IssuerId } from './data/transit/cred.js'; import { ILogObj, Logger } from 'tslog'; export const log = new Logger({ diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts index d8bee18..0360e28 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts @@ -1,7 +1,88 @@ -import { Struct, Provable, Field } from 'o1js'; -import { arraysAreEqual, ftn } from '../../helpers/utils.js'; +/* DEV: Due to misconception I've had on how Provable.witness and the level + of dynamism that circuits can have, I have to re-write this module + so that claims in the forms suitable for the zk program are represented + as a MerkleMap instead. + + Which means that most of this module will be gone */ + +import { Struct, Provable, Field, MerkleMapWitness, MerkleMap } from 'o1js'; +import { + arraysAreEqual, + ftn, + mapObject, +} from '../../helpers/utils.js'; import { FieldsSchema } from './common.js'; -import { Claim } from '../transit/cred.js'; +import { Claim, CredentialDataClaims } from '../transit/cred.js'; + +// ------------ NEW + +/** Since the claim will be presented to the circuit as fields and a witness + to the claim MerkleMap this module will now focus on making a claim + that is given in its transit form, suitable to be put into a MerkleMap + + In order to clearly and uniquely identify the claim we can use information + available in the transit form of the credential which is: + - the claim's name, + - the claim's standardId, + - the claims field representation length + + Hence the claim id will be the hash of the concatenation of these three + */ +export class ClaimId extends Field { + static fromTransit(claim: Claim): ClaimId { + const claimId = `${claim.name}${claim.standard.standardId}${claim.fieldsValue.length}`; + return new Field(claimId); + } +} + +/** For the convenience and encapsulation of working with claims + in the o1js written circuits, let's build a structure holding + all the data conveniently and in one place + */ + +type ClaimData = { + claimId: ClaimId; + claim: Claim; + getWitness(): MerkleMapWitness; +}; + +export class ClaimMap { + public readonly claimIdMap: Record; + + protected constructor(public readonly claims: Record, + public readonly merkleMap: MerkleMap) { + this.claimIdMap = + mapObject(claims, ({ value: newValue }) => { + return { newKey: newValue.claimId.toString(), newValue } + } + ); + } + + public getRoot() { + return this.merkleMap.getRoot(); + } + + public getClaimById(claimId: ClaimId) { + return this.claimIdMap[claimId.toString()]; + } + + static fromTransit(claims: CredentialDataClaims) { + const merkleMap = new MerkleMap(); + + const claimData = mapObject(claims, ({ key: newKey, value: claim }) => { + const claimId = ClaimId.fromTransit(claim); + const witness = merkleMap.getWitness(claimId); + return { + newKey, + newValue: { claimId, claim, getWitness: () => witness } + }; + }); + + return new ClaimMap(claimData, merkleMap); + } +} + +// ------------ OLD const CLAIMS_MAX_SIZE = 128; @@ -18,7 +99,9 @@ export function mkClaimStruct(claim: Claim | Field[]): IClaimStruct { if (Array.isArray(claim)) { return ClaimStruct(claim.length).fromFields(claim); } else { - return ClaimStruct(claim.fieldsValue.length).fromFields(claim.fieldsValue.map(s => new Field(s))); + return ClaimStruct(claim.fieldsValue.length).fromFields( + claim.fieldsValue.map((s) => new Field(s)) + ); } } @@ -60,15 +143,13 @@ export const ClaimStruct = (length: number): IClaimStructClass => { static fromTransit(t: Claim) { return new Claim_(FieldsSchema.parse(t.fieldsValue)); } - } return Claim_ as IClaimStructClass; }; - export const computeClaimSizes = (claims: IClaimStruct[]) => { - return claims.map(c => ftn(c.length)); + return claims.map((c) => ftn(c.length)); }; export const mkClaims = (claims: IClaimStruct[]): IFieldClaims => { @@ -76,7 +157,6 @@ export const mkClaims = (claims: IClaimStruct[]): IFieldClaims => { return Claims(size).fromClaims(claims); }; - export function Claims(claimSizes: number[]) { if (claimSizes.length == 0) { throw new Error('claimSizes must not be empty.'); @@ -105,7 +185,7 @@ export function Claims(claimSizes: number[]) { } static fromTransit(claims: Claim[]) { - const receivedSizes = claims.map((c) => (c.fieldsValue.length)); + const receivedSizes = claims.map((c) => c.fieldsValue.length); if (!arraysAreEqual(receivedSizes, claimSizes)) { throw new Error("'claims' array sizes are invalid"); @@ -135,12 +215,14 @@ export function Claims(claimSizes: number[]) { return new Claims_({ count: new Field(claims.length), packed }); } + // the provable code control flow cannot depend on the numbers + // gotten from inputs public getClaim(ix: Field, assert: Field[]): Field[] { const i = Number(ix.toBigInt()); const length = Number(this.packed[i + 1].sub(this.packed[i]).toBigInt()); - const c = Number(this.count.toBigInt()); const op = Provable.witness(Provable.Array(Field, length), () => { + const c = Number(this.count.toBigInt()); const start = Number(this.packed[i].toBigInt()); const next = Number(this.packed[i + 1].toBigInt()); return this.packed.slice(c + 1 + start, c + 1 + next); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index ee87da2..5ad0c5b 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -1,6 +1,13 @@ +/* DEV: Due to misconception I've had on how Provable.witness and the level + of dynamism that circuits can have, I have to re-write this module + so that claims in the forms suitable for the zk program are represented + as a MerkleMap. +*/ + import { Struct, Field, Signature } from 'o1js'; import { SignatureSchema, FieldSchema, UnixTimestamp } from './common.js'; import { + ClaimMap, Claims, IFieldClaims, mkClaimStruct, @@ -12,7 +19,65 @@ import { ILogObj, Logger } from 'tslog'; const log = new Logger({name: 'data/o1js/vcred'}); -export interface IVCredStruct { +// ===================== New + +/** + Claims will be reprensented in a merkle map so there's a reduction + in the complexity of the credential provable structure. + */ +export const VCredStructUnsignedFields = { + id: VCredId, + issuer: IssuerId, + issuanceDate: UnixTimestamp, + expirationDate: UnixTimestamp, + subject: CredSubjectId, + claimsMerkleMapRoot: Field, + credentialStandardHash: Field +}; + +export class VCredStructUnsigned2 extends Struct(VCredStructUnsignedFields) { + static Fields = VCredStructUnsignedFields; + + public toFields(): Field[] { + return [ + ...this.id.toFields(), + ...this.issuer.toFields(), + ...this.issuanceDate.toFields(), + ...this.expirationDate.toFields(), + ...this.subject.toFields(), + this.claimsMerkleMapRoot, + ...this.credentialStandardHash.toFields() + ]; + } + + static fromTransit(t: CredentialData): VCredStructUnsigned2 { + const id = VCredId.fromTransit(t.id); + const issuer = IssuerId.fromTransit(t.issuer); + const issuanceDate = UnixTimestamp.fromTransit(t.issuanceDate); + const expirationDate = UnixTimestamp.fromTransit(t.expirationDate); + const subject = CredSubjectId.fromTransit(t.subject); + const claimsMerkleMapRoot = ClaimMap.fromTransit(t.claims).getRoot() + const credentialStandardHash = FieldSchema.parse( + t.credentialStandardHash + ); + + return new VCredStructUnsigned2({ + id, + issuer, + issuanceDate, + expirationDate, + subject, + claimsMerkleMapRoot, + credentialStandardHash + }); + } + } + + + + +// ===================== OLD +export interface IVCredStruct2 { id: VCredId; issuer: IssuerId; issuanceDate: UnixTimestamp; @@ -21,7 +86,7 @@ export interface IVCredStruct { claims: IFieldClaims; credentialStandardHash: Field; toFields(): Field[]; - signature?: Signature; + claimMarkleTreeIssuerSignature?: Signature; } export function VCredStructUnsigned(claimSizes: number[]) { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts index 58341cf..047a36a 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.ts @@ -72,13 +72,15 @@ export const CredentialStandardSchema = z.object({ export type CredentialStandard = z.infer; // ---------------- Credential Data ---------------- - -export const CredentialDataSchema = z.object({ - claims: z - .record(z.string().min(1), ClaimSchema) +export const CredentialDataClaimsSchema = z.record(z.string().min(1), ClaimSchema) .refine((claims) => Object.keys(claims).length > 0, { message: 'Must define at least one claim.' - }), + }) + +export type CredentialDataClaims = z.infer; + +export const CredentialDataSchema = z.object({ + claims: CredentialDataClaimsSchema, id: VCredIdSchema, issuer: IssuerIdSchema, issuanceDate: S.DateTimeSchema, diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts index e8e070d..3239417 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/helpers/utils.ts @@ -2,16 +2,31 @@ import { Field } from 'o1js'; export const ftn = (fld: Field) => Number(fld.toBigInt()); -export function arraysAreEqual(array1: T[], array2: T[]): boolean { - if (array1.length !== array2.length) { +export function arraysAreEqual(array1: T[], array2: T[]): boolean { + if (array1.length !== array2.length) { + return false; + } + + for (let i = 0; i < array1.length; i++) { + if (array1[i] !== array2[i]) { return false; } + } - for (let i = 0; i < array1.length; i++) { - if (array1[i] !== array2[i]) { - return false; - } - } + return true; +} - return true; - } +export function mapObject, U extends string, V>( + obj: T, + transform: ({ key, value }: { key: keyof T, value: T[keyof T] }) => { newKey: U, newValue: V } +): Record { + const result: Record = {} as Record; + + // Iterate over each key-value pair in the object + Object.entries(obj).forEach(([key, value]) => { + const { newKey, newValue } = transform({ key: key as keyof T, value }); + result[newKey] = newValue; + }); + + return result; +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index de4aeed..f77129e 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,5 +1,5 @@ import { Logger } from 'tslog'; -import { Field, PrivateKey, Signature, Struct, UInt64, ZkProgram } from 'o1js'; +import { Field, Poseidon, PrivateKey, Signature, Struct, UInt64, ZkProgram } from 'o1js'; import { Issuer, IssuerSchema } from './issuer.js'; import * as DateOfBirth from './zkclaims/date-of-birth.js'; import * as Citizenship from './zkclaims/citizenship.js'; @@ -116,7 +116,14 @@ if (!credential) { throw new Error('Credential not found'); } +// for proofs we need credential in o1js struct form +// lets first assume fixed size claim data +class VCred extends VCredStruct([1]) {} + +log.info('From transit'); +const vcred = VCred.fromTransit(credential); +const credentialHash = Poseidon.hash(vcred.toFields()); log.info('(later) Requesting a resource access schema'); @@ -125,8 +132,9 @@ log.info('(later) Requesting a resource access schema'); // 1. Secret input of a private key matching the subject pubkey // 2. Matching issuer -// 3. Matching credential standard hash -// 4. datetime validity +// 3. Valid issuer signature +// 4. Matching credential standard hash +// 5. datetime validity // 5. claim proofs @@ -179,11 +187,6 @@ methods: - claimData -- to */ -// lets first assume fixed size - - -class VCred extends VCredStruct([1]) {} - class ClaimProofPublicInput extends Struct({ credentialHash: Field, claimIndex: Field, @@ -198,6 +201,36 @@ class ClaimProofOutput extends Struct({ claimCode: Field }) {} +const mkClaimProofProgram = ( + claimIndex: number, + claimLength: number, + + + + +) => { + +const Program = ZkProgram({ + name: 'VCredProof', + publicInput: ClaimProofPublicInput, + publicOutput: ClaimProofOutput, + methods: { + prove: { + privateInputs: [ClaimProofSecretInput], + method(publicInput: ClaimProofPublicInput, secretInput: ClaimProofSecretInput): ClaimProofOutput { + const claimSlice: Field[] = secretInput.credential.claims.toFields().slice(claimIndex,claimLength) + + // the claim computation + UInt64.from(claimSlice[0]).assertGreaterThanOrEqual(UInt64.from(publicInput.operand)); + + return new ClaimProofOutput({ claimCode: new Field(1) }); + } + } + } +}); +} + + const Program = ZkProgram({ name: 'VCredProof', publicInput: ClaimProofPublicInput, @@ -209,7 +242,8 @@ const Program = ZkProgram({ const claimSlice = secretInput.credential.claims.toFields().slice(5,10) const claim = secretInput.credential.claims.getClaim(publicInput.claimIndex, claimSlice); - UInt64.from(claim[0]).assertGreaterThan(UInt64.from(publicInput.operand)); + // the claim computation + UInt64.from(claim[0]).assertGreaterThanOrEqual(UInt64.from(publicInput.operand)); return new ClaimProofOutput({ claimCode: new Field(1) }); } @@ -217,8 +251,23 @@ const Program = ZkProgram({ } }); +log.info('Compiling the program'); await Program.compile(); +log.info('Building the proof'); +const claimProof = await Program.prove( + new ClaimProofPublicInput({ + credentialHash, + claimIndex: new Field(0), + operand: new Field(18) + }), + new ClaimProofSecretInput({ credential: vcred }) +); + +log.info('Claim proof done.'); + +// --- + // // for example somthing akin to: // [{ access: ["read"], From 5e6828701aeed997bd51c3ce031e266460333890 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Fri, 19 Apr 2024 21:26:34 +0200 Subject: [PATCH 23/34] Introduce credproofhelper and the final credential validity program. --- .../src/circuit/proveCredentialValidity.ts | 2 + .../src/circuit/vcred-proof.ts | 103 +++++++ .../src/credential.ts | 11 +- .../src/data/o1js/vcred.ts | 257 ++++++++---------- .../src/index.ts | 10 +- 5 files changed, 224 insertions(+), 159 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts new file mode 100644 index 0000000..57283ad --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts @@ -0,0 +1,2 @@ +const proveCredentialValidity = async(credential, Credential +); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts index e69de29..7f12fc2 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts @@ -0,0 +1,103 @@ +// TODO - documentation, +import { Bool, Field, Poseidon, PrivateKey, Provable, PublicKey, Struct, ZkProgram } from "o1js"; +import { VCredProofHelper, VCredStruct, VCredTypeId } from "src/data/o1js/vcred"; +import { Credential } from "src/data/transit/cred"; + +/** + + publicinputs: + - validity range + - signatureChallenge (for proving that the prover is the subject) + - credentialtypeId = hash (credentialStandardHash , issuer) + - proverIsSubject: Bool -- if the prover is the subject, proved via solving the signature challenge + - hasSubjectPubkey: Bool -- if `SubjectPubkey` contains the subject pubkey + + privateinputs: + - SubjectPrivkey: Privkey -- if `proverIsSubject` is true, contains the subject privkey + - credentialData: CredentialData -- the credential data + + publicOutputs: + - credentialHash: Field -- hash of the credential data + - SubjectPubkey: Pubkey -- if `hasSubjectPubkey` is true, contains the subject pubkey + +*/ +export class VCredProofPublicInput extends Struct ({ + validFrom: Field, + validTo: Field, + signatureChallenge: Field, + credentialTypeId: VCredTypeId, + proverIsSubject: Bool, +}) {} + +export class VCredProofPrivateInput extends Struct({ + subjectPrivkey: PrivateKey, + credentialData: VCredStruct, +}) {} + +export class VCredProofPublicOutput extends Struct({ + credentialHash: Field, + subjectPubkey: PublicKey +}) {} + + +export const ValidateVCredProgram = ZkProgram({ + name: 'ValidateVCred', + publicInput: VCredProofPublicInput, + publicOutput: VCredProofPublicOutput, + methods: { + validate: { + privateInputs: [ VCredProofPrivateInput ], + method( + publicInput: VCredProofPublicInput, + privateInput: VCredProofPrivateInput + ): VCredProofPublicOutput { + + const cred = privateInput.credentialData; + + // Verify the credential's signature. + cred.signature.verify(cred.issuer.pubkey, cred.dataToFields()) + + // Ensure the credential is within the validity period. + publicInput.validFrom.assertGreaterThanOrEqual( + cred.issuanceDate.unixTimestamp, + "Valid from date cannot be set before the credential's issuance date." + ); + publicInput.validTo.assertLessThanOrEqual( + cred.expirationDate.unixTimestamp, + "Valid to date cannot be set after the credential's expiration date." + ); + + const subjectPubkey = Provable.if( + publicInput.proverIsSubject, + cred.subject.pubkey, + privateInput.subjectPrivkey.toPublicKey() + ); + + // todo replace with challenge proof + subjectPubkey.assertEquals( + privateInput.subjectPrivkey.toPublicKey() + ) + + const credentialHash = Poseidon.hash(cred.dataToFields()) + + const ret = new VCredProofPublicOutput({ + credentialHash, + subjectPubkey + }); + return ret; + } + } + } +}); + +export class ValidateVCredProof extends ZkProgram.Proof(ValidateVCredProgram) {} + +// todo finish and accept public input arguments +const proveCredentialValidity = async ( credential: Credential, compileProver = true) : Promise => { + const proofHelper = VCredProofHelper.forCredential(credential); + + if (compileProver) { + await ValidateVCredProgram.compile(); + } +} + diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts index 7d09be8..80be23d 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -4,7 +4,7 @@ import { arraysAreEqual } from './helpers/utils.js'; import { Logger } from 'tslog'; import { CredSubjectId, Credential, CredentialData, CredentialSchema, CredentialStandard, IssuerId } from './data/transit/cred.js'; import { claimStandardHash } from './claim.js'; -import { mkVCredStruct } from './data/o1js/vcred.js'; +import { VCredDataStruct } from './data/o1js/vcred.js'; const log = new Logger({ name: 'credential.ts' }); @@ -42,6 +42,12 @@ export const credentialStandardHash = (standard: CredentialStandard): Field => { return Poseidon.hash([idHash, schemaHash]); }; +export const credentialDataHash = (data: CredentialData): Field => { + const flds = VCredDataStruct.fromTransit(data).toFields(); + return Poseidon.hash(flds); +} + + export const verifyAndIssueCredential = ( standard: CredentialStandard, @@ -54,10 +60,9 @@ export const verifyAndIssueCredential = log.debug('Entering verifyAndIssueCredential...'); log.debug('Converting the credential data to o1js fields.'); - const flds = mkVCredStruct(credentialData).toFields(); log.debug('Creating signature for the fields data'); - const signature = sign(flds); + const signature = sign([credentialDataHash(credentialData)]) // create the credential diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index 5ad0c5b..f50b3d9 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -1,30 +1,15 @@ -/* DEV: Due to misconception I've had on how Provable.witness and the level +/* DEV: Due to a misconception I've had on how Provable.witness and the level of dynamism that circuits can have, I have to re-write this module so that claims in the forms suitable for the zk program are represented as a MerkleMap. */ -import { Struct, Field, Signature } from 'o1js'; +import { Struct, Field, Signature, Poseidon } from 'o1js'; import { SignatureSchema, FieldSchema, UnixTimestamp } from './common.js'; -import { - ClaimMap, - Claims, - IFieldClaims, - mkClaimStruct, - mkClaims -} from './claim.js'; +import { ClaimMap } from './claim.js'; import { CredSubjectId, IssuerId, VCredId } from './ids.js'; import { Credential, CredentialData } from '../transit/cred.js'; -import { ILogObj, Logger } from 'tslog'; -const log = new Logger({name: 'data/o1js/vcred'}); - -// ===================== New - -/** - Claims will be reprensented in a merkle map so there's a reduction - in the complexity of the credential provable structure. - */ export const VCredStructUnsignedFields = { id: VCredId, issuer: IssuerId, @@ -35,158 +20,132 @@ export const VCredStructUnsignedFields = { credentialStandardHash: Field }; -export class VCredStructUnsigned2 extends Struct(VCredStructUnsignedFields) { - static Fields = VCredStructUnsignedFields; - - public toFields(): Field[] { - return [ - ...this.id.toFields(), - ...this.issuer.toFields(), - ...this.issuanceDate.toFields(), - ...this.expirationDate.toFields(), - ...this.subject.toFields(), - this.claimsMerkleMapRoot, - ...this.credentialStandardHash.toFields() - ]; - } +export const VCredStructFields = { + ...VCredStructUnsignedFields, + signature: Signature +}; - static fromTransit(t: CredentialData): VCredStructUnsigned2 { - const id = VCredId.fromTransit(t.id); - const issuer = IssuerId.fromTransit(t.issuer); - const issuanceDate = UnixTimestamp.fromTransit(t.issuanceDate); - const expirationDate = UnixTimestamp.fromTransit(t.expirationDate); - const subject = CredSubjectId.fromTransit(t.subject); - const claimsMerkleMapRoot = ClaimMap.fromTransit(t.claims).getRoot() - const credentialStandardHash = FieldSchema.parse( - t.credentialStandardHash - ); - - return new VCredStructUnsigned2({ - id, - issuer, - issuanceDate, - expirationDate, - subject, - claimsMerkleMapRoot, - credentialStandardHash - }); - } +export class VCredTypeId extends Field { + static forVCred(vcred: VCredDataStruct): VCredTypeId { + return new VCredTypeId(Poseidon.hash([ + vcred.credentialStandardHash, + ...vcred.issuer.pubkey.toFields() + ])); } +} +/** + This is an o1js representation of a credential data that is + to be signed by an issuer and treated as an actual credential, + in the form that is acceptable as input data for a proof. + */ +export class VCredDataStruct extends Struct(VCredStructUnsignedFields) { + static Fields = VCredStructUnsignedFields; + public toFields(): Field[] { + return [ + ...this.id.toFields(), + ...this.issuer.toFields(), + ...this.issuanceDate.toFields(), + ...this.expirationDate.toFields(), + ...this.subject.toFields(), + this.claimsMerkleMapRoot, + ...this.credentialStandardHash.toFields() + ]; + } - -// ===================== OLD -export interface IVCredStruct2 { - id: VCredId; - issuer: IssuerId; - issuanceDate: UnixTimestamp; - expirationDate: UnixTimestamp; - subject: CredSubjectId; - claims: IFieldClaims; - credentialStandardHash: Field; - toFields(): Field[]; - claimMarkleTreeIssuerSignature?: Signature; + static fromTransit(t: CredentialData): VCredDataStruct { + const id = VCredId.fromTransit(t.id); + const issuer = IssuerId.fromTransit(t.issuer); + const issuanceDate = UnixTimestamp.fromTransit(t.issuanceDate); + const expirationDate = UnixTimestamp.fromTransit(t.expirationDate); + const subject = CredSubjectId.fromTransit(t.subject); + const claimsMerkleMapRoot = ClaimMap.fromTransit(t.claims).getRoot(); + const credentialStandardHash = FieldSchema.parse(t.credentialStandardHash); + + return new VCredDataStruct({ + id, + issuer, + issuanceDate, + expirationDate, + subject, + claimsMerkleMapRoot, + credentialStandardHash + }); + } } -export function VCredStructUnsigned(claimSizes: number[]) { - const ClaimsType = Claims(claimSizes); - - const Data = { - id: VCredId, - issuer: IssuerId, - issuanceDate: UnixTimestamp, - expirationDate: UnixTimestamp, - subject: CredSubjectId, - claims: ClaimsType, - credentialStandardHash: Field - }; - - class BaseVCredStruct_ extends Struct(Data) implements IVCredStruct { - static Fields = Data; - - public toFields(): Field[] { - return [ - ...this.id.toFields(), - ...this.issuer.toFields(), - ...this.issuanceDate.toFields(), - ...this.expirationDate.toFields(), - ...this.subject.toFields(), - ...this.claims.toFields(), - ...this.credentialStandardHash.toFields() - ]; - } +/** + This is an o1js representation of the credential. + This is the representation of the credential that is + used in the proofs. + */ +export class VCredStruct extends Struct(VCredStructFields) { + public dataToFields() { + return this.signedData().toFields(); + } - static fromTransit(t: CredentialData): BaseVCredStruct_ { - const id = VCredId.fromTransit(t.id); - const issuer = IssuerId.fromTransit(t.issuer); - const issuanceDate = UnixTimestamp.fromTransit(t.issuanceDate); - const expirationDate = UnixTimestamp.fromTransit(t.expirationDate); - const subject = CredSubjectId.fromTransit(t.subject); - const claims = mkClaims(Object.values(t.claims).map(mkClaimStruct)); - const credentialStandardHash = FieldSchema.parse( - t.credentialStandardHash - ); - - return new BaseVCredStruct_({ - id, - issuer, - issuanceDate, - expirationDate, - subject, - claims, - credentialStandardHash - }); - } + public signedData(): VCredDataStruct { + return new VCredDataStruct(this); } - return BaseVCredStruct_; -} + public toFields() { + return [...this.dataToFields(), ...this.signature.toFields()]; + } -export function VCredStruct(claimSizes: number[]) { - const BaseVCredStructType = VCredStructUnsigned(claimSizes); + static fromTransit(t: Credential): VCredStruct { + const base = VCredDataStruct.fromTransit(t); + const signature = SignatureSchema.parse(t.signature); - const Fields = { ...BaseVCredStructType.Fields, signature: Signature }; + return new VCredStruct({ ...base, signature }); + } +} - class VCredStruct_ extends Struct(Fields) implements IVCredStruct { - static Fields = Fields; +/** + Claims will be reprensented in a merkle map so there's a reduction + in the complexity of the credential provable structure.a - public contentToFields() { - return new BaseVCredStructType(this).toFields(); - } + What we need in order to have a convenient interface for creating proofs is: - public toFields() { - return [...this.contentToFields(), ...this.signature.toFields()]; - } + From a transit credential you get a structure that: - static fromTransit(t: Credential): VCredStruct_ { - const base = BaseVCredStructType.fromTransit(t); - const signature = SignatureSchema.parse(t.signature); + - creates the merklemap of claims - `ClaimMap` + - gets the credential in the form acceptable as proof input data + that is ready to be signed by issuer - return new VCredStruct_({ ...base, signature }); - } - } +*/ - return VCredStruct_; -} +export class VCredProofHelper { + public readonly claims: ClaimMap; + public readonly vcred: VCredStruct; -export function mkVCredStruct(credentialData: CredentialData): IVCredStruct; -export function mkVCredStruct(credential: Credential): IVCredStruct; + public get vcredHash(): Field { + return Poseidon.hash(this.vcred.toFields()); + } -export function mkVCredStruct(credential: Credential | CredentialData): IVCredStruct { - // credential has a signature as opposed to credentialData - log.debug("Creating VCredStruct from credential transit data.") - log.debug('credential', credential); - const claims = credential.claims; + private constructor(public readonly credential: Credential) { + this.claims = ClaimMap.fromTransit(credential.claims); + this.vcred = VCredStruct.fromTransit(credential); + this.initialValidityCheck(); + } + public static forCredential(t: Credential): VCredProofHelper { + return new VCredProofHelper(t); + } - const claimSizes = Object.values(claims).map( - (claim) => claim.fieldsValue.length - ); - log.debug('claimSizes', claimSizes); + private initialValidityCheck() { + // claim merkle root was created in an unexpected way + if (!this.claims.getRoot().equals(this.vcred.claimsMerkleMapRoot)) { + throw new Error('Claims root does not match the credential claims root'); + } - if ('signature' in credential) { - return VCredStruct(claimSizes).fromTransit(credential); - } else { - return VCredStructUnsigned(claimSizes).fromTransit(credential); + // signer signature is invalid + const credentialDataHash = Poseidon.hash(this.vcred.dataToFields()); + if ( + !this.vcred.signature + .verify(this.vcred.issuer.pubkey, [credentialDataHash]) + .equals(true) + ) { + throw new Error('Credential signature is invalid'); + } } } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index f77129e..f3dfe0e 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -8,7 +8,7 @@ import { DateTimeSchema, FieldSchema } from './data/transit/common.js'; import { CredSubjectId, CredSubjectIdSchema, Credential, CredentialData, CredentialStandard, VCredIdSchema } from './data/transit/cred.js'; import { credentialStandardHash, verifyAndIssueCredential } from './credential.js'; import { CredentialStore, MockStorage } from './credential-store.js'; -import { VCredStruct } from './data/o1js/vcred.js'; +import { VCredProofHelper, VCredStruct } from './data/o1js/vcred.js'; const log = new Logger({ name: 'index.ts prototyping' }); @@ -117,13 +117,9 @@ if (!credential) { } // for proofs we need credential in o1js struct form -// lets first assume fixed size claim data -class VCred extends VCredStruct([1]) {} - -log.info('From transit'); -const vcred = VCred.fromTransit(credential); -const credentialHash = Poseidon.hash(vcred.toFields()); +log.info('Setting up o1js proof helper for the credential'); +const vcredproofhelper = VCredProofHelper.forCredential(credential); log.info('(later) Requesting a resource access schema'); From 235b1de71c38fd0d5a19ae880ee89bf0adb0ac46 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 20 Apr 2024 19:45:10 +0200 Subject: [PATCH 24/34] Finish the improved credential validity proving module --- .../src/circuit/proveCredentialValidity.ts | 2 - .../src/circuit/vcred-proof.ts | 109 +++++++++++++----- 2 files changed, 82 insertions(+), 29 deletions(-) delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts deleted file mode 100644 index 57283ad..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/proveCredentialValidity.ts +++ /dev/null @@ -1,2 +0,0 @@ -const proveCredentialValidity = async(credential, Credential -); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts index 7f12fc2..8e5dfda 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts @@ -1,45 +1,49 @@ -// TODO - documentation, +/** + * This module contains the logic for proving the validity of a credential. + * It provides a convenient interface for creating proofs. +*/ + +import { DateTime } from "luxon"; import { Bool, Field, Poseidon, PrivateKey, Provable, PublicKey, Struct, ZkProgram } from "o1js"; +import { UnixTimestamp } from "src/data/o1js/common"; import { VCredProofHelper, VCredStruct, VCredTypeId } from "src/data/o1js/vcred"; import { Credential } from "src/data/transit/cred"; /** - - publicinputs: - - validity range - - signatureChallenge (for proving that the prover is the subject) - - credentialtypeId = hash (credentialStandardHash , issuer) - - proverIsSubject: Bool -- if the prover is the subject, proved via solving the signature challenge - - hasSubjectPubkey: Bool -- if `SubjectPubkey` contains the subject pubkey - - privateinputs: - - SubjectPrivkey: Privkey -- if `proverIsSubject` is true, contains the subject privkey - - credentialData: CredentialData -- the credential data - - publicOutputs: - - credentialHash: Field -- hash of the credential data - - SubjectPubkey: Pubkey -- if `hasSubjectPubkey` is true, contains the subject pubkey - -*/ + * The public input to the proof of a credential's validity. + */ export class VCredProofPublicInput extends Struct ({ - validFrom: Field, - validTo: Field, - signatureChallenge: Field, + validFrom: UnixTimestamp, + validTo: UnixTimestamp, credentialTypeId: VCredTypeId, proverIsSubject: Bool, }) {} +/** + * The private input to the proof of a credential's validity. + */ export class VCredProofPrivateInput extends Struct({ subjectPrivkey: PrivateKey, credentialData: VCredStruct, }) {} +/** + * The public output of the proof of a credential's validity. + */ export class VCredProofPublicOutput extends Struct({ credentialHash: Field, subjectPubkey: PublicKey }) {} +/** + * The actual ZkProgram for proving the validity of a credential. + * Some tests that are used to build the proofs constraints are: + * - The credential type matches the expected type. + * - The credential's issuer signature is valid. + * - The credential is within the validity period. + * - The prover is the subject of the credential. (optional) + */ export const ValidateVCredProgram = ZkProgram({ name: 'ValidateVCred', publicInput: VCredProofPublicInput, @@ -54,26 +58,34 @@ export const ValidateVCredProgram = ZkProgram({ const cred = privateInput.credentialData; + // Ensure the credential type matches the expected type. + const actualCredType = VCredTypeId.forVCred(cred) + publicInput.credentialTypeId.assertEquals( + actualCredType, + "Credential type does not match the expected type." + ); + // Verify the credential's signature. cred.signature.verify(cred.issuer.pubkey, cred.dataToFields()) // Ensure the credential is within the validity period. - publicInput.validFrom.assertGreaterThanOrEqual( + publicInput.validFrom.unixTimestamp.assertGreaterThanOrEqual( cred.issuanceDate.unixTimestamp, "Valid from date cannot be set before the credential's issuance date." ); - publicInput.validTo.assertLessThanOrEqual( + publicInput.validTo.unixTimestamp.assertLessThanOrEqual( cred.expirationDate.unixTimestamp, "Valid to date cannot be set after the credential's expiration date." ); + // if `proverIsSubject` is false, then + // make the next assertion trivially true const subjectPubkey = Provable.if( publicInput.proverIsSubject, cred.subject.pubkey, privateInput.subjectPrivkey.toPublicKey() ); - // todo replace with challenge proof subjectPubkey.assertEquals( privateInput.subjectPrivkey.toPublicKey() ) @@ -92,12 +104,55 @@ export const ValidateVCredProgram = ZkProgram({ export class ValidateVCredProof extends ZkProgram.Proof(ValidateVCredProgram) {} -// todo finish and accept public input arguments -const proveCredentialValidity = async ( credential: Credential, compileProver = true) : Promise => { - const proofHelper = VCredProofHelper.forCredential(credential); + +export type SecretInput = { + credential: Credential, + subjectPrivkey: PrivateKey, +} + +export type CredentialValidityProofParameters = { + credentialTypeId: VCredTypeId, + validFrom: DateTime, + validTo: DateTime, + proverIsSubject: boolean, +} + +/** + * Proves the validity of a credential. Details of how the will be constructed can be altered by the parameters. + * + * @param secretInput The secret input to the proof. This includes the credential and the subject's private key. + * @param params The parameters for the proof. This includes the credential type ID, the validity range, and whether the prover should be checked for also being the credential's subject. + * @param compileProver Whether to compile the prover before running the proof. + * @returns The proof of the credential's validity. + */ +export const proveCredentialValidity = + async ( + secretInput: SecretInput, + params: CredentialValidityProofParameters, + compileProver = true) +: Promise => { + + // convert parameters to public input + const publicInput = new VCredProofPublicInput({ + validFrom: new UnixTimestamp({unixTimestamp: new Field(params.validFrom.toUTC().toUnixInteger())}), + validTo: new UnixTimestamp({ unixTimestamp: new Field(params.validTo.toUTC().toUnixInteger()) }), + credentialTypeId: params.credentialTypeId, + proverIsSubject: new Bool(params.proverIsSubject) + }); + + const proofHelper = VCredProofHelper.forCredential(secretInput.credential); + + const privateInput = new VCredProofPrivateInput({ + subjectPrivkey: secretInput.subjectPrivkey, + credentialData: proofHelper.vcred + }); if (compileProver) { await ValidateVCredProgram.compile(); } + + const prog = await ValidateVCredProgram.validate(publicInput, privateInput); + + return prog; } From a6e98d91fab50bce7d99de1838cf245380bf5309 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 20 Apr 2024 21:35:39 +0200 Subject: [PATCH 25/34] Add claim-proof module Field1, Field2, String (unfinished) --- .../src/circuit/claim-proof.ts | 579 ++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts new file mode 100644 index 0000000..1e89d29 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts @@ -0,0 +1,579 @@ +import { + Bool, + CircuitString, + Field, + MerkleMapWitness, + Poseidon, + SelfProof, + Struct, + ZkProgram +} from 'o1js'; +import { VCredDataStruct } from 'src/data/o1js/vcred.js'; + +// how to be smart about diffrent claim data types? + +export class ClaimDataField1 extends Struct({ + data: Field +}) { + public toFields(): Field[] { + return [this.data]; + } +} + +// the programs public input +export class ClaimProofPublicInput extends Struct({ + credentialHash: Field, + claimMerkleMapRootHash: Field, + operand: Field, + methodId: Field +}) {} + +// the programs secret input +export class ClaimProofPrivateInput extends Struct({ + credential: VCredDataStruct, + claimWitness: MerkleMapWitness, + claimData: ClaimDataField1 +}) {} + +/** The cummulative output hash of the proof. + * This exists so that one can recursively rollup proofs + * about claims. + * Then the output hash can be used to retrace the proved + * computation. + */ +export class CummulativeClaimProofHash extends Field { + static fromPublicInput( + publicInput: ClaimProofPublicInput + ): CummulativeClaimProofHash { + return new CummulativeClaimProofHash( + Poseidon.hash([ + publicInput.credentialHash, + publicInput.claimMerkleMapRootHash, + publicInput.operand, + publicInput.methodId + ]) + ); + } + + /** Monoidal append operation for the cummulative hash */ + public append(publicInput: ClaimProofPublicInput) { + const newHash = CummulativeClaimProofHash.fromPublicInput(publicInput); + return new CummulativeClaimProofHash(Poseidon.hash([this, newHash])); + } + + /** Auxilliary function to check if the proof cummulative hash + corresponds to the set of public inputs determinining + how the proof is being constructed. + */ + public verify(publicInputs: ClaimProofPublicInput[]): boolean { + const l = publicInputs.length; + if (l === 0) { + return false; + } + let cumm = CummulativeClaimProofHash.fromPublicInput(publicInputs[0]); + for (let i = 1; i < l; i++) { + cumm = cumm.append(publicInputs[i]); + } + + return cumm.equals(this).toBoolean(); + } + + public toFields(): Field[] { + return [this]; + } +} + +export class ClaimProofOutput extends Struct({ + cummulativeHash: CummulativeClaimProofHash +}) {} + + +const claimDataField1MethodHelper = ( + methodName: string, + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput, + theClaimCheck: ({claimData, operand} : {claimData: Field, operand: Field}) => Bool) => { + + // verify method id + const methodId = Poseidon.hash( + CircuitString.fromString(methodName).toFields() + ); + methodId.assertEquals( + publicInput.methodId, + 'Invalid method identifier' + ); + + // verify credential hash + publicInput.credentialHash.assertEquals( + Poseidon.hash(privateInput.credential.toFields()) + ); + + // merkle witness verification + const claimHash = Poseidon.hash(privateInput.claimData.toFields()); + const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash) + publicInput.claimMerkleMapRootHash.assertEquals(root); + + // at this point we know that the claim data in fact comes + // from a credential of the given hash + + // now comes the actual verification of the claim data + // for this methodId, which is an equality check + + // we will assume that the claim data is a single field + // and that the operand is a field + theClaimCheck({ + claimData: privateInput.claimData.data, + operand: publicInput.operand + }).assertTrue('Claim data does not match operand'); + } + +// lets for now assume that the claim data is a field +export const ValidateClaimField1Program = ZkProgram({ + name: 'ValidateClaimField1', + publicInput: ClaimProofPublicInput, + publicOutput: ClaimProofOutput, + methods: { + baseEqual: { + privateInputs: [ClaimProofPrivateInput], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput + ): ClaimProofOutput { + + claimDataField1MethodHelper( + 'baseEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.equals(operand) + ); + + + const cummulativeHash = + CummulativeClaimProofHash.fromPublicInput(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + cummulativeEqual: { + privateInputs: [SelfProof, ClaimProofPrivateInput], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofPrivateInput + ): ClaimProofOutput { + + earlierProof.verify(); + + claimDataField1MethodHelper( + 'cummulativeEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.equals(operand) + ); + + const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + baseGreaterThanOrEqual: { + privateInputs: [ClaimProofPrivateInput], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput + ): ClaimProofOutput { + + claimDataField1MethodHelper( + 'baseGreaterThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.greaterThanOrEqual(operand) + ); + + const cummulativeHash = + CummulativeClaimProofHash.fromPublicInput(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + cummulativeGreaterThanOrEqual: { + privateInputs: [SelfProof, ClaimProofPrivateInput], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofPrivateInput + ): ClaimProofOutput { + + earlierProof.verify(); + + claimDataField1MethodHelper( + 'cummulativeGreaterThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.greaterThanOrEqual(operand) + ); + + const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + } + }, + baseLessThanOrEqual: { + privateInputs: [ClaimProofPrivateInput], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput + ): ClaimProofOutput { + + claimDataField1MethodHelper( + 'baseLessThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.lessThanOrEqual(operand) + ); + + const cummulativeHash = + CummulativeClaimProofHash.fromPublicInput(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + cummulativeLessThanOrEqual: { + privateInputs: [SelfProof, ClaimProofPrivateInput], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofPrivateInput + ): ClaimProofOutput { + + earlierProof.verify(); + + claimDataField1MethodHelper( + 'cummulativeLessThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.lessThanOrEqual(operand) + ); + + const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + } + } + } +}); + +export const ValidateClaimField1Proof = ZkProgram.Proof(ValidateClaimField1Program); + +// now the same but for a claim data that has two fields: + +export class ClaimDataField2 extends Struct({ + data1: Field, + data2: Field +}) { + public toFields(): Field[] { + return [this.data1, this.data2]; + } +} + +export class ClaimProofPrivateInput2 extends Struct({ + credential: VCredDataStruct, + claimWitness: MerkleMapWitness, + claimData: ClaimDataField2 +}) {} + +export const claimDataField2MethodHelper = ( + methodName: string, + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput2, + theClaimCheck: ({claimData, operand} : {claimData: ClaimDataField2, operand: Field}) => Bool) => { + + // verify method id + const methodId = Poseidon.hash( + CircuitString.fromString(methodName).toFields() + ); + methodId.assertEquals( + publicInput.methodId, + 'Invalid method identifier' + ); + + // verify credential hash + publicInput.credentialHash.assertEquals( + Poseidon.hash(privateInput.credential.toFields()) + ); + + // merkle witness verification + const claimHash = Poseidon.hash(privateInput.claimData.toFields()); + const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash) + publicInput.claimMerkleMapRootHash.assertEquals(root); + + // at this point we know that the claim data in fact comes + // from a credential of the given hash + + // now comes the actual verification of the claim data + // for this methodId, which is an equality check + + // we will assume that the claim data is a single field + // and that the operand is a field + theClaimCheck({ + claimData: privateInput.claimData, + operand: publicInput.operand + }).assertTrue('Claim data does not match operand'); + } + +export const ValidateClaimField2Program = ZkProgram({ + name: 'ValidateClaimField2', + publicInput: ClaimProofPublicInput, + publicOutput: ClaimProofOutput, + methods: { + baseEqual: { + privateInputs: [ClaimProofPrivateInput2], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput2 + ): ClaimProofOutput { + + claimDataField2MethodHelper( + 'baseEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data1.equals(operand) + ); + + const cummulativeHash = + CummulativeClaimProofHash.fromPublicInput(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + cummulativeEqual: { + privateInputs: [SelfProof, ClaimProofPrivateInput2], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofPrivateInput2 + ): ClaimProofOutput { + + earlierProof.verify(); + + claimDataField2MethodHelper( + 'cummulativeEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data1.equals(operand) + ); + + const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + baseGreaterThanOrEqual: { + privateInputs: [ClaimProofPrivateInput2], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput2 + ): ClaimProofOutput { + + claimDataField2MethodHelper( + 'baseGreaterThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data1.greaterThanOrEqual(operand) + ); + + const cummulativeHash = + CummulativeClaimProofHash.fromPublicInput(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + cummulativeGreaterThanOrEqual: { + privateInputs: [SelfProof, ClaimProofPrivateInput2], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofPrivateInput2 + ): ClaimProofOutput { + + earlierProof.verify(); + + claimDataField2MethodHelper( + 'cummulativeGreaterThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data1.greaterThanOrEqual(operand) + ); + + const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + } + }, + baseLessThanOrEqual: { + privateInputs: [ClaimProofPrivateInput2], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInput2 + ): ClaimProofOutput { + + claimDataField2MethodHelper( + 'baseLessThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data1.lessThanOrEqual(operand) + ); + + const cummulativeHash = + CummulativeClaimProofHash.fromPublicInput(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + cummulativeLessThanOrEqual: { + privateInputs: [SelfProof, ClaimProofPrivateInput2], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofPrivateInput2 + ): ClaimProofOutput { + + earlierProof.verify(); + + claimDataField2MethodHelper( + 'cummulativeLessThanOrEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data1.lessThanOrEqual(operand) + ); + + const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + } + } + } +}); + +export const ValidateClaimField2Proof = ZkProgram.Proof(ValidateClaimField2Program); + + +// now the same but for a claim data that is a citcuit string: + +export class ClaimDataString extends Struct({ + data: CircuitString +}) { + public toFields(): Field[] { + return [this.data]; + } +} + +export class ClaimProofPrivateInputString extends Struct({ + credential: VCredDataStruct, + claimWitness: MerkleMapWitness, + claimData: ClaimDataString +}) {} + +export const claimDataStringMethodHelper = ( + methodName: string, + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInputString, + theClaimCheck: ({claimData, operand} : {claimData: ClaimDataString, operand: Field}) => Bool) => { + + // verify method id + const methodId = Poseidon.hash( + CircuitString.fromString(methodName).toFields() + ); + methodId.assertEquals( + publicInput.methodId, + 'Invalid method identifier' + ); + + // verify credential hash + publicInput.credentialHash.assertEquals( + Poseidon.hash(privateInput.credential.toFields()) + ); + + // merkle witness verification + const claimHash = Poseidon.hash(privateInput.claimData.toFields()); + const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash) + publicInput.claimMerkleMapRootHash.assertEquals(root); + + // at this point we know that the claim data in fact comes + // from a credential of the given hash + + // now comes the actual verification of the claim data + // for this methodId, which is an equality check + + // we will assume that the claim data is a single field + // and that the operand is a field + theClaimCheck({ + claimData: privateInput.claimData, + operand: publicInput.operand + }).assertTrue('Claim data does not match operand'); + } + +// TODO: +// this one will be better offering proving membership in a set, or +// or proving that string does not belong to a set +// or proving that a string is a substring of another string +export const ValidateClaimStringProgram = ZkProgram({ + name: 'ValidateClaimString', + publicInput: ClaimProofPublicInput, + publicOutput: ClaimProofOutput, + methods: { + baseEqual: { + privateInputs: [ClaimProofPrivateInputString], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofPrivateInputString + ): ClaimProofOutput { + + claimDataStringMethodHelper( + 'baseEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data.equals(operand) + ); + + const cummulativeHash = + CummulativeClaimProofHash.fromPublicInput(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + cummulativeEqual: { + privateInputs: [SelfProof, ClaimProofPrivateInputString], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofPrivateInputString + ): ClaimProofOutput { + + earlierProof.verify(); + + claimDataStringMethodHelper( + 'cummulativeEqual', + publicInput, + privateInput, + ({claimData, operand}) => claimData.data.equals(operand) + ); + + const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); + const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); + return ret; + + } + }, + } + +); From da9c55bb90c26899a711b99124175ada0443a9b4 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Mon, 22 Apr 2024 14:37:11 +0200 Subject: [PATCH 26/34] Fix ClaimId bug. --- .../src/data/o1js/claim.ts | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts index 0360e28..03ad3d3 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts @@ -5,12 +5,16 @@ Which means that most of this module will be gone */ -import { Struct, Provable, Field, MerkleMapWitness, MerkleMap } from 'o1js'; import { - arraysAreEqual, - ftn, - mapObject, -} from '../../helpers/utils.js'; + Struct, + Provable, + Field, + MerkleMapWitness, + MerkleMap, + Poseidon, + CircuitString +} from 'o1js'; +import { arraysAreEqual, ftn, mapObject } from '../../helpers/utils.js'; import { FieldsSchema } from './common.js'; import { Claim, CredentialDataClaims } from '../transit/cred.js'; @@ -31,7 +35,7 @@ import { Claim, CredentialDataClaims } from '../transit/cred.js'; export class ClaimId extends Field { static fromTransit(claim: Claim): ClaimId { const claimId = `${claim.name}${claim.standard.standardId}${claim.fieldsValue.length}`; - return new Field(claimId); + return Poseidon.hash(CircuitString.fromString(claimId).toFields()); } } @@ -49,13 +53,13 @@ type ClaimData = { export class ClaimMap { public readonly claimIdMap: Record; - protected constructor(public readonly claims: Record, - public readonly merkleMap: MerkleMap) { - this.claimIdMap = - mapObject(claims, ({ value: newValue }) => { - return { newKey: newValue.claimId.toString(), newValue } - } - ); + protected constructor( + public readonly claims: Record, + public readonly merkleMap: MerkleMap + ) { + this.claimIdMap = mapObject(claims, ({ value: newValue }) => { + return { newKey: newValue.claimId.toString(), newValue }; + }); } public getRoot() { From 9a1cb6ed4858c279f447d4cc8a01895a4051210d Mon Sep 17 00:00:00 2001 From: adamczykm Date: Mon, 22 Apr 2024 19:59:33 +0200 Subject: [PATCH 27/34] Split claim proving (naive approach) and implement a generic approach. --- .../src/circuit/claim-field1-proving.ts | 292 +++++++++ .../src/circuit/claim-field2-proving.ts | 333 ++++++++++ .../src/circuit/claim-proof.ts | 579 ------------------ .../src/circuit/generic-claim-proving.ts | 208 +++++++ .../src/credential.ts | 2 +- .../src/data/o1js/vcred.test.ts | 276 ++++----- .../src/index.ts | 147 +++-- 7 files changed, 1053 insertions(+), 784 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field1-proving.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field2-proving.ts delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field1-proving.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field1-proving.ts new file mode 100644 index 0000000..9b986c9 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field1-proving.ts @@ -0,0 +1,292 @@ +import { + Bool, + CircuitString, + Field, + MerkleMapWitness, + Poseidon, + SelfProof, + Struct, + ZkProgram +} from 'o1js'; +import { VCredDataStruct } from '../data/o1js/vcred.js'; + +// how to be smart (generic) about different claim data types? + +// the current approach is overly naive and does not use the +// type system to its full potential +// the idea is to have a generic claim data type with which +// claim proving programs can be defined +// Dev TODO later +// the ideal solution would involve generic claim data +// and generic methods that one wants to support +// to generate zkprograms that work well with credential structure +// and do all the necessary checks on claims + +export class ClaimField1Data extends Struct({ + data: Field +}) { + public toFields(): Field[] { + return [this.data]; + } +} + + + +// the programs public input +export class ClaimField1ProofPublicInput extends Struct({ + credentialHash: Field, + claimMerkleMapRootHash: Field, + operand: Field, + methodId: Field +}) {} + +// the programs secret input +export class ClaimField1ProofPrivateInput extends Struct({ + credential: VCredDataStruct, + claimWitness: MerkleMapWitness, + claimData: ClaimField1Data +}) {} + +/** The cummulative output hash of the proof. + * This exists so that one can recursively rollup proofs + * about claims. + * Then the output hash can be used to retrace the proved + * computation. + */ +export class CummulativeClaimField1ProofHash extends Field { + static fromPublicInput( + publicInput: ClaimField1ProofPublicInput + ): CummulativeClaimField1ProofHash { + return new CummulativeClaimField1ProofHash( + Poseidon.hash([ + publicInput.credentialHash, + publicInput.claimMerkleMapRootHash, + publicInput.operand, + publicInput.methodId + ]) + ); + } + + /** Monoidal append operation for the cummulative hash */ + public append(publicInput: ClaimField1ProofPublicInput) { + const newHash = + CummulativeClaimField1ProofHash.fromPublicInput(publicInput); + return new CummulativeClaimField1ProofHash(Poseidon.hash([this, newHash])); + } + + /** Auxilliary function to check if the proof cummulative hash + corresponds to the set of public inputs determinining + how the proof is being constructed. + */ + public verify(publicInputs: ClaimField1ProofPublicInput[]): boolean { + const l = publicInputs.length; + if (l === 0) { + return false; + } + let cumm = CummulativeClaimField1ProofHash.fromPublicInput(publicInputs[0]); + for (let i = 1; i < l; i++) { + cumm = cumm.append(publicInputs[i]); + } + + return cumm.equals(this).toBoolean(); + } + + public toFields(): Field[] { + return [this]; + } +} + +export class ClaimField1ProofOutput extends Struct({ + cummulativeHash: CummulativeClaimField1ProofHash +}) {} + +const claimDataField1MethodHelper = ( + methodName: string, + publicInput: ClaimField1ProofPublicInput, + privateInput: ClaimField1ProofPrivateInput, + theClaimCheck: ({ + claimData, + operand + }: { + claimData: ClaimField1Data, + operand: Field; + }) => Bool +) => { + // verify method id + const methodId = Poseidon.hash( + CircuitString.fromString(methodName).toFields() + ); + methodId.assertEquals(publicInput.methodId, 'Invalid method identifier'); + + // verify credential hash + publicInput.credentialHash.assertEquals( + Poseidon.hash(privateInput.credential.toFields()) + ); + + // merkle witness verification + const claimHash = Poseidon.hash(privateInput.claimData.toFields()); + const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash); + publicInput.claimMerkleMapRootHash.assertEquals(root); + + // at this point we know that the claim data in fact comes + // from a credential of the given hash + + // now comes the actual verification of the claim data + // for this methodId, which is an equality check + + // we will assume that the claim data is a single field + // and that the operand is a field + theClaimCheck({ + claimData: privateInput.claimData, + operand: publicInput.operand + }).assertTrue('Claim data does not match operand'); +}; + +const cummulativeHashHelper = ( + earlierProof: SelfProof, + publicInput: ClaimField1ProofPublicInput +): ClaimField1ProofOutput => { + const oldCummulativeHash = earlierProof.publicOutput + .cummulativeHash as CummulativeClaimField1ProofHash; + const cummulativeHash: CummulativeClaimField1ProofHash = + oldCummulativeHash.append(publicInput); + const ret: ClaimField1ProofOutput = new ClaimField1ProofOutput({ + cummulativeHash + }); + return ret; +}; + +const baseCummulativeHashHelper = ( + publicInput: ClaimField1ProofPublicInput +): ClaimField1ProofOutput => { + const cummulativeHash = + CummulativeClaimField1ProofHash.fromPublicInput(publicInput); + + const ret: ClaimField1ProofOutput = new ClaimField1ProofOutput({ + cummulativeHash + }); + return ret; +}; + +// lets for now assume that the claim data is a field +export const Validate1FieldClaimProgram = ZkProgram({ + name: 'Validate1FieldClaim', + publicInput: ClaimField1ProofPublicInput, + publicOutput: ClaimField1ProofOutput, + methods: { + baseEqual: { + privateInputs: [ClaimField1ProofPrivateInput], + method( + publicInput: ClaimField1ProofPublicInput, + privateInput: ClaimField1ProofPrivateInput + ): ClaimField1ProofOutput { + claimDataField1MethodHelper( + 'baseEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.data.equals(operand) + ); + + return baseCummulativeHashHelper(publicInput); + } + }, + cummulativeEqual: { + privateInputs: [SelfProof, ClaimField1ProofPrivateInput], + method( + publicInput: ClaimField1ProofPublicInput, + earlierProof: SelfProof< + ClaimField1ProofPublicInput, + ClaimField1ProofOutput + >, + privateInput: ClaimField1ProofPrivateInput + ): ClaimField1ProofOutput { + earlierProof.verify(); + + claimDataField1MethodHelper( + 'cummulativeEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.data.equals(operand) + ); + + return cummulativeHashHelper(earlierProof, publicInput); + } + }, + baseGreaterThanOrEqual: { + privateInputs: [ClaimField1ProofPrivateInput], + method( + publicInput: ClaimField1ProofPublicInput, + privateInput: ClaimField1ProofPrivateInput + ): ClaimField1ProofOutput { + claimDataField1MethodHelper( + 'baseGreaterThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.data.greaterThanOrEqual(operand) + ); + + return baseCummulativeHashHelper(publicInput); + } + }, + cummulativeGreaterThanOrEqual: { + privateInputs: [SelfProof, ClaimField1ProofPrivateInput], + method( + publicInput: ClaimField1ProofPublicInput, + earlierProof: SelfProof< + ClaimField1ProofPublicInput, + ClaimField1ProofOutput + >, + privateInput: ClaimField1ProofPrivateInput + ): ClaimField1ProofOutput { + earlierProof.verify(); + + claimDataField1MethodHelper( + 'cummulativeGreaterThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.data.greaterThanOrEqual(operand) + ); + + return cummulativeHashHelper(earlierProof, publicInput); + } + }, + baseLessThanOrEqual: { + privateInputs: [ClaimField1ProofPrivateInput], + method( + publicInput: ClaimField1ProofPublicInput, + privateInput: ClaimField1ProofPrivateInput + ): ClaimField1ProofOutput { + claimDataField1MethodHelper( + 'baseLessThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.data.lessThanOrEqual(operand) + ); + + return baseCummulativeHashHelper(publicInput); + } + }, + cummulativeLessThanOrEqual: { + privateInputs: [SelfProof, ClaimField1ProofPrivateInput], + method( + publicInput: ClaimField1ProofPublicInput, + earlierProof: SelfProof< + ClaimField1ProofPublicInput, + ClaimField1ProofOutput + >, + privateInput: ClaimField1ProofPrivateInput + ): ClaimField1ProofOutput { + earlierProof.verify(); + + claimDataField1MethodHelper( + 'cummulativeLessThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.data.lessThanOrEqual(operand) + ); + + return cummulativeHashHelper(earlierProof, publicInput); + } + } + } +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field2-proving.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field2-proving.ts new file mode 100644 index 0000000..0ca1428 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-field2-proving.ts @@ -0,0 +1,333 @@ +import { + CircuitString, + Field, + Poseidon, + Provable, + SelfProof, + Struct +} from 'o1js'; +import { MerkleMapWitness, ZkProgram, Bool } from 'o1js'; +import { VCredDataStruct } from '../data/o1js/vcred.js'; + +// how to be smart (generic) about different claim data types? + +// the current approach is overly naive and does not use the +// type system to its full potential +// the idea is to have a generic claim data type with which +// claim proving programs can be defined +// Dev TODO later +// the ideal solution would involve generic claim data +// and generic methods that one wants to support +// to generate zkprograms that work well with credential structure +// and do all the necessary checks on claims +// Define a new class for claim data with two fields + +export class ClaimField2Data extends Struct({ + data1: Field, + data2: Field +}) { + public toFields(): Field[] { + return [this.data1, this.data2]; + } + + public equals(other: ClaimField2Data): Bool { + return this.data1.equals(other.data1).and(this.data2.equals(other.data2)); + } +} + +// static methods in Struct classes cause type level issues +export function ClaimField2Data_fromFields( + fields: Field[], + sliceOffset = 0 +): ClaimField2Data { + return new ClaimField2Data({ + data1: fields[sliceOffset], + data2: fields[sliceOffset + 1] + }); +} + +/** The cummulative output hash of the proof. + * This exists so that one can recursively rollup proofs + * about claims. + * Then the output hash can be used to retrace the proved + * computation. + */ +export class CummulativeClaimField2ProofHash extends Field { + static fromPublicInput( + publicInput: ClaimField2ProofPublicInput + ): CummulativeClaimField2ProofHash { + return new CummulativeClaimField2ProofHash( + Poseidon.hash([ + publicInput.credentialHash, + publicInput.claimMerkleMapRootHash, + ...publicInput.operand.toFields(), + publicInput.methodId + ]) + ); + } + + /** Monoidal append operation for the cummulative hash */ + public append(publicInput: ClaimField2ProofPublicInput) { + const newHash = + CummulativeClaimField2ProofHash.fromPublicInput(publicInput); + return new CummulativeClaimField2ProofHash(Poseidon.hash([this, newHash])); + } + + /** Auxilliary function to check if the proof cummulative hash + corresponds to the set of public inputs determinining + how the proof is being constructed. + */ + public verify(publicInputs: ClaimField2ProofPublicInput[]): boolean { + const l = publicInputs.length; + if (l === 0) { + return false; + } + let cumm = CummulativeClaimField2ProofHash.fromPublicInput(publicInputs[0]); + for (let i = 1; i < l; i++) { + cumm = cumm.append(publicInputs[i]); + } + + return cumm.equals(this).toBoolean(); + } + + public toFields(): Field[] { + return [this]; + } +} + +// Extend the Proof Input structures to include the new ClaimField2Data +export class ClaimField2ProofPrivateInput extends Struct({ + credential: VCredDataStruct, + claimWitness: MerkleMapWitness, + claimData: ClaimField2Data // Changed to use ClaimField2Data +}) {} + +// the programs public input +export class ClaimField2ProofPublicInput extends Struct({ + credentialHash: Field, + claimMerkleMapRootHash: Field, + operand: ClaimField2Data, // Changed to use ClaimField2Data + methodId: Field +}) {} + +export class ClaimField2ProofOutput extends Struct({ + cummulativeHash: CummulativeClaimField2ProofHash +}) {} + +// Define specific methods for handling claim data with two fields. +// Example method handling using the two-field structure +const claimDataField2MethodHelper = ( + methodName: string, + publicInput: ClaimField2ProofPublicInput, + privateInput: ClaimField2ProofPrivateInput, + theClaimCheck: ({ + claimData, + operand + }: { + claimData: ClaimField2Data; + operand: ClaimField2Data; + }) => Bool +) => { + // verify method id + const methodId = Poseidon.hash( + CircuitString.fromString(methodName).toFields() + ); + methodId.assertEquals(publicInput.methodId, 'Invalid method identifier'); + + // verify credential hash + publicInput.credentialHash.assertEquals( + Poseidon.hash(privateInput.credential.toFields()) + ); + + // merkle witness verification + const claimHash = Poseidon.hash(privateInput.claimData.toFields()); + const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash); + publicInput.claimMerkleMapRootHash.assertEquals(root); + + // at this point we know that the claim data in fact comes + // from a credential of the given hash + + // now comes the actual verification of the claim data + // for this methodId, which is an equality check + + // we will assume that the claim data is a single field + // and that the operand is a field + theClaimCheck({ + claimData: privateInput.claimData, + operand: publicInput.operand + }).assertTrue('Claim data does not match operand'); +}; + +// You can extend or modify existing methods or add new ones to handle the two-field data. +// Implement the rest of the system logic as needed. + +const cummulativeHashHelper = ( + earlierProof: SelfProof, + publicInput: ClaimField2ProofPublicInput +): ClaimField2ProofOutput => { + const oldCummulativeHash = earlierProof.publicOutput + .cummulativeHash as CummulativeClaimField2ProofHash; + const cummulativeHash: CummulativeClaimField2ProofHash = + oldCummulativeHash.append(publicInput); + const ret: ClaimField2ProofOutput = new ClaimField2ProofOutput({ + cummulativeHash + }); + return ret; +}; + +const baseCummulativeHashHelper = ( + publicInput: ClaimField2ProofPublicInput +): ClaimField2ProofOutput => { + const cummulativeHash = + CummulativeClaimField2ProofHash.fromPublicInput(publicInput); + + const ret: ClaimField2ProofOutput = new ClaimField2ProofOutput({ + cummulativeHash + }); + return ret; +}; + +export const Validate2FieldClaimProgram = ZkProgram({ + name: 'Validate2FieldClaim', + publicInput: ClaimField2ProofPublicInput, + publicOutput: ClaimField2ProofOutput, + methods: { + // Define methods for different types of claims, using ClaimField2ProofPrivateInput + // and the claimDataField2MethodHelper function + + baseEqual: { + privateInputs: [ClaimField2ProofPrivateInput], + method( + publicInput: ClaimField2ProofPublicInput, + privateInput: ClaimField2ProofPrivateInput + ): ClaimField2ProofOutput { + claimDataField2MethodHelper( + 'baseEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.equals(operand) + ); + + return baseCummulativeHashHelper(publicInput); + } + }, + cummulativeEqual: { + privateInputs: [SelfProof, ClaimField2ProofPrivateInput], + method( + publicInput: ClaimField2ProofPublicInput, + earlierProof: SelfProof< + ClaimField2ProofPublicInput, + ClaimField2ProofOutput + >, + privateInput: ClaimField2ProofPrivateInput + ): ClaimField2ProofOutput { + earlierProof.verify(); + + claimDataField2MethodHelper( + 'cummulativeEqual', + publicInput, + privateInput, + ({ claimData, operand }) => claimData.equals(operand) + ); + + return cummulativeHashHelper(earlierProof, publicInput); + } + }, + baseGreaterThanOrEqual: { + privateInputs: [ClaimField2ProofPrivateInput], + method( + publicInput: ClaimField2ProofPublicInput, + privateInput: ClaimField2ProofPrivateInput + ): ClaimField2ProofOutput { + claimDataField2MethodHelper( + 'baseGreaterThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => + Provable.if( + claimData.data1.equals(operand.data1), + claimData.data2.greaterThanOrEqual(operand.data2), + claimData.data1.greaterThanOrEqual(operand.data1) + ) + ); + + return baseCummulativeHashHelper(publicInput); + } + }, + cummulativeGreaterThanOrEqual: { + privateInputs: [SelfProof, ClaimField2ProofPrivateInput], + method( + publicInput: ClaimField2ProofPublicInput, + earlierProof: SelfProof< + ClaimField2ProofPublicInput, + ClaimField2ProofOutput + >, + privateInput: ClaimField2ProofPrivateInput + ): ClaimField2ProofOutput { + earlierProof.verify(); + + claimDataField2MethodHelper( + 'cummulativeGreaterThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => + Provable.if( + claimData.data1.equals(operand.data1), + claimData.data2.greaterThanOrEqual(operand.data2), + claimData.data1.greaterThanOrEqual(operand.data1) + ) + ); + + return cummulativeHashHelper(earlierProof, publicInput); + } + }, + baseLessThanOrEqual: { + privateInputs: [ClaimField2ProofPrivateInput], + method( + publicInput: ClaimField2ProofPublicInput, + privateInput: ClaimField2ProofPrivateInput + ): ClaimField2ProofOutput { + claimDataField2MethodHelper( + 'baseLessThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => + Provable.if( + claimData.data1.equals(operand.data1), + claimData.data2.lessThanOrEqual(operand.data2), + claimData.data1.lessThanOrEqual(operand.data1) + ) + ); + + return baseCummulativeHashHelper(publicInput); + } + }, + cummulativeLessThanOrEqual: { + privateInputs: [SelfProof, ClaimField2ProofPrivateInput], + method( + publicInput: ClaimField2ProofPublicInput, + earlierProof: SelfProof< + ClaimField2ProofPublicInput, + ClaimField2ProofOutput + >, + privateInput: ClaimField2ProofPrivateInput + ): ClaimField2ProofOutput { + earlierProof.verify(); + + claimDataField2MethodHelper( + 'cummulativeLessThanOrEqual', + publicInput, + privateInput, + ({ claimData, operand }) => + Provable.if( + claimData.data1.equals(operand.data1), + claimData.data2.lessThanOrEqual(operand.data2), + claimData.data1.lessThanOrEqual(operand.data1) + ) + ); + + return cummulativeHashHelper(earlierProof, publicInput); + } + } + } +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts deleted file mode 100644 index 1e89d29..0000000 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/claim-proof.ts +++ /dev/null @@ -1,579 +0,0 @@ -import { - Bool, - CircuitString, - Field, - MerkleMapWitness, - Poseidon, - SelfProof, - Struct, - ZkProgram -} from 'o1js'; -import { VCredDataStruct } from 'src/data/o1js/vcred.js'; - -// how to be smart about diffrent claim data types? - -export class ClaimDataField1 extends Struct({ - data: Field -}) { - public toFields(): Field[] { - return [this.data]; - } -} - -// the programs public input -export class ClaimProofPublicInput extends Struct({ - credentialHash: Field, - claimMerkleMapRootHash: Field, - operand: Field, - methodId: Field -}) {} - -// the programs secret input -export class ClaimProofPrivateInput extends Struct({ - credential: VCredDataStruct, - claimWitness: MerkleMapWitness, - claimData: ClaimDataField1 -}) {} - -/** The cummulative output hash of the proof. - * This exists so that one can recursively rollup proofs - * about claims. - * Then the output hash can be used to retrace the proved - * computation. - */ -export class CummulativeClaimProofHash extends Field { - static fromPublicInput( - publicInput: ClaimProofPublicInput - ): CummulativeClaimProofHash { - return new CummulativeClaimProofHash( - Poseidon.hash([ - publicInput.credentialHash, - publicInput.claimMerkleMapRootHash, - publicInput.operand, - publicInput.methodId - ]) - ); - } - - /** Monoidal append operation for the cummulative hash */ - public append(publicInput: ClaimProofPublicInput) { - const newHash = CummulativeClaimProofHash.fromPublicInput(publicInput); - return new CummulativeClaimProofHash(Poseidon.hash([this, newHash])); - } - - /** Auxilliary function to check if the proof cummulative hash - corresponds to the set of public inputs determinining - how the proof is being constructed. - */ - public verify(publicInputs: ClaimProofPublicInput[]): boolean { - const l = publicInputs.length; - if (l === 0) { - return false; - } - let cumm = CummulativeClaimProofHash.fromPublicInput(publicInputs[0]); - for (let i = 1; i < l; i++) { - cumm = cumm.append(publicInputs[i]); - } - - return cumm.equals(this).toBoolean(); - } - - public toFields(): Field[] { - return [this]; - } -} - -export class ClaimProofOutput extends Struct({ - cummulativeHash: CummulativeClaimProofHash -}) {} - - -const claimDataField1MethodHelper = ( - methodName: string, - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput, - theClaimCheck: ({claimData, operand} : {claimData: Field, operand: Field}) => Bool) => { - - // verify method id - const methodId = Poseidon.hash( - CircuitString.fromString(methodName).toFields() - ); - methodId.assertEquals( - publicInput.methodId, - 'Invalid method identifier' - ); - - // verify credential hash - publicInput.credentialHash.assertEquals( - Poseidon.hash(privateInput.credential.toFields()) - ); - - // merkle witness verification - const claimHash = Poseidon.hash(privateInput.claimData.toFields()); - const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash) - publicInput.claimMerkleMapRootHash.assertEquals(root); - - // at this point we know that the claim data in fact comes - // from a credential of the given hash - - // now comes the actual verification of the claim data - // for this methodId, which is an equality check - - // we will assume that the claim data is a single field - // and that the operand is a field - theClaimCheck({ - claimData: privateInput.claimData.data, - operand: publicInput.operand - }).assertTrue('Claim data does not match operand'); - } - -// lets for now assume that the claim data is a field -export const ValidateClaimField1Program = ZkProgram({ - name: 'ValidateClaimField1', - publicInput: ClaimProofPublicInput, - publicOutput: ClaimProofOutput, - methods: { - baseEqual: { - privateInputs: [ClaimProofPrivateInput], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput - ): ClaimProofOutput { - - claimDataField1MethodHelper( - 'baseEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.equals(operand) - ); - - - const cummulativeHash = - CummulativeClaimProofHash.fromPublicInput(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - cummulativeEqual: { - privateInputs: [SelfProof, ClaimProofPrivateInput], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofPrivateInput - ): ClaimProofOutput { - - earlierProof.verify(); - - claimDataField1MethodHelper( - 'cummulativeEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.equals(operand) - ); - - const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - baseGreaterThanOrEqual: { - privateInputs: [ClaimProofPrivateInput], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput - ): ClaimProofOutput { - - claimDataField1MethodHelper( - 'baseGreaterThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.greaterThanOrEqual(operand) - ); - - const cummulativeHash = - CummulativeClaimProofHash.fromPublicInput(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - cummulativeGreaterThanOrEqual: { - privateInputs: [SelfProof, ClaimProofPrivateInput], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofPrivateInput - ): ClaimProofOutput { - - earlierProof.verify(); - - claimDataField1MethodHelper( - 'cummulativeGreaterThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.greaterThanOrEqual(operand) - ); - - const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - } - }, - baseLessThanOrEqual: { - privateInputs: [ClaimProofPrivateInput], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput - ): ClaimProofOutput { - - claimDataField1MethodHelper( - 'baseLessThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.lessThanOrEqual(operand) - ); - - const cummulativeHash = - CummulativeClaimProofHash.fromPublicInput(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - cummulativeLessThanOrEqual: { - privateInputs: [SelfProof, ClaimProofPrivateInput], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofPrivateInput - ): ClaimProofOutput { - - earlierProof.verify(); - - claimDataField1MethodHelper( - 'cummulativeLessThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.lessThanOrEqual(operand) - ); - - const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - } - } - } -}); - -export const ValidateClaimField1Proof = ZkProgram.Proof(ValidateClaimField1Program); - -// now the same but for a claim data that has two fields: - -export class ClaimDataField2 extends Struct({ - data1: Field, - data2: Field -}) { - public toFields(): Field[] { - return [this.data1, this.data2]; - } -} - -export class ClaimProofPrivateInput2 extends Struct({ - credential: VCredDataStruct, - claimWitness: MerkleMapWitness, - claimData: ClaimDataField2 -}) {} - -export const claimDataField2MethodHelper = ( - methodName: string, - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput2, - theClaimCheck: ({claimData, operand} : {claimData: ClaimDataField2, operand: Field}) => Bool) => { - - // verify method id - const methodId = Poseidon.hash( - CircuitString.fromString(methodName).toFields() - ); - methodId.assertEquals( - publicInput.methodId, - 'Invalid method identifier' - ); - - // verify credential hash - publicInput.credentialHash.assertEquals( - Poseidon.hash(privateInput.credential.toFields()) - ); - - // merkle witness verification - const claimHash = Poseidon.hash(privateInput.claimData.toFields()); - const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash) - publicInput.claimMerkleMapRootHash.assertEquals(root); - - // at this point we know that the claim data in fact comes - // from a credential of the given hash - - // now comes the actual verification of the claim data - // for this methodId, which is an equality check - - // we will assume that the claim data is a single field - // and that the operand is a field - theClaimCheck({ - claimData: privateInput.claimData, - operand: publicInput.operand - }).assertTrue('Claim data does not match operand'); - } - -export const ValidateClaimField2Program = ZkProgram({ - name: 'ValidateClaimField2', - publicInput: ClaimProofPublicInput, - publicOutput: ClaimProofOutput, - methods: { - baseEqual: { - privateInputs: [ClaimProofPrivateInput2], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput2 - ): ClaimProofOutput { - - claimDataField2MethodHelper( - 'baseEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data1.equals(operand) - ); - - const cummulativeHash = - CummulativeClaimProofHash.fromPublicInput(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - cummulativeEqual: { - privateInputs: [SelfProof, ClaimProofPrivateInput2], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofPrivateInput2 - ): ClaimProofOutput { - - earlierProof.verify(); - - claimDataField2MethodHelper( - 'cummulativeEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data1.equals(operand) - ); - - const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - baseGreaterThanOrEqual: { - privateInputs: [ClaimProofPrivateInput2], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput2 - ): ClaimProofOutput { - - claimDataField2MethodHelper( - 'baseGreaterThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data1.greaterThanOrEqual(operand) - ); - - const cummulativeHash = - CummulativeClaimProofHash.fromPublicInput(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - cummulativeGreaterThanOrEqual: { - privateInputs: [SelfProof, ClaimProofPrivateInput2], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofPrivateInput2 - ): ClaimProofOutput { - - earlierProof.verify(); - - claimDataField2MethodHelper( - 'cummulativeGreaterThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data1.greaterThanOrEqual(operand) - ); - - const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - } - }, - baseLessThanOrEqual: { - privateInputs: [ClaimProofPrivateInput2], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInput2 - ): ClaimProofOutput { - - claimDataField2MethodHelper( - 'baseLessThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data1.lessThanOrEqual(operand) - ); - - const cummulativeHash = - CummulativeClaimProofHash.fromPublicInput(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - cummulativeLessThanOrEqual: { - privateInputs: [SelfProof, ClaimProofPrivateInput2], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofPrivateInput2 - ): ClaimProofOutput { - - earlierProof.verify(); - - claimDataField2MethodHelper( - 'cummulativeLessThanOrEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data1.lessThanOrEqual(operand) - ); - - const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - } - } - } -}); - -export const ValidateClaimField2Proof = ZkProgram.Proof(ValidateClaimField2Program); - - -// now the same but for a claim data that is a citcuit string: - -export class ClaimDataString extends Struct({ - data: CircuitString -}) { - public toFields(): Field[] { - return [this.data]; - } -} - -export class ClaimProofPrivateInputString extends Struct({ - credential: VCredDataStruct, - claimWitness: MerkleMapWitness, - claimData: ClaimDataString -}) {} - -export const claimDataStringMethodHelper = ( - methodName: string, - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInputString, - theClaimCheck: ({claimData, operand} : {claimData: ClaimDataString, operand: Field}) => Bool) => { - - // verify method id - const methodId = Poseidon.hash( - CircuitString.fromString(methodName).toFields() - ); - methodId.assertEquals( - publicInput.methodId, - 'Invalid method identifier' - ); - - // verify credential hash - publicInput.credentialHash.assertEquals( - Poseidon.hash(privateInput.credential.toFields()) - ); - - // merkle witness verification - const claimHash = Poseidon.hash(privateInput.claimData.toFields()); - const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash) - publicInput.claimMerkleMapRootHash.assertEquals(root); - - // at this point we know that the claim data in fact comes - // from a credential of the given hash - - // now comes the actual verification of the claim data - // for this methodId, which is an equality check - - // we will assume that the claim data is a single field - // and that the operand is a field - theClaimCheck({ - claimData: privateInput.claimData, - operand: publicInput.operand - }).assertTrue('Claim data does not match operand'); - } - -// TODO: -// this one will be better offering proving membership in a set, or -// or proving that string does not belong to a set -// or proving that a string is a substring of another string -export const ValidateClaimStringProgram = ZkProgram({ - name: 'ValidateClaimString', - publicInput: ClaimProofPublicInput, - publicOutput: ClaimProofOutput, - methods: { - baseEqual: { - privateInputs: [ClaimProofPrivateInputString], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofPrivateInputString - ): ClaimProofOutput { - - claimDataStringMethodHelper( - 'baseEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data.equals(operand) - ); - - const cummulativeHash = - CummulativeClaimProofHash.fromPublicInput(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - cummulativeEqual: { - privateInputs: [SelfProof, ClaimProofPrivateInputString], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofPrivateInputString - ): ClaimProofOutput { - - earlierProof.verify(); - - claimDataStringMethodHelper( - 'cummulativeEqual', - publicInput, - privateInput, - ({claimData, operand}) => claimData.data.equals(operand) - ); - - const cummulativeHash: CummulativeClaimProofHash = earlierProof.publicOutput.cummulativeHash.append(publicInput); - const ret: ClaimProofOutput = new ClaimProofOutput({ cummulativeHash }); - return ret; - - } - }, - } - -); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts new file mode 100644 index 0000000..9ddd4bd --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts @@ -0,0 +1,208 @@ +import { + Bool, + CircuitString, + Field, + FlexibleProvablePure, + MerkleMapWitness, + Poseidon, + SelfProof, + Struct, + ZkProgram +} from 'o1js'; +import { VCredDataStruct } from '../data/o1js/vcred.js'; + + +/** + This is a more nuanced version of the claim validation program. + It is generic and meant to make claim verification very convenient. + For example: + + export const FieldSecretMembershipClaimProgram = MkValidateClaimProgram( + Field, // secret: ClaimData is just a field () + Field, // Reference (public data): MerkleMap root + MerkleMapWitness, // custom secret + Field, // not used + )(({claimData, referenceData: merkleRoot, secretData: merkleWitness}) => { + + const [root] = merkleWitness.computeRootAndKey(claimData); + const checkValid: Bool = merkleRoot.equals(root); + + return { checkValid, customOutput: new Field(0) }; + }); + + TODO: + (there are still some discrepancies + - there's no check about which claim is being checked + ) + make it so that the below holds: + + This will prove that: + + The claim data belongs to the merklemap + GIVEN: + - a credentialhash (that corresponds to a valid credential, and already acccepted credential) + - a claim id (todo) + - a merkle map root hash + + + +*/ +// TODO: update methodid checks, they are not useful as of this +// form in the generic approach +export const MkValidateClaimProgram = ( + ClaimData: FlexibleProvablePure, + ReferenceData: FlexibleProvablePure, + SecretData: FlexibleProvablePure, + CustomOutput: FlexibleProvablePure +) => { + class TheClaimCheckInput extends Struct({ + claimData: ClaimData, + referenceData: ReferenceData, + secretData: SecretData + }) {} + + class TheClaimCheckOutput extends Struct({ + checkValid: Bool, + customOutput: CustomOutput + }) {} + + return ( + theClaimCheck: (input: TheClaimCheckInput) => TheClaimCheckOutput + ) => { + class ClaimProofPublicInput extends Struct({ + methodId: Field, + credentialHash: Field, + claimMerkleMapRootHash: Field, + customInput: ReferenceData + }) { + public toFields(): Field[] { + return [ + this.methodId, + this.credentialHash, + this.claimMerkleMapRootHash, + ...this.customInput.toFields() + ]; + } + } + + class ClaimProofSecretInput extends Struct({ + credential: VCredDataStruct, + claimWitness: MerkleMapWitness, + claimData: ClaimData, + customSecret: SecretData + }) {} + + class ClaimProofOutput extends Struct({ + claimCummulativeHash: Field, + customOutput: CustomOutput + }) {} + + const claimDataMethodHelper = ( + methodName: string, + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofSecretInput + ): ClaimProofOutput => { + // verify method id + const methodId = Poseidon.hash( + CircuitString.fromString(methodName).toFields() + ); + methodId.assertEquals(publicInput.methodId, 'Invalid method identifier'); + + // verify credential hash + publicInput.credentialHash.assertEquals( + Poseidon.hash(privateInput.credential.toFields()) + ); + + // merkle witness verification + const claimHash = Poseidon.hash(privateInput.claimData.toFields()); + const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash); + publicInput.claimMerkleMapRootHash.assertEquals(root); + + // at this point we know that the claim data in fact comes + // from a credential of the given hash + + // now comes the actual verification of the claim data + // for this methodId, which is an equality check + + const claimInput: TheClaimCheckInput = { + claimData: privateInput.claimData, + referenceData: publicInput.customInput, + secretData: privateInput.customSecret + }; + + const { checkValid, customOutput } = theClaimCheck(claimInput); + + checkValid.assertTrue('Claim data check failed'); + + return customOutput; + }; + + const ValidateClaimProgram = ZkProgram({ + name: 'CustomValidateClaim', + publicInput: ClaimProofPublicInput, + publicOutput: ClaimProofOutput, + methods: { + baseEqual: { + privateInputs: [ClaimProofSecretInput], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofSecretInput + ): ClaimProofOutput { + return claimDataMethodHelper('baseEqual', publicInput, privateInput); + } + }, + cummulativeEqual: { + privateInputs: [SelfProof, ClaimProofSecretInput], + method( + publicInput: ClaimProofPublicInput, + earlierProof: SelfProof, + privateInput: ClaimProofSecretInput + ): ClaimProofOutput { + + // verify recursive proof + earlierProof.verify(); + + // the proof has to be for the same credential + earlierProof.publicInput.credentialHash.assertEquals( + Poseidon.hash([publicInput.credentialHash]) + ); + + // verify the custom check + const {customOutput} = claimDataMethodHelper( + 'cummulativeEqual', + publicInput, + privateInput + ); + + // compute the cummulative hash + const oldCummulativeHash = earlierProof.publicOutput.claimCummulativeHash; + const currentPublicInputHash = Poseidon.hash(publicInput.toFields()); + const cummulativeHash = Poseidon.hash([ + oldCummulativeHash, + currentPublicInputHash, + ]); + + return new ClaimProofOutput({ claimCummulativeHash: cummulativeHash, customOutput }); + } + } + } + }); + + return ValidateClaimProgram; + }; +}; + + +// temp test: example usage +export const FieldSecretMembershipClaimProgram = MkValidateClaimProgram( + Field, // secret: ClaimData is just a field + Field, // Reference (public data): MerkleMap root + MerkleMapWitness, // custom secret + Field, // not used +)(({claimData, referenceData: merkleRoot, secretData: merkleWitness}) => { + + const [root] = merkleWitness.computeRootAndKey(claimData); + const checkValid: Bool = merkleRoot.equals(root); + + return { checkValid, customOutput: new Field(0) }; +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts index 80be23d..0c1effa 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -80,8 +80,8 @@ export const verifyAndIssueCredential = } // additional assertions + if (!signature.verify(o1js.PublicKey.fromBase58(issuer.pubkey), [credentialDataHash(credentialData)]).equals(true)) { // issuer pubkey matches the private key - if (!signature.verify(o1js.PublicKey.fromBase58(issuer.pubkey), flds).equals(true)) { throw new Error('Issuer pubkey does not match the private key used for the signature'); } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts index 3815cb2..d4386ac 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts @@ -1,150 +1,150 @@ -import { Field, PrivateKey, Signature } from 'o1js'; -import { IVCredStruct, VCredStruct, VCredStructUnsigned, mkVCredStruct } from './vcred.js'; // Update import path as needed -import { IClaimStruct, mkClaimStruct, mkClaims } from './claim.js'; // Import necessary dependencies -import { CredSubjectId, IssuerId, VCredId } from './ids.js'; -import { UnixTimestamp } from './common.js'; -import { Claim, Credential, CredentialData, CredentialStandard } from '../transit/cred.js'; +// import { Field, PrivateKey, Signature } from 'o1js'; +// import { IVCredStruct, VCredStruct, VCredStructUnsigned, mkVCredStruct } from './vcred.js'; // Update import path as needed +// import { IClaimStruct, mkClaimStruct, mkClaims } from './claim.js'; // Import necessary dependencies +// import { CredSubjectId, IssuerId, VCredId } from './ids.js'; +// import { UnixTimestamp } from './common.js'; +// import { Claim, Credential, CredentialData, CredentialStandard } from '../transit/cred.js'; -describe('VCredStruct tests', () => { - const pk1 = PrivateKey.random().toPublicKey(); - const pk1s: string = pk1.toBase58(); - const pk2 = PrivateKey.random().toPublicKey(); - const pk2s = pk2.toBase58(); +// describe('VCredStruct tests', () => { +// const pk1 = PrivateKey.random().toPublicKey(); +// const pk1s: string = pk1.toBase58(); +// const pk2 = PrivateKey.random().toPublicKey(); +// const pk2s = pk2.toBase58(); - // dummy standard - const DummyStandard: CredentialStandard = { - standardId: 'dummy', - description: 'Dummy standard', - schema: { - claim1: { - standardId: 'dummy', - description: 'Dummy claim 1', - fieldsConversion: { - length: 1, - description: 'Dummy claim 1', - codeExample: '' - } - }, - claim2:{ - standardId: 'dummy', - description: 'Dummy claim 2', - fieldsConversion: { - length: 2, - description: 'Dummy claim 2', - codeExample: '' - } - } - } - }; - const claim1s: Claim = { - name: 'claim1', - value: '0x123', - fieldsValue: ["0x123"], - standard: DummyStandard.schema.claim1 - }; - const claim2s = { - name: 'claim2', - value: '0x456,0x789', - fieldsValue: ["0x456", "0x789"], - standard: DummyStandard.schema.claim2 - }; +// // dummy standard +// const DummyStandard: CredentialStandard = { +// standardId: 'dummy', +// description: 'Dummy standard', +// schema: { +// claim1: { +// standardId: 'dummy', +// description: 'Dummy claim 1', +// fieldsConversion: { +// length: 1, +// description: 'Dummy claim 1', +// codeExample: '' +// } +// }, +// claim2:{ +// standardId: 'dummy', +// description: 'Dummy claim 2', +// fieldsConversion: { +// length: 2, +// description: 'Dummy claim 2', +// codeExample: '' +// } +// } +// } +// }; +// const claim1s: Claim = { +// name: 'claim1', +// value: '0x123', +// fieldsValue: ["0x123"], +// standard: DummyStandard.schema.claim1 +// }; +// const claim2s = { +// name: 'claim2', +// value: '0x456,0x789', +// fieldsValue: ["0x456", "0x789"], +// standard: DummyStandard.schema.claim2 +// }; - let claim1: IClaimStruct; - let claim2: IClaimStruct; +// let claim1: IClaimStruct; +// let claim2: IClaimStruct; - beforeAll(() => { - claim1 = mkClaimStruct(claim1s); - claim2 = mkClaimStruct(claim2s); - }); +// beforeAll(() => { +// claim1 = mkClaimStruct(claim1s); +// claim2 = mkClaimStruct(claim2s); +// }); - const ClaimSizes = [3, 2]; - const VCredStructUnsignedType = VCredStructUnsigned(ClaimSizes); - const VCredStructType = VCredStruct(ClaimSizes); +// const ClaimSizes = [3, 2]; +// const VCredStructUnsignedType = VCredStructUnsigned(ClaimSizes); +// const VCredStructType = VCredStruct(ClaimSizes); - const testData = () => { - return { - id: new VCredId({ id: new Field(123) }), - issuer: new IssuerId({ pubkey: pk1 }), - issuanceDate: new UnixTimestamp({ unixTimestamp: new Field(1711897450) }), - expirationDate: new UnixTimestamp({ - unixTimestamp: new Field(1721897450) - }), - subject: new CredSubjectId({ pubkey: pk2 }), - claims: mkClaims([claim1, claim2]), - credentialStandardHash: new Field(789) - }; - }; +// const testData = () => { +// return { +// id: new VCredId({ id: new Field(123) }), +// issuer: new IssuerId({ pubkey: pk1 }), +// issuanceDate: new UnixTimestamp({ unixTimestamp: new Field(1711897450) }), +// expirationDate: new UnixTimestamp({ +// unixTimestamp: new Field(1721897450) +// }), +// subject: new CredSubjectId({ pubkey: pk2 }), +// claims: mkClaims([claim1, claim2]), +// credentialStandardHash: new Field(789) +// }; +// }; - describe('VCredStructUnsigned', () => { - it('should instantiate correctly with valid data', () => { - const instance = new VCredStructUnsignedType(testData()); - expect(instance).toBeInstanceOf(VCredStructUnsignedType); - expect(instance.toFields()).toEqual( - expect.arrayContaining([expect.any(Field)]) - ); - }); +// describe('VCredStructUnsigned', () => { +// it('should instantiate correctly with valid data', () => { +// const instance = new VCredStructUnsignedType(testData()); +// expect(instance).toBeInstanceOf(VCredStructUnsignedType); +// expect(instance.toFields()).toEqual( +// expect.arrayContaining([expect.any(Field)]) +// ); +// }); - it('should parse from credential data transit type', () => { - const data: CredentialData = { - id: '123', - issuer: { pubkey: pk1s }, - issuanceDate: '1711897450', - expirationDate: '1721897450', - subject: { pubkey: pk2s }, - claims: { - claim1: claim1s, - claim2: claim2s - }, - credentialStandardHash: '789' - } - const res: IVCredStruct = mkVCredStruct(data) - expect(res).toBeDefined(); - }); - }); +// it('should parse from credential data transit type', () => { +// const data: CredentialData = { +// id: '123', +// issuer: { pubkey: pk1s }, +// issuanceDate: '1711897450', +// expirationDate: '1721897450', +// subject: { pubkey: pk2s }, +// claims: { +// claim1: claim1s, +// claim2: claim2s +// }, +// credentialStandardHash: '789' +// } +// const res: IVCredStruct = mkVCredStruct(data) +// expect(res).toBeDefined(); +// }); +// }); - describe('VCredStruct', () => { - const testDataSig = () => { - return { - id: new VCredId({ id: new Field(123) }), - issuer: new IssuerId({ pubkey: pk1 }), - issuanceDate: new UnixTimestamp({ - unixTimestamp: new Field(123123123) - }), - expirationDate: new UnixTimestamp({ - unixTimestamp: new Field(223123123) - }), - subject: new CredSubjectId({ pubkey: pk2 }), - claims: mkClaims([claim1, claim2]), - credentialStandardHash: new Field(789), - signature: Signature.fromBase58('7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE') - }; - }; +// describe('VCredStruct', () => { +// const testDataSig = () => { +// return { +// id: new VCredId({ id: new Field(123) }), +// issuer: new IssuerId({ pubkey: pk1 }), +// issuanceDate: new UnixTimestamp({ +// unixTimestamp: new Field(123123123) +// }), +// expirationDate: new UnixTimestamp({ +// unixTimestamp: new Field(223123123) +// }), +// subject: new CredSubjectId({ pubkey: pk2 }), +// claims: mkClaims([claim1, claim2]), +// credentialStandardHash: new Field(789), +// signature: Signature.fromBase58('7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE') +// }; +// }; - it('should instantiate correctly with valid data, including signature', () => { - const instance = new VCredStructType(testDataSig()); - expect(instance).toBeInstanceOf(VCredStructType); - expect(instance.toFields()).toEqual( - expect.arrayContaining([expect.any(Field)]) - ); - }); +// it('should instantiate correctly with valid data, including signature', () => { +// const instance = new VCredStructType(testDataSig()); +// expect(instance).toBeInstanceOf(VCredStructType); +// expect(instance.toFields()).toEqual( +// expect.arrayContaining([expect.any(Field)]) +// ); +// }); - it('should have a valid schema including signature', () => { - const cred: Credential = { - id: '123', - issuer: { pubkey: pk1s }, - issuanceDate: '1711897450', - expirationDate: '1721897450', - subject: { pubkey: pk2s }, - claims: { - claim1: claim1s, - claim2: claim2s - }, - credentialStandardHash: '789', - signature: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' - }; - const res: IVCredStruct = mkVCredStruct(cred) - expect(res).toBeDefined(); - }); - }); -}); +// it('should have a valid schema including signature', () => { +// const cred: Credential = { +// id: '123', +// issuer: { pubkey: pk1s }, +// issuanceDate: '1711897450', +// expirationDate: '1721897450', +// subject: { pubkey: pk2s }, +// claims: { +// claim1: claim1s, +// claim2: claim2s +// }, +// credentialStandardHash: '789', +// signature: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' +// }; +// const res: IVCredStruct = mkVCredStruct(cred) +// expect(res).toBeDefined(); +// }); +// }); +// }); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index f3dfe0e..6de0b01 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -1,5 +1,5 @@ import { Logger } from 'tslog'; -import { Field, Poseidon, PrivateKey, Signature, Struct, UInt64, ZkProgram } from 'o1js'; +import { Field, PrivateKey, Signature, Struct, UInt64, ZkProgram } from 'o1js'; import { Issuer, IssuerSchema } from './issuer.js'; import * as DateOfBirth from './zkclaims/date-of-birth.js'; import * as Citizenship from './zkclaims/citizenship.js'; @@ -8,7 +8,10 @@ import { DateTimeSchema, FieldSchema } from './data/transit/common.js'; import { CredSubjectId, CredSubjectIdSchema, Credential, CredentialData, CredentialStandard, VCredIdSchema } from './data/transit/cred.js'; import { credentialStandardHash, verifyAndIssueCredential } from './credential.js'; import { CredentialStore, MockStorage } from './credential-store.js'; -import { VCredProofHelper, VCredStruct } from './data/o1js/vcred.js'; +import { VCredProofHelper } from './data/o1js/vcred.js'; +import { FieldSecretMembershipClaimProgram } from './circuit/generic-claim-proving.js'; +import { Validate1FieldClaimProgram } from './circuit/claim-field1-proving.js'; +import { Validate2FieldClaimProgram } from './circuit/claim-field2-proving.js'; const log = new Logger({ name: 'index.ts prototyping' }); @@ -183,86 +186,98 @@ methods: - claimData -- to */ -class ClaimProofPublicInput extends Struct({ - credentialHash: Field, - claimIndex: Field, - operand: Field -}) {} +log.info('Compiling the program #1'); +await Validate1FieldClaimProgram.compile() -class ClaimProofSecretInput extends Struct({ - credential: VCred -}) {} +log.info('Compiling the program #2'); +await Validate2FieldClaimProgram.compile() -class ClaimProofOutput extends Struct({ - claimCode: Field -}) {} +log.info('Compiling the program #3'); +// there's an issue with compiling +// TypeError: Cannot read properties of undefined (reading 'value') +await FieldSecretMembershipClaimProgram.compile() -const mkClaimProofProgram = ( - claimIndex: number, - claimLength: number, +// class ClaimProofPublicInput extends Struct({ +// credentialHash: Field, +// claimIndex: Field, +// operand: Field +// }) {} +// class ClaimProofSecretInput extends Struct({ +// credential: VCred +// }) {} +// class ClaimProofOutput extends Struct({ +// claimCode: Field +// }) {} -) => { +// const mkClaimProofProgram = ( +// claimIndex: number, +// claimLength: number, -const Program = ZkProgram({ - name: 'VCredProof', - publicInput: ClaimProofPublicInput, - publicOutput: ClaimProofOutput, - methods: { - prove: { - privateInputs: [ClaimProofSecretInput], - method(publicInput: ClaimProofPublicInput, secretInput: ClaimProofSecretInput): ClaimProofOutput { - const claimSlice: Field[] = secretInput.credential.claims.toFields().slice(claimIndex,claimLength) - // the claim computation - UInt64.from(claimSlice[0]).assertGreaterThanOrEqual(UInt64.from(publicInput.operand)); - return new ClaimProofOutput({ claimCode: new Field(1) }); - } - } - } -}); -} +// ) => { -const Program = ZkProgram({ - name: 'VCredProof', - publicInput: ClaimProofPublicInput, - publicOutput: ClaimProofOutput, - methods: { - prove: { - privateInputs: [ClaimProofSecretInput], - method(publicInput: ClaimProofPublicInput, secretInput: ClaimProofSecretInput): ClaimProofOutput { - const claimSlice = secretInput.credential.claims.toFields().slice(5,10) - const claim = secretInput.credential.claims.getClaim(publicInput.claimIndex, claimSlice); +// const Program = ZkProgram({ +// name: 'VCredProof', +// publicInput: ClaimProofPublicInput, +// publicOutput: ClaimProofOutput, +// methods: { +// prove: { +// privateInputs: [ClaimProofSecretInput], +// method(publicInput: ClaimProofPublicInput, secretInput: ClaimProofSecretInput): ClaimProofOutput { +// const claimSlice: Field[] = secretInput.credential.claims.toFields().slice(claimIndex,claimLength) - // the claim computation - UInt64.from(claim[0]).assertGreaterThanOrEqual(UInt64.from(publicInput.operand)); +// // the claim computation +// UInt64.from(claimSlice[0]).assertGreaterThanOrEqual(UInt64.from(publicInput.operand)); - return new ClaimProofOutput({ claimCode: new Field(1) }); - } - } - } -}); - -log.info('Compiling the program'); -await Program.compile(); - -log.info('Building the proof'); -const claimProof = await Program.prove( - new ClaimProofPublicInput({ - credentialHash, - claimIndex: new Field(0), - operand: new Field(18) - }), - new ClaimProofSecretInput({ credential: vcred }) -); +// return new ClaimProofOutput({ claimCode: new Field(1) }); +// } +// } +// } +// }); +// } + + +// const Program = ZkProgram({ +// name: 'VCredProof', +// publicInput: ClaimProofPublicInput, +// publicOutput: ClaimProofOutput, +// methods: { +// prove: { +// privateInputs: [ClaimProofSecretInput], +// method(publicInput: ClaimProofPublicInput, secretInput: ClaimProofSecretInput): ClaimProofOutput { +// const claimSlice = secretInput.credential.claims.toFields().slice(5,10) +// const claim = secretInput.credential.claims.getClaim(publicInput.claimIndex, claimSlice); + +// // the claim computation +// UInt64.from(claim[0]).assertGreaterThanOrEqual(UInt64.from(publicInput.operand)); + +// return new ClaimProofOutput({ claimCode: new Field(1) }); +// } +// } +// } +// }); + +// log.info('Compiling the program'); +// await Program.compile(); + +// log.info('Building the proof'); +// const claimProof = await Program.prove( +// new ClaimProofPublicInput({ +// credentialHash, +// claimIndex: new Field(0), +// operand: new Field(18) +// }), +// new ClaimProofSecretInput({ credential: vcred }) +// ); -log.info('Claim proof done.'); +// log.info('Claim proof done.'); -// --- +// // --- // // for example somthing akin to: From 92cd86b9900b45b1ac6756f6bcd057d2dbd5f968 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Tue, 23 Apr 2024 17:24:40 +0200 Subject: [PATCH 28/34] Fix a bug where the generic claim zkprogram would not compile --- .../src/circuit/generic-claim-proving.ts | 21 +++++++++++++------ .../src/index.ts | 4 ++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts index 9ddd4bd..2581ef3 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts @@ -97,11 +97,15 @@ export const MkValidateClaimProgram = ( customOutput: CustomOutput }) {} + class CustomOutputClass extends Struct({ + customOutput: CustomOutput + }) {} + const claimDataMethodHelper = ( methodName: string, publicInput: ClaimProofPublicInput, privateInput: ClaimProofSecretInput - ): ClaimProofOutput => { + ): CustomOutputClass => { // verify method id const methodId = Poseidon.hash( CircuitString.fromString(methodName).toFields() @@ -134,7 +138,7 @@ export const MkValidateClaimProgram = ( checkValid.assertTrue('Claim data check failed'); - return customOutput; + return { customOutput }; }; const ValidateClaimProgram = ZkProgram({ @@ -148,7 +152,9 @@ export const MkValidateClaimProgram = ( publicInput: ClaimProofPublicInput, privateInput: ClaimProofSecretInput ): ClaimProofOutput { - return claimDataMethodHelper('baseEqual', publicInput, privateInput); + const {customOutput} = claimDataMethodHelper('baseEqual', publicInput, privateInput); + const currentPublicInputHash = Poseidon.hash(publicInput.toFields()); + return new ClaimProofOutput({ claimCummulativeHash: currentPublicInputHash, customOutput }); } }, cummulativeEqual: { @@ -187,14 +193,17 @@ export const MkValidateClaimProgram = ( } } }); - - return ValidateClaimProgram; + return { + ValidateClaimProgram, + ClaimProofPublicInput, + ClaimProofSecretInput, + } }; }; // temp test: example usage -export const FieldSecretMembershipClaimProgram = MkValidateClaimProgram( +export const { ValidateClaimProgram: FieldSecretMembershipClaimProgram, ClaimProofPublicInput, ClaimProofSecretInput } = MkValidateClaimProgram( Field, // secret: ClaimData is just a field Field, // Reference (public data): MerkleMap root MerkleMapWitness, // custom secret diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 6de0b01..cf178fd 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -187,10 +187,10 @@ methods: */ log.info('Compiling the program #1'); -await Validate1FieldClaimProgram.compile() +// await Validate1FieldClaimProgram.compile() log.info('Compiling the program #2'); -await Validate2FieldClaimProgram.compile() +// await Validate2FieldClaimProgram.compile() log.info('Compiling the program #3'); // there's an issue with compiling From 5d38221787ed5ceba2fdba7a87704c48c4ab7296 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Tue, 23 Apr 2024 20:31:55 +0200 Subject: [PATCH 29/34] Finish implementation of generic claim proving program. --- .../src/circuit/generic-claim-proving.ts | 274 +++++++++++------- 1 file changed, 163 insertions(+), 111 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts index 2581ef3..df4f9a6 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts @@ -5,36 +5,74 @@ import { FlexibleProvablePure, MerkleMapWitness, Poseidon, + Provable, SelfProof, Struct, ZkProgram } from 'o1js'; import { VCredDataStruct } from '../data/o1js/vcred.js'; - /** This is a more nuanced version of the claim validation program. It is generic and meant to make claim verification very convenient. + + One can provide a set of functions that will deal with verification + of claim data. + + This functions will get wrapped in a function that will take care of + the verification of claim belonging to a credential of a given hash. + + Each wrapped function will become a method of the zkprogram. + + Additionally, the program will be able to merge proofs, created + using this program. + + The beforementioned wrapper builds a trace of the method calls, so that + later on, the exact chain of method calls can be verified given + the final proof. + For example: - export const FieldSecretMembershipClaimProgram = MkValidateClaimProgram( - Field, // secret: ClaimData is just a field () - Field, // Reference (public data): MerkleMap root - MerkleMapWitness, // custom secret - Field, // not used - )(({claimData, referenceData: merkleRoot, secretData: merkleWitness}) => { + class ReferenceData extends Struct({ + fieldData: Field, + stringData: CircuitString + }) {} + + export const { + ValidateClaimsProgram: FieldSecretMembershipClaimProgram, + ClaimProofPublicInput, + ClaimProofSecretInput + } = MkValidateClaimsProgram( + CircuitString, // secret: ClaimData is a string + ReferenceData, // Reference (public data): e.g. MerkleMap root and some string + MerkleMapWitness // custom secret + )({ + proveClaimIsMember: ({ + claimData, + referenceData: {fieldData: merkleRoot, stringData: _} + secretData: merkleWitness + }) => { + const [root] = merkleWitness.computeRootAndKey(Poseidon.hash(claimData.toFields())); + const checkValid: Bool = merkleRoot.equals(root); + return { checkValid }; + } + + proveClaimIsNotEqual: ({ + claimData, + referenceData: {fieldData: _, stringData: otherString} + secretData: merkleWitness + }) => { + const checkValid: Bool = otherString.equals(claimData).not(); + return { checkValid }; + } + }); + + const proof = await FieldSecretMembershipClaimProgram.proveClaimIsMember( + ... + ); - const [root] = merkleWitness.computeRootAndKey(claimData); - const checkValid: Bool = merkleRoot.equals(root); - return { checkValid, customOutput: new Field(0) }; - }); - TODO: - (there are still some discrepancies - - there's no check about which claim is being checked - ) - make it so that the below holds: This will prove that: @@ -47,39 +85,38 @@ import { VCredDataStruct } from '../data/o1js/vcred.js'; */ -// TODO: update methodid checks, they are not useful as of this +// TODO: update checks, they are not useful as of this // form in the generic approach -export const MkValidateClaimProgram = ( +export const MkValidateClaimsProgram = ( ClaimData: FlexibleProvablePure, ReferenceData: FlexibleProvablePure, - SecretData: FlexibleProvablePure, - CustomOutput: FlexibleProvablePure + SecretData: FlexibleProvablePure ) => { - class TheClaimCheckInput extends Struct({ + class ClaimCheckInput extends Struct({ claimData: ClaimData, referenceData: ReferenceData, secretData: SecretData }) {} - class TheClaimCheckOutput extends Struct({ - checkValid: Bool, - customOutput: CustomOutput + class ClaimCheckOutput extends Struct({ + checkValid: Bool }) {} return ( - theClaimCheck: (input: TheClaimCheckInput) => TheClaimCheckOutput + claimCheckMethods: Record< + string, + (input: ClaimCheckInput) => ClaimCheckOutput + > ) => { class ClaimProofPublicInput extends Struct({ - methodId: Field, credentialHash: Field, - claimMerkleMapRootHash: Field, + claimId: Field, customInput: ReferenceData }) { public toFields(): Field[] { return [ - this.methodId, this.credentialHash, - this.claimMerkleMapRootHash, + this.claimId, ...this.customInput.toFields() ]; } @@ -93,34 +130,29 @@ export const MkValidateClaimProgram = ( }) {} class ClaimProofOutput extends Struct({ - claimCummulativeHash: Field, - customOutput: CustomOutput - }) {} - - class CustomOutputClass extends Struct({ - customOutput: CustomOutput + proofExecutionTraceHash: Field }) {} const claimDataMethodHelper = ( - methodName: string, publicInput: ClaimProofPublicInput, - privateInput: ClaimProofSecretInput - ): CustomOutputClass => { - // verify method id - const methodId = Poseidon.hash( - CircuitString.fromString(methodName).toFields() - ); - methodId.assertEquals(publicInput.methodId, 'Invalid method identifier'); - + privateInput: ClaimProofSecretInput, + methodId: Field, + currentMethodClaimCheck: (input: ClaimCheckInput) => ClaimCheckOutput + ): Field => { // verify credential hash publicInput.credentialHash.assertEquals( Poseidon.hash(privateInput.credential.toFields()) ); - // merkle witness verification - const claimHash = Poseidon.hash(privateInput.claimData.toFields()); - const [root, _] = privateInput.claimWitness.computeRootAndKey(claimHash); - publicInput.claimMerkleMapRootHash.assertEquals(root); + // verify claim data + // claim data along with its id should match the witness + const claimMerkleValue = Poseidon.hash([ + publicInput.claimId, + ...privateInput.claimData.toFields() + ]); + const [root, _] = + privateInput.claimWitness.computeRootAndKey(claimMerkleValue); + privateInput.credential.claimsMerkleMapRoot.assertEquals(root); // at this point we know that the claim data in fact comes // from a credential of the given hash @@ -128,90 +160,110 @@ export const MkValidateClaimProgram = ( // now comes the actual verification of the claim data // for this methodId, which is an equality check - const claimInput: TheClaimCheckInput = { + const claimInput: ClaimCheckInput = { claimData: privateInput.claimData, referenceData: publicInput.customInput, secretData: privateInput.customSecret }; - const { checkValid, customOutput } = theClaimCheck(claimInput); + const { checkValid } = currentMethodClaimCheck(claimInput); checkValid.assertTrue('Claim data check failed'); - return { customOutput }; + // hash that will allow to verify the exact method call + const methodCallHash = Poseidon.hash([ + methodId, + ...publicInput.toFields() + ]); + + return methodCallHash; }; - const ValidateClaimProgram = ZkProgram({ + // Define a type for the methods in your programMethods + interface MethodDefinition { + privateInputs: any[]; + method: (publicInput: any, ...args: any[]) => any; + } + + let programMethods: { [key: string]: MethodDefinition } = { + mergeProofs: { + privateInputs: [SelfProof, SelfProof], + method( + _publicInput: ClaimProofPublicInput, + firstProof: SelfProof, + secondProof: SelfProof + ): ClaimProofOutput { + // verify proofs + firstProof.verify(); + secondProof.verify(); + + return new ClaimProofOutput({ + proofExecutionTraceHash: Poseidon.hash([ + firstProof.publicOutput.proofExecutionTraceHash, + secondProof.publicOutput.proofExecutionTraceHash + ]) + }); + } + } + }; + for (const [methodName, method] of Object.entries(claimCheckMethods)) { + if (methodName === 'mergeProofs') { + throw new Error('mergeProofs is a reserved method name'); + } + programMethods[methodName] = { + privateInputs: [ClaimProofSecretInput], + method( + publicInput: ClaimProofPublicInput, + privateInput: ClaimProofSecretInput + ): ClaimProofOutput { + const methodId = Provable.witness(Field, () => + Poseidon.hash(CircuitString.fromString(methodName).toFields()) + ); + const methodCallHash = claimDataMethodHelper( + publicInput, + privateInput, + methodId, + method + ); + return new ClaimProofOutput({ + proofExecutionTraceHash: methodCallHash + }); + } + }; + } + + const ValidateClaimsProgram = ZkProgram({ name: 'CustomValidateClaim', publicInput: ClaimProofPublicInput, publicOutput: ClaimProofOutput, - methods: { - baseEqual: { - privateInputs: [ClaimProofSecretInput], - method( - publicInput: ClaimProofPublicInput, - privateInput: ClaimProofSecretInput - ): ClaimProofOutput { - const {customOutput} = claimDataMethodHelper('baseEqual', publicInput, privateInput); - const currentPublicInputHash = Poseidon.hash(publicInput.toFields()); - return new ClaimProofOutput({ claimCummulativeHash: currentPublicInputHash, customOutput }); - } - }, - cummulativeEqual: { - privateInputs: [SelfProof, ClaimProofSecretInput], - method( - publicInput: ClaimProofPublicInput, - earlierProof: SelfProof, - privateInput: ClaimProofSecretInput - ): ClaimProofOutput { - - // verify recursive proof - earlierProof.verify(); - - // the proof has to be for the same credential - earlierProof.publicInput.credentialHash.assertEquals( - Poseidon.hash([publicInput.credentialHash]) - ); - - // verify the custom check - const {customOutput} = claimDataMethodHelper( - 'cummulativeEqual', - publicInput, - privateInput - ); - - // compute the cummulative hash - const oldCummulativeHash = earlierProof.publicOutput.claimCummulativeHash; - const currentPublicInputHash = Poseidon.hash(publicInput.toFields()); - const cummulativeHash = Poseidon.hash([ - oldCummulativeHash, - currentPublicInputHash, - ]); - - return new ClaimProofOutput({ claimCummulativeHash: cummulativeHash, customOutput }); - } - } - } + methods: programMethods as any }); return { - ValidateClaimProgram, + ValidateClaimsProgram, ClaimProofPublicInput, - ClaimProofSecretInput, - } + ClaimProofSecretInput + }; }; }; - // temp test: example usage -export const { ValidateClaimProgram: FieldSecretMembershipClaimProgram, ClaimProofPublicInput, ClaimProofSecretInput } = MkValidateClaimProgram( +export const { + ValidateClaimsProgram: FieldSecretMembershipClaimProgram, + ClaimProofPublicInput, + ClaimProofSecretInput +} = MkValidateClaimsProgram( Field, // secret: ClaimData is just a field Field, // Reference (public data): MerkleMap root - MerkleMapWitness, // custom secret - Field, // not used -)(({claimData, referenceData: merkleRoot, secretData: merkleWitness}) => { - - const [root] = merkleWitness.computeRootAndKey(claimData); - const checkValid: Bool = merkleRoot.equals(root); + MerkleMapWitness // custom secret +)({ + proveClaimIsMember: ({ + claimData, + referenceData: merkleRoot, + secretData: merkleWitness + }) => { + const [root] = merkleWitness.computeRootAndKey(claimData); + const checkValid: Bool = merkleRoot.equals(root); - return { checkValid, customOutput: new Field(0) }; + return { checkValid } + } }); From e9b9a339d2a41b15c26c853a8419833915af80cc Mon Sep 17 00:00:00 2001 From: adamczykm Date: Fri, 26 Apr 2024 21:44:05 +0200 Subject: [PATCH 30/34] Fix issues in o1js data types +better credential verification +tests --- .../src/circuit/generic-claim-proving.test.ts | 74 +++++ .../src/circuit/generic-claim-proving.ts | 3 +- .../src/circuit/vcred-proof.ts | 21 +- .../src/data/o1js/claim.ts | 288 ++++++------------ .../src/data/o1js/claims.test.ts | 128 +++++--- .../src/data/o1js/vcred.test.ts | 288 +++++++++--------- .../src/data/o1js/vcred.ts | 56 +++- .../src/data/transit/common.ts | 6 + .../src/data/transit/cred.test.ts | 81 +---- .../src/test_fixtures/claims.test.ts | 0 .../src/test_fixtures/credentials.test.ts | 0 .../src/test_fixtures/transit-data.test.ts | 76 +++++ .../tsconfig.json | 2 +- 13 files changed, 542 insertions(+), 481 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/claims.test.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/credentials.test.ts create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit-data.test.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts new file mode 100644 index 0000000..06ac699 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts @@ -0,0 +1,74 @@ +import { Bool, Field, Poseidon } from 'o1js'; +import { MkValidateClaimsProgram } from './generic-claim-proving.js'; + +describe('MkValidateClaimsProgram tests + compilation', () => { + + const { + ValidateClaimsProgram: Prog1, + ClaimProofPublicInput, + ClaimProofSecretInput + } = MkValidateClaimsProgram(Field, Field, Field)({ + proveClaimIsMember: ({ + claimData, + referenceData, + secretData + }) => { + const output = Poseidon.hash([claimData.add(secretData)]); + const checkValid: Bool = output.equals(referenceData); + return { checkValid } + } + }); + it('test program compiles', async () => { + await expect(Prog1.compile()).resolves.toBeDefined() + }); + + describe('MkValidateClaimsProgram tests', () => { + + beforeAll(async () => { + await Prog1.compile(); + }) + + it('test program creates a proof without problems', async () => { + + // class ClaimProofPublicInput extends Struct({ + // credentialHash: Field, + // claimId: Field, + // customInput: ReferenceData + // }) { + // public toFields(): Field[] { + // return [ + // this.credentialHash, + // this.claimId, + // ...this.customInput.toFields() + // ]; + // } + // } + + // class ClaimProofSecretInput extends Struct({ + // credential: VCredDataStruct, + // claimWitness: MerkleMapWitness, + // claimData: ClaimData, + // customSecret: SecretData + // }) {} + + // class ClaimProofOutput extends Struct({ + // proofExecutionTraceHash: Field + // }) {} + + + // const claimData = new ClaimProofPublicInput( + // Field(1), + // Field(1), + // Field(1) + // ); + }); + // ); + // const referenceData = Field(1); + // const secretData = Field(1); + // const proof = await Prog1.proveClaimIsMember({ claimData, referenceData, secretData }); + // expect(proof).toBeDefined(); + // }); + + }); + +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts index df4f9a6..e51f8c1 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts @@ -241,7 +241,8 @@ export const MkValidateClaimsProgram = ( return { ValidateClaimsProgram, ClaimProofPublicInput, - ClaimProofSecretInput + ClaimProofSecretInput, + ClaimProofOutput }; }; }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts index 8e5dfda..d3c8c42 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts @@ -5,9 +5,9 @@ import { DateTime } from "luxon"; import { Bool, Field, Poseidon, PrivateKey, Provable, PublicKey, Struct, ZkProgram } from "o1js"; -import { UnixTimestamp } from "src/data/o1js/common"; -import { VCredProofHelper, VCredStruct, VCredTypeId } from "src/data/o1js/vcred"; -import { Credential } from "src/data/transit/cred"; +import { UnixTimestamp } from "../data/o1js/common.js"; +import { VCredProofHelper, VCredStruct, VCredTypeId } from "../data/o1js/vcred.js"; +import { Credential } from "../data/transit/cred.js"; /** * The public input to the proof of a credential's validity. @@ -15,7 +15,7 @@ import { Credential } from "src/data/transit/cred"; export class VCredProofPublicInput extends Struct ({ validFrom: UnixTimestamp, validTo: UnixTimestamp, - credentialTypeId: VCredTypeId, + credentialTypeId: Field, proverIsSubject: Bool, }) {} @@ -58,12 +58,13 @@ export const ValidateVCredProgram = ZkProgram({ const cred = privateInput.credentialData; - // Ensure the credential type matches the expected type. - const actualCredType = VCredTypeId.forVCred(cred) - publicInput.credentialTypeId.assertEquals( - actualCredType, - "Credential type does not match the expected type." - ); + // TODO + // // Ensure the credential type matches the expected type. + // const actualCredType = VCredTypeId.forVCred(cred) + // publicInput.credentialTypeId.assertEquals( + // actualCredType, + // "Credential type does not match the expected type." + // ); // Verify the credential's signature. cred.signature.verify(cred.issuer.pubkey, cred.dataToFields()) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts index 03ad3d3..e3a349e 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claim.ts @@ -1,24 +1,28 @@ -/* DEV: Due to misconception I've had on how Provable.witness and the level - of dynamism that circuits can have, I have to re-write this module - so that claims in the forms suitable for the zk program are represented - as a MerkleMap instead. - - Which means that most of this module will be gone */ - +/** + * This module provides the necessary components and functions to manage and verify + * credential's claims using Merkle trees within o1js zk circuits. + * Utilizing o1 Labs' o1js library, the module offers classes and functions to represent + * claims, generate unique identifiers (Claim IDs), and manage these claims within a + * MerkleMap to ensure data integrity and enable efficient cryptographic proofs. + */ import { - Struct, - Provable, Field, MerkleMapWitness, MerkleMap, Poseidon, CircuitString } from 'o1js'; -import { arraysAreEqual, ftn, mapObject } from '../../helpers/utils.js'; -import { FieldsSchema } from './common.js'; +import { mapObject } from '../../helpers/utils.js'; import { Claim, CredentialDataClaims } from '../transit/cred.js'; +import { fieldsFromHex } from '../transit/common.js'; +import { Logger } from 'tslog'; + +const log = new Logger({name: 'claim'}); -// ------------ NEW +/** The claim id is a unique identifier for the claim + that is used in the credential's merkle map + */ +export class ClaimId extends Field {} /** Since the claim will be presented to the circuit as fields and a witness to the claim MerkleMap this module will now focus on making a claim @@ -32,24 +36,78 @@ import { Claim, CredentialDataClaims } from '../transit/cred.js'; Hence the claim id will be the hash of the concatenation of these three */ -export class ClaimId extends Field { - static fromTransit(claim: Claim): ClaimId { - const claimId = `${claim.name}${claim.standard.standardId}${claim.fieldsValue.length}`; - return Poseidon.hash(CircuitString.fromString(claimId).toFields()); - } +export const mkClaimId = (claim: Claim) : ClaimId => { + const claimId = `${claim.name}${claim.standard.standardId}${claim.fieldsValue.length}`; + return Poseidon.hash(CircuitString.fromString(claimId).toFields()); } +/** The claim's value that end up in the merkle tree + will be the concatenation of the claim's id and the claim's + fieldsValue. + + You have to know both the claim's id and the claim's fieldsValue + to know its merkle value and determine whether it is in the credential + (merkle map) or not. + */ +export const mkClaimMerkleValue = (claim: Claim): Field => { + const claimId = mkClaimId(claim); + const value = fieldsFromHex(claim.fieldsValue); + return mkClaimMerkleValueProvable(claimId, value); +} + +/** The credential claim merkle tree has leaves that are constructed by + concatenating the claim's id and the claim's fieldsValue. + */ +export const mkClaimMerkleValueProvable = (claimId: Field, claimValue: Field[]) : Field => { + return Poseidon.hash([claimId, ...claimValue]); +}; + + /** For the convenience and encapsulation of working with claims in the o1js written circuits, let's build a structure holding all the data conveniently and in one place */ +export class ClaimData { + constructor( + public readonly claim: Claim, + ) {} -type ClaimData = { - claimId: ClaimId; - claim: Claim; - getWitness(): MerkleMapWitness; -}; + public get claimId() : ClaimId { + return mkClaimId(this.claim); + } + + public get claimMerkleValue() : Field { + return mkClaimMerkleValue(this.claim); + } + public getWitness(m: MerkleMap) : MerkleMapWitness { + return m.getWitness(this.claimId); + } +} + +/** + * Manages a collection of claims as a Merkle map, facilitating cryptographic operations + * and efficient verification processes. The `ClaimMap` class provides methods to manipulate + * and query claim data wrapped in a Merkle tree structure, ensuring integrity and security + * of the claim data. + * + * Attributes: + * - claimIdMap: A dictionary mapping claim IDs to their corresponding `ClaimData` objects. + * - claims: The original dictionary of claim keys to `ClaimData` objects. + * - merkleMap: The MerkleMap instance that holds the structured data of claims. + * + * Methods: + * - getWitness(claimData): Retrieves the Merkle map witness for a given claim, essential for + * cryptographic proofs. + * - getMerkleValue(claimData): Returns the Merkle value of a claim (not a key!) + * - getRoot(): Returns the root of the Merkle map, representing the summary of all claims. + * - getClaimById(claimId): Fetches a claim by its ID from the map, returning the associated `ClaimData`. + * + * Usage: + * The class is constructed internally via a static method `fromTransit`, which converts a set of + * credential claims into a `ClaimMap`. This approach encapsulates the complexity of initializing + * and populating the Merkle tree structure. + */ export class ClaimMap { public readonly claimIdMap: Record; @@ -62,6 +120,14 @@ export class ClaimMap { }); } + public getWitness(claimName: string) : MerkleMapWitness { + return this.claims[claimName].getWitness(this.merkleMap); + } + + public getMerkleValue(claimName: string) : Field { + return this.claims[claimName].claimMerkleValue; + } + public getRoot() { return this.merkleMap.getRoot(); } @@ -70,180 +136,24 @@ export class ClaimMap { return this.claimIdMap[claimId.toString()]; } + /** Create a ClaimMap from a credential's claims. */ static fromTransit(claims: CredentialDataClaims) { const merkleMap = new MerkleMap(); - const claimData = mapObject(claims, ({ key: newKey, value: claim }) => { - const claimId = ClaimId.fromTransit(claim); - const witness = merkleMap.getWitness(claimId); + // wrap claims in ClaimData + const claimData = mapObject(claims, ({ key, value }) => { + const claimData = new ClaimData(value); return { - newKey, - newValue: { claimId, claim, getWitness: () => witness } + newKey: key, + newValue: claimData }; }); - return new ClaimMap(claimData, merkleMap); - } -} - -// ------------ OLD - -const CLAIMS_MAX_SIZE = 128; - -export interface IClaimStruct { - get length(): Field; - get claimValue(): Field[]; - toFields(): Field[]; -} - -export function mkClaimStruct(claim: Claim): IClaimStruct; -export function mkClaimStruct(flds: Field[]): IClaimStruct; - -export function mkClaimStruct(claim: Claim | Field[]): IClaimStruct { - if (Array.isArray(claim)) { - return ClaimStruct(claim.length).fromFields(claim); - } else { - return ClaimStruct(claim.fieldsValue.length).fromFields( - claim.fieldsValue.map((s) => new Field(s)) - ); - } -} - -export interface IClaimStructClass { - new (claimValue: Field[]): IClaimStruct; - fromFields(fields: Field[]): IClaimStruct; -} - -export interface IFieldClaims { - count: Field; - packed: Field[]; - toFields(): Field[]; - getClaim(ix: Field, assert: Field[]): Field[]; -} - -export const ClaimStruct = (length: number): IClaimStructClass => { - class Claim_ - extends Struct({ - length: Field, - claimValue: Provable.Array(Field, length) - }) - implements IClaimStruct - { - constructor(claimValue: Field[]) { - if (claimValue.length !== length) { - throw new Error(`Invalid claim array size: ${claimValue.length}`); - } - super({ length: new Field(length), claimValue }); - } - - public toFields() { - return [this.length, ...this.claimValue]; - } - - static fromFields(fields: Field[]) { - return new Claim_(fields); - } - - static fromTransit(t: Claim) { - return new Claim_(FieldsSchema.parse(t.fieldsValue)); - } - } - - return Claim_ as IClaimStructClass; -}; - -export const computeClaimSizes = (claims: IClaimStruct[]) => { - return claims.map((c) => ftn(c.length)); -}; - -export const mkClaims = (claims: IClaimStruct[]): IFieldClaims => { - const size = computeClaimSizes(claims); - return Claims(size).fromClaims(claims); -}; - -export function Claims(claimSizes: number[]) { - if (claimSizes.length == 0) { - throw new Error('claimSizes must not be empty.'); - } - const claimCount = claimSizes.length; - // 0 (start index) + indices + claims - const totalSize = 1 + claimCount + claimSizes.reduce((a, v) => a + v, 0); - - if (totalSize > CLAIMS_MAX_SIZE) { - throw new Error( - `Total Claims size ${totalSize} exceeds the maximum size ${CLAIMS_MAX_SIZE}` - ); - } + // populate the merkle map + Object.values(claimData).forEach((c: ClaimData) => { + merkleMap.set(c.claimId, c.claimMerkleValue); + }); - class Claims_ - extends Struct({ - count: Field, - packed: Provable.Array(Field, totalSize) - }) - implements IFieldClaims - { - static MAX_SIZE = CLAIMS_MAX_SIZE; - - public toFields() { - return [this.count, ...this.packed]; - } - - static fromTransit(claims: Claim[]) { - const receivedSizes = claims.map((c) => c.fieldsValue.length); - - if (!arraysAreEqual(receivedSizes, claimSizes)) { - throw new Error("'claims' array sizes are invalid"); - } - return Claims(receivedSizes).fromClaims(claims.map(mkClaimStruct)); - } - - static fromClaims(claims: IClaimStruct[]) { - const receivedSizes = claims.map((c) => ftn(c.length)); - - if (!arraysAreEqual(receivedSizes, claimSizes)) { - throw new Error("'claims' array sizes are invalid"); - } - - let packed: Field[] = []; - // first push all locations - packed.push(new Field(0)); - for (let i = 0; i < claims.length; i++) { - const claimEndIx = packed[i].add(claims[i].length); - packed.push(claimEndIx); - } - // then push all values - for (const claim of claims) { - packed.push(...claim.claimValue); - } - - return new Claims_({ count: new Field(claims.length), packed }); - } - - // the provable code control flow cannot depend on the numbers - // gotten from inputs - public getClaim(ix: Field, assert: Field[]): Field[] { - const i = Number(ix.toBigInt()); - const length = Number(this.packed[i + 1].sub(this.packed[i]).toBigInt()); - - const op = Provable.witness(Provable.Array(Field, length), () => { - const c = Number(this.count.toBigInt()); - const start = Number(this.packed[i].toBigInt()); - const next = Number(this.packed[i + 1].toBigInt()); - return this.packed.slice(c + 1 + start, c + 1 + next); - }); - - for (let j = 0; j < length; j++) { - op[j].assertEquals(assert[j]); - } - - return op; - } + return new ClaimMap(claimData, merkleMap); } - - return Claims_; -} - -export function mkClaimStructs(claims: Claim[]): IFieldClaims { - const claimSizes = claims.map((c) => c.fieldsValue.length); - return Claims(claimSizes).fromTransit(claims); } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts index 625316b..ee83db9 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts @@ -1,57 +1,99 @@ -import { Field } from "o1js"; -import { ClaimStruct, mkClaims } from "./claim.js"; - -describe('ClaimStruct', () => { - it('should create a claim with the correct length and values', () => { - const claimLength = 3; - const claimValues = [new Field(1), new Field(2), new Field(3)]; - const Claim = ClaimStruct(claimLength); - const claimInstance = new Claim(claimValues); - - expect(claimInstance.length.toBigInt()).toBe(BigInt(claimLength)); - expect(claimInstance.claimValue).toEqual(claimValues); - expect(claimInstance.toFields()).toEqual([new Field(claimLength), ...claimValues]); +import { dateOfBirthClaim, sampleCredential1 } from '../..//test_fixtures/transit-data.test.js'; +import { Claim } from '../transit/cred.js'; +import { ClaimData, ClaimMap, mkClaimId, mkClaimMerkleValue } from './claim.js'; // Import the functions to test +import { MerkleMap } from 'o1js'; // Ensure all dependencies are imported +// import { Logger } from 'tslog'; + +// const log = new Logger({name: 'claim.tests'}); + +describe('mkClaimId function', () => { + it('claimids are different for different data', () => { + // Deep copy the `dateOfBirthClaim` for each test instance + const claim1: Claim = JSON.parse(JSON.stringify(dateOfBirthClaim)); + let claim2: Claim = JSON.parse(JSON.stringify(dateOfBirthClaim)); + claim2.name = "exampleClaim"; + + let claim3: Claim = JSON.parse(JSON.stringify(dateOfBirthClaim)); + claim3.standard.standardId = "STD1234"; + + let claim4: Claim = JSON.parse(JSON.stringify(dateOfBirthClaim)); + claim4.fieldsValue = ["0x1234abcd", "0x1234abcd"]; + + // the claim ids should be different + const claims = [claim1, claim2, claim3, claim4]; + const claimIds = claims.map(claim => mkClaimId(claim)); + + for (let i = 0; i < claimIds.length; i++) { + // same for same claim + expect(claimIds[i].equals(mkClaimId(claims[i])).toBoolean()).toBe(true); + for (let j = i + 1; j < claimIds.length; j++) { + expect(claimIds[i].equals(claimIds[j]).toBoolean()).toBe(false); + } + } }); - it('should throw an error for mismatched length and values', () => { - const claimLength = 2; - const claimValues = [new Field(1), new Field(2), new Field(3)]; // Intentional mismatch in lengths - const Claim = ClaimStruct(claimLength); - expect(() => new Claim(claimValues)).toThrow() + it('claim merkle values are properly constructed', () => { + // Deep copy the `dateOfBirthClaim` for each test instance + const claim1: Claim = JSON.parse(JSON.stringify(dateOfBirthClaim)); + let claim2: Claim = JSON.parse(JSON.stringify(dateOfBirthClaim)); + let claim3: Claim = JSON.parse(JSON.stringify(dateOfBirthClaim)); + claim2.fieldsValue = ["0x1234abcd"]; + + const id1 = mkClaimId(claim1); + const id2 = mkClaimId(claim2); + expect(id1.equals(id2).toBoolean()).toBe(true); + + // the claim ids should be the same but values different + const merkleValue1 = mkClaimMerkleValue(claim1); + const merkleValue2 = mkClaimMerkleValue(claim2); + expect(merkleValue1.equals(merkleValue2).toBoolean()).toBe(false); }); }); -describe('Claims', () => { - it('should create Claims with correct structure', () => { - - const claim1 = new (ClaimStruct(1))([new Field(1)]); - const claim2 = new (ClaimStruct(2))([new Field(21), new Field(22)]); - const claims = [claim1, claim2]; - const claimsInstance = mkClaims(claims); +describe('ClaimMap class', () => { + const credential = sampleCredential1; + it('should initialize correctly from transit data', () => { + const claimMap = ClaimMap.fromTransit(credential.claims); + expect(claimMap).toBeDefined(); + expect(Object.keys(claimMap.claimIdMap).length).toBe(2); + expect(Object.keys(claimMap.claims).length).toBe(2); + }); - expect(claimsInstance.count.toBigInt()).toBe(BigInt(2)); + it('should return the correct Merkle root', () => { + const claimMap = ClaimMap.fromTransit(credential.claims); - const asNumbers = claimsInstance.toFields().map(f => Number(f.toBigInt())); + //compute expected root + const m = new MerkleMap(); + Object.values(credential.claims).forEach(claim => { + const claimId = mkClaimId(claim); + const claimValue = mkClaimMerkleValue(claim); + m.set(claimId, claimValue); + }); - const expected = [2, 0, 1, 3, 1, 21, 22]; + expect(claimMap.getRoot().equals(m.getRoot()).toBoolean()).toBe(true); - expect(asNumbers).toEqual(expected); }); - it('should retrieve correct claim data', () => { - const claim1 = new (ClaimStruct(1))([new Field(1)]); - const claim2 = new (ClaimStruct(2))([new Field(21), new Field(22)]); - const claims = [claim1, claim2]; - const claimsInstance = mkClaims(claims); + it('merkle witnesses work as expected', () => { + const claimMap = ClaimMap.fromTransit(credential.claims); + const ns = ["dateOfBirth", "citizenship"] + ns.forEach(n => { + const witness = claimMap.getWitness(n); + const value = claimMap.getMerkleValue(n); - const claim1Retrieved = claimsInstance.getClaim(new Field(0), [new Field(1)]); - const claim2Retrieved = claimsInstance.getClaim(new Field(1), [new Field(21), new Field(22)]); + const [root, key] = witness.computeRootAndKey(value); - expect(claim1Retrieved).toHaveLength(1); - expect(claim1Retrieved[0].toBigInt()).toBe(BigInt(1)); - expect(claim2Retrieved).toHaveLength(2); - expect(claim2Retrieved[0].toBigInt()).toBe(BigInt(21)); - expect(claim2Retrieved[1].toBigInt()).toBe(BigInt(22)); + expect(root.equals(claimMap.getRoot()).toBoolean()).toBe(true); + expect(key.equals(mkClaimId(credential.claims[n])).toBoolean()).toBe(true); + }); }); -} - ); + + it('should retrieve the correct claim by ID', () => { + const claimMap = ClaimMap.fromTransit(credential.claims); + const claimData = new ClaimData(dateOfBirthClaim); + const retrievedClaim = claimMap.getClaimById(claimData.claimId); + + expect(retrievedClaim).toBeDefined(); + expect(retrievedClaim.claim).toEqual(dateOfBirthClaim); + }); +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts index d4386ac..49145dd 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts @@ -1,150 +1,138 @@ -// import { Field, PrivateKey, Signature } from 'o1js'; -// import { IVCredStruct, VCredStruct, VCredStructUnsigned, mkVCredStruct } from './vcred.js'; // Update import path as needed -// import { IClaimStruct, mkClaimStruct, mkClaims } from './claim.js'; // Import necessary dependencies -// import { CredSubjectId, IssuerId, VCredId } from './ids.js'; -// import { UnixTimestamp } from './common.js'; -// import { Claim, Credential, CredentialData, CredentialStandard } from '../transit/cred.js'; - -// describe('VCredStruct tests', () => { -// const pk1 = PrivateKey.random().toPublicKey(); -// const pk1s: string = pk1.toBase58(); -// const pk2 = PrivateKey.random().toPublicKey(); -// const pk2s = pk2.toBase58(); - -// // dummy standard -// const DummyStandard: CredentialStandard = { -// standardId: 'dummy', -// description: 'Dummy standard', -// schema: { -// claim1: { -// standardId: 'dummy', -// description: 'Dummy claim 1', -// fieldsConversion: { -// length: 1, -// description: 'Dummy claim 1', -// codeExample: '' -// } -// }, -// claim2:{ -// standardId: 'dummy', -// description: 'Dummy claim 2', -// fieldsConversion: { -// length: 2, -// description: 'Dummy claim 2', -// codeExample: '' -// } -// } -// } -// }; -// const claim1s: Claim = { -// name: 'claim1', -// value: '0x123', -// fieldsValue: ["0x123"], -// standard: DummyStandard.schema.claim1 -// }; -// const claim2s = { -// name: 'claim2', -// value: '0x456,0x789', -// fieldsValue: ["0x456", "0x789"], -// standard: DummyStandard.schema.claim2 -// }; - -// let claim1: IClaimStruct; -// let claim2: IClaimStruct; - - -// beforeAll(() => { -// claim1 = mkClaimStruct(claim1s); -// claim2 = mkClaimStruct(claim2s); -// }); - -// const ClaimSizes = [3, 2]; -// const VCredStructUnsignedType = VCredStructUnsigned(ClaimSizes); -// const VCredStructType = VCredStruct(ClaimSizes); - -// const testData = () => { -// return { -// id: new VCredId({ id: new Field(123) }), -// issuer: new IssuerId({ pubkey: pk1 }), -// issuanceDate: new UnixTimestamp({ unixTimestamp: new Field(1711897450) }), -// expirationDate: new UnixTimestamp({ -// unixTimestamp: new Field(1721897450) -// }), -// subject: new CredSubjectId({ pubkey: pk2 }), -// claims: mkClaims([claim1, claim2]), -// credentialStandardHash: new Field(789) -// }; -// }; - -// describe('VCredStructUnsigned', () => { -// it('should instantiate correctly with valid data', () => { -// const instance = new VCredStructUnsignedType(testData()); -// expect(instance).toBeInstanceOf(VCredStructUnsignedType); -// expect(instance.toFields()).toEqual( -// expect.arrayContaining([expect.any(Field)]) -// ); -// }); - -// it('should parse from credential data transit type', () => { -// const data: CredentialData = { -// id: '123', -// issuer: { pubkey: pk1s }, -// issuanceDate: '1711897450', -// expirationDate: '1721897450', -// subject: { pubkey: pk2s }, -// claims: { -// claim1: claim1s, -// claim2: claim2s -// }, -// credentialStandardHash: '789' -// } -// const res: IVCredStruct = mkVCredStruct(data) -// expect(res).toBeDefined(); -// }); -// }); - -// describe('VCredStruct', () => { -// const testDataSig = () => { -// return { -// id: new VCredId({ id: new Field(123) }), -// issuer: new IssuerId({ pubkey: pk1 }), -// issuanceDate: new UnixTimestamp({ -// unixTimestamp: new Field(123123123) -// }), -// expirationDate: new UnixTimestamp({ -// unixTimestamp: new Field(223123123) -// }), -// subject: new CredSubjectId({ pubkey: pk2 }), -// claims: mkClaims([claim1, claim2]), -// credentialStandardHash: new Field(789), -// signature: Signature.fromBase58('7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE') -// }; -// }; - -// it('should instantiate correctly with valid data, including signature', () => { -// const instance = new VCredStructType(testDataSig()); -// expect(instance).toBeInstanceOf(VCredStructType); -// expect(instance.toFields()).toEqual( -// expect.arrayContaining([expect.any(Field)]) -// ); -// }); - -// it('should have a valid schema including signature', () => { -// const cred: Credential = { -// id: '123', -// issuer: { pubkey: pk1s }, -// issuanceDate: '1711897450', -// expirationDate: '1721897450', -// subject: { pubkey: pk2s }, -// claims: { -// claim1: claim1s, -// claim2: claim2s -// }, -// credentialStandardHash: '789', -// signature: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' -// }; -// const res: IVCredStruct = mkVCredStruct(cred) -// expect(res).toBeDefined(); -// }); -// }); -// }); +import { sampleCredential1 } from '../..//test_fixtures/transit-data.test.js'; +import { CredentialData } from '../transit/cred.js'; +import { IssuerId } from './ids.js'; +import { + CredentialStandardMerkleTreeHeight, + VCredDataStruct, + VCredProofHelper, + VCredStruct, + mkCredentialTypeId +} from './vcred.js'; +import { Field, MerkleTree, MerkleWitness, Poseidon, PrivateKey, PublicKey, ZkProgram, public_, verify } from 'o1js'; +// import { Logger } from 'tslog'; + +// const log = new Logger({name: 'claim.tests'}); + +describe('o1js vcred tests', () => { + const credential = sampleCredential1; + const credentialData: CredentialData = credential; + it('o1js vcred from transit', () => { + const vcred: VCredDataStruct = VCredDataStruct.fromTransit(credentialData); + expect(vcred).toBeDefined(); + + const flds = vcred.toFields(); + expect(flds).toBeDefined(); + + const vcred2: VCredStruct = VCredStruct.fromTransit(credential); + expect(vcred2).toBeDefined(); + + const flds2 = vcred2.toFields(); + expect(flds2).toBeDefined(); + + const flds3 = vcred2.dataToFields(); + expect(flds3.length).toBe(flds.length); + for (let i = 0; i < flds.length; i++) { + expect(flds[i].equals(flds3[i]).toBoolean()).toBe(true); + } + }); + + it('proof helper works as expected', () => { + const ph = VCredProofHelper.forCredential(credential); + expect(ph).toBeDefined(); + }); + + describe('mkCredentialTypeId', () => { + // Reset mocks before each test + beforeEach(() => {}); + + test('should throw an error if issuers array is empty', () => { + const issuers: IssuerId[] = []; + const standards: Field[] = [new Field(0)]; + expect(() => mkCredentialTypeId(issuers, standards)).toThrow( + 'Cannot create a credential type id without any input hashes' + ); + }); + + test('should throw an error if credential standards array is empty', () => { + const issuers = [ + new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }) + ]; + const standards: Field[] = []; + expect(() => mkCredentialTypeId(issuers, standards)).toThrow( + 'Cannot create a credential type id without any input hashes' + ); + }); + + test('should compute hash without errors with one issuer and one standard', () => { + const issuers = [ + new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }) + ]; + const standards = [new Field(1)]; + const result = mkCredentialTypeId(issuers, standards); + expect(result).toBeDefined(); + }); + + test('should compute hash correctly with multiple issuers and standards', () => { + const issuers = [ + new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }), + new IssuerId({ pubkey: PrivateKey.random().toPublicKey()}) + ]; + const standards = [new Field(1), new Field(2)]; + const result = mkCredentialTypeId(issuers, standards); + expect(result).toBeDefined(); + }); + + test('One can recreate the computation in provable code', async () => { + + class MyMerkleWitness extends MerkleWitness(CredentialStandardMerkleTreeHeight) {} + + const issuerId1 = new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }); + const issuerId2 = new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }); + const issuers = [ issuerId1, issuerId2 ]; + + const m1 = new MerkleTree(CredentialStandardMerkleTreeHeight); + m1.fill(issuers.map((issuer) => Poseidon.hash(issuer.pubkey.toFields()))); + const rootIssuers = m1.getRoot(); + const issuer1Witness = new MyMerkleWitness(m1.getWitness(BigInt(0))); + + const standards = [new Field(1), new Field(2)]; + const result = mkCredentialTypeId(issuers, standards); + + const m2 = new MerkleTree(CredentialStandardMerkleTreeHeight); + m2.fill(standards); + const rootStandards = m2.getRoot(); + const standard2Witness = new MyMerkleWitness(m2.getWitness(BigInt(1))); + + const MyProg = ZkProgram( + { + name: "test" + , publicInput: Field + , methods: + { + test: + { + privateInputs: [PublicKey, Field, MyMerkleWitness, MyMerkleWitness] + , method(publicInput: Field, issuerPubkey: PublicKey, standardIdHash: Field, witness1: MyMerkleWitness, witness2: MyMerkleWitness) { + const root1 = witness1.calculateRoot(Poseidon.hash(issuerPubkey.toFields())); + const root2 = witness2.calculateRoot(standardIdHash); + const result = Poseidon.hash([root1, root2]); + result.assertEquals(publicInput); + } + } + } + }); + + const { verificationKey } = await MyProg.compile(); + + const proof = await MyProg.test( + result, + issuerId1.pubkey, + standards[1], + issuer1Witness, + standard2Witness + ); + + await expect(verify(proof, verificationKey)).resolves.toBe(true); + }, 100000); + }); +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index f50b3d9..6c21275 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -1,15 +1,15 @@ -/* DEV: Due to a misconception I've had on how Provable.witness and the level - of dynamism that circuits can have, I have to re-write this module - so that claims in the forms suitable for the zk program are represented - as a MerkleMap. -*/ - -import { Struct, Field, Signature, Poseidon } from 'o1js'; +import { Struct, Field, Signature, Poseidon, MerkleTree } from 'o1js'; import { SignatureSchema, FieldSchema, UnixTimestamp } from './common.js'; import { ClaimMap } from './claim.js'; import { CredSubjectId, IssuerId, VCredId } from './ids.js'; import { Credential, CredentialData } from '../transit/cred.js'; +/** One can test membership of credential standard and issuer + by membership tests in a merkle tree. + 2^7 = 128 should be enough + */ +export const CredentialStandardMerkleTreeHeight = 8; + export const VCredStructUnsignedFields = { id: VCredId, issuer: IssuerId, @@ -25,14 +25,40 @@ export const VCredStructFields = { signature: Signature }; -export class VCredTypeId extends Field { - static forVCred(vcred: VCredDataStruct): VCredTypeId { - return new VCredTypeId(Poseidon.hash([ - vcred.credentialStandardHash, - ...vcred.issuer.pubkey.toFields() - ])); - } -} +export class VCredTypeId extends Field {} + +/** To verify the credential one will have to derive this id from the credential + and sets of accepted issuers and credential standards. + + Usually it will be only one standard and one or more issuers. + */ +export const mkCredentialTypeId = ( + acceptedIssuers: IssuerId[], + acceptedCredentialStandardHashes: Field[] +): Field => { + const input_hashes = [ + acceptedIssuers.map((issuer) => Poseidon.hash(issuer.pubkey.toFields())), + acceptedCredentialStandardHashes + ]; + const composite_hashes: Field[] = []; + + input_hashes.forEach((hashes) => { + if (hashes.length === 0) { + throw new Error( + 'Cannot create a credential type id without any input hashes' + ); + } + const m = new MerkleTree(CredentialStandardMerkleTreeHeight); + m.fill(hashes); + composite_hashes.push(m.getRoot()); + }); + + return Poseidon.hash(composite_hashes); +}; + +export const mkCredentialTypeIdForVCred = (vcred: VCredStruct): Field => { + return mkCredentialTypeId([vcred.issuer], [vcred.credentialStandardHash]); +}; /** This is an o1js representation of a credential data that is diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts index 425779e..2cd532a 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts @@ -25,6 +25,12 @@ export const FieldSchemaHex = z export const FieldSchema = z.union([FieldSchemaInt, FieldSchemaBigInt, FieldSchemaDec, FieldSchemaHex]); export const FieldsSchema = z.array(FieldSchema); +export type FieldString = z.infer; +export type FieldsString = z.infer; + +export const fieldFromHex = (x: FieldString) => new Field(BigInt(x)); +export const fieldsFromHex = (x: FieldsString) => x.map(fieldFromHex); + // ========= Base58 string schemas ========= export const Base58Schema = z.string().regex(/^[A-HJ-NP-Za-km-z1-9]+$/); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts index ba53c6a..a3708bc 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts @@ -1,5 +1,6 @@ // import { Field } from 'o1js'; -import { CredentialDataSchema, CredentialSchema, CredentialStandard, CredentialStandardSchema } from './cred.js'; +import { citizenshipClaim, credentialStandard1, dateOfBirthClaim } from 'src/test_fixtures/transit-data.test.js'; +import { Claim, CredentialDataSchema, CredentialSchema, CredentialStandard, CredentialStandardSchema } from './cred.js'; describe('Credential creation and validation tests', () => { let KnownUserCredential: CredentialStandard; @@ -7,18 +8,8 @@ describe('Credential creation and validation tests', () => { // based on schema let CredentialDataRaw1: { claims: { - dateOfBirth: { - name: string; - value: string; - fieldsValue: number[]; - standard: typeof KnownUserCredential.schema.dateOfBirth; - }; - citizenship: { - name: string; - value: string; - fieldsValue: number[]; - standard: typeof KnownUserCredential.schema.citizenship; - }; + dateOfBirth: Claim; + citizenship: Claim; }; id: string; issuer: { pubkey: string }; @@ -30,18 +21,8 @@ describe('Credential creation and validation tests', () => { let Credential1Raw: { claims: { - dateOfBirth: { - name: string; - value: string; - fieldsValue: number[]; - standard: typeof KnownUserCredential.schema.dateOfBirth; - }; - citizenship: { - name: string; - value: string; - fieldsValue: number[]; - standard: typeof KnownUserCredential.schema.citizenship; - }; + dateOfBirth: Claim; + citizenship: Claim; }; id: string; issuer: { @@ -57,55 +38,11 @@ describe('Credential creation and validation tests', () => { }; beforeEach(() => { - KnownUserCredential = { - standardId: 'eth.example.KnownUserCredential-v1.0', - description: - 'Credential that will be given to users after verification of documents.', - schema: { - dateOfBirth: { - standardId: 'dateOfBirth', - description: - 'Date of birth as stated on provided national id or a passport', - referenceToExternalStandard: - 'The format is described here https://www.w3.org/TR/xmlschema11-2/#dateTime', - fieldsConversion: { - length: 1, - description: - 'Converts the date to unix timestamp (seconds) and then to a single o1js Field.', - codeExample: - '// for example using `luxon.DateTime`\n return new Field(BigInt(cred.dateOfBirth.toUtc().toUnixInteger()));' - } - }, - citizenship: { - standardId: 'citizenship', - description: - 'Country citizenship as confirmed by verified documentation. Only single-country citizenships supported.', - referenceToExternalStandard: - 'The citizenship is in the form of a country code following the standard ISO 3166-1 alpha-3', - fieldsConversion: { - length: 3, - description: - 'Each of 3 letter is represented as a field using o1js.CircuitString.fromString', - codeExample: - 'o1js.CircuitString.fromString(cred.citizenship).toFields()' - } - } - } - }; + KnownUserCredential = credentialStandard1 ; CredentialDataRaw1 = { claims: { - dateOfBirth: { - name: 'dateOfBirth', - value: '1990-01-01T00:00:00Z', - fieldsValue: [631152000], - standard: KnownUserCredential.schema.dateOfBirth - }, - citizenship: { - name: 'citizenship', - value: 'USA', - fieldsValue: [0x5541, 0x5341, 0x0000], - standard: KnownUserCredential.schema.citizenship - } + dateOfBirth: dateOfBirthClaim, + citizenship: citizenshipClaim }, id: '0x1234567890', issuer: { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/claims.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/claims.test.ts new file mode 100644 index 0000000..e69de29 diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/credentials.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/credentials.test.ts new file mode 100644 index 0000000..e69de29 diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit-data.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit-data.test.ts new file mode 100644 index 0000000..a4736cd --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit-data.test.ts @@ -0,0 +1,76 @@ +import { Claim, Credential, CredentialData, CredentialStandard } from '../data/transit/cred.js'; + +export const credentialStandard1: CredentialStandard = { + standardId: 'eth.example.KnownUserCredential-v1.0', + description: + 'Credential that will be given to users after verification of documents.', + schema: { + dateOfBirth: { + standardId: 'dateOfBirth', + description: + 'Date of birth as stated on provided national id or a passport', + referenceToExternalStandard: + 'The format is described here https://www.w3.org/TR/xmlschema11-2/#dateTime', + fieldsConversion: { + length: 1, + description: + 'Converts the date to unix timestamp (seconds) and then to a single o1js Field.', + codeExample: + '// for example using `luxon.DateTime`\n return new Field(BigInt(cred.dateOfBirth.toUtc().toUnixInteger()));' + } + }, + citizenship: { + standardId: 'citizenship', + description: + 'Country citizenship as confirmed by verified documentation. Only single-country citizenships supported.', + referenceToExternalStandard: + 'The citizenship is in the form of a country code following the standard ISO 3166-1 alpha-3', + fieldsConversion: { + length: 3, + description: + 'Each of 3 letter is represented as a field using o1js.CircuitString.fromString', + codeExample: + 'o1js.CircuitString.fromString(cred.citizenship).toFields()' + } + } + } +}; + +export const dateOfBirthClaim: Claim = { + name: 'dateOfBirth', + value: '1990-01-01T00:00:00Z', + fieldsValue: ['0x662bc83b'], + standard: credentialStandard1.schema.dateOfBirth +}; + +export const citizenshipClaim: Claim = { + name: 'citizenship', + value: 'USA', + fieldsValue: ['0x5541', '0x5341', '0x5341'], + standard: credentialStandard1.schema.citizenship +}; + + +export const credentialData1: CredentialData = +{ + claims: { + dateOfBirth: dateOfBirthClaim, + citizenship: citizenshipClaim + }, + id: '0x1234567890', + issuer: { + pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' + }, + issuanceDate: '2023-01-01T00:00:00Z', + expirationDate: '2028-01-01T00:00:00Z', + subject: { + pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' + }, + credentialStandardHash: + '0x25F1E2728547794B6147CBEC641301AEFC2F5ACE1EE5F9C98B52A110460EF661' +} + +export const sampleCredential1: Credential = { + ...credentialData1, + signature: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json b/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json index 0422d60..412dfc0 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json @@ -24,5 +24,5 @@ "ts-node": { "require": ["tsconfig-paths/register"] }, - "exclude": ["node_modules", "**/*.spec.ts"] + "exclude": ["node_modules", "**/*.spec.ts", "src/**/*dev.ts"] } From 7055a392bfeeec025c155b5fd0b7716068ea59db Mon Sep 17 00:00:00 2001 From: adamczykm Date: Fri, 26 Apr 2024 21:54:16 +0200 Subject: [PATCH 31/34] Add better credential verifiaction to the validation program --- .../src/circuit/vcred-proof.ts | 41 +++++++++++++------ .../src/data/o1js/vcred.ts | 16 +++++++- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts index d3c8c42..f3bf51f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts @@ -6,7 +6,7 @@ import { DateTime } from "luxon"; import { Bool, Field, Poseidon, PrivateKey, Provable, PublicKey, Struct, ZkProgram } from "o1js"; import { UnixTimestamp } from "../data/o1js/common.js"; -import { VCredProofHelper, VCredStruct, VCredTypeId } from "../data/o1js/vcred.js"; +import { VCredMerkleWitness, VCredProofHelper, VCredStruct, VCredTypeId } from "../data/o1js/vcred.js"; import { Credential } from "../data/transit/cred.js"; /** @@ -15,7 +15,8 @@ import { Credential } from "../data/transit/cred.js"; export class VCredProofPublicInput extends Struct ({ validFrom: UnixTimestamp, validTo: UnixTimestamp, - credentialTypeId: Field, + // Hash of merkle roots + credentialTypeMembershipProof: Field, proverIsSubject: Bool, }) {} @@ -25,6 +26,8 @@ export class VCredProofPublicInput extends Struct ({ export class VCredProofPrivateInput extends Struct({ subjectPrivkey: PrivateKey, credentialData: VCredStruct, + issuerPubkeyWitness: VCredMerkleWitness, + standardIdWitness: VCredMerkleWitness }) {} /** @@ -50,7 +53,7 @@ export const ValidateVCredProgram = ZkProgram({ publicOutput: VCredProofPublicOutput, methods: { validate: { - privateInputs: [ VCredProofPrivateInput ], + privateInputs: [VCredProofPrivateInput], method( publicInput: VCredProofPublicInput, privateInput: VCredProofPrivateInput @@ -58,13 +61,19 @@ export const ValidateVCredProgram = ZkProgram({ const cred = privateInput.credentialData; - // TODO - // // Ensure the credential type matches the expected type. - // const actualCredType = VCredTypeId.forVCred(cred) - // publicInput.credentialTypeId.assertEquals( - // actualCredType, - // "Credential type does not match the expected type." - // ); + // -- verify credential type membership proof + const issuerRoot = privateInput.issuerPubkeyWitness.calculateRoot( + Poseidon.hash(cred.issuer.pubkey.toFields()) + ); + const standardRoot = privateInput.standardIdWitness.calculateRoot( + privateInput.credentialData.credentialStandardHash + ); + const credentialTypeMembershipProof = Poseidon.hash([issuerRoot, standardRoot]); + publicInput.credentialTypeMembershipProof.assertEquals( + credentialTypeMembershipProof, + "Credential type membership proof does not match the expected value." + ); + // -- // Verify the credential's signature. cred.signature.verify(cred.issuer.pubkey, cred.dataToFields()) @@ -112,7 +121,7 @@ export type SecretInput = { } export type CredentialValidityProofParameters = { - credentialTypeId: VCredTypeId, + credentialTypeMembershipProof: Field, validFrom: DateTime, validTo: DateTime, proverIsSubject: boolean, @@ -133,11 +142,15 @@ export const proveCredentialValidity = compileProver = true) : Promise => { + // todo + const issuerPubkeyWitness: VCredMerkleWitness = undefined as unknown as VCredMerkleWitness + const standardIdWitness: VCredMerkleWitness= undefined as unknown as VCredMerkleWitness + // convert parameters to public input const publicInput = new VCredProofPublicInput({ validFrom: new UnixTimestamp({unixTimestamp: new Field(params.validFrom.toUTC().toUnixInteger())}), validTo: new UnixTimestamp({ unixTimestamp: new Field(params.validTo.toUTC().toUnixInteger()) }), - credentialTypeId: params.credentialTypeId, + credentialTypeMembershipProof: params.credentialTypeMembershipProof, proverIsSubject: new Bool(params.proverIsSubject) }); @@ -145,7 +158,9 @@ export const proveCredentialValidity = const privateInput = new VCredProofPrivateInput({ subjectPrivkey: secretInput.subjectPrivkey, - credentialData: proofHelper.vcred + credentialData: proofHelper.vcred, + issuerPubkeyWitness, + standardIdWitness }); if (compileProver) { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index 6c21275..1012648 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -1,4 +1,4 @@ -import { Struct, Field, Signature, Poseidon, MerkleTree } from 'o1js'; +import { Struct, Field, Signature, Poseidon, MerkleTree, MerkleWitness } from 'o1js'; import { SignatureSchema, FieldSchema, UnixTimestamp } from './common.js'; import { ClaimMap } from './claim.js'; import { CredSubjectId, IssuerId, VCredId } from './ids.js'; @@ -10,6 +10,14 @@ import { Credential, CredentialData } from '../transit/cred.js'; */ export const CredentialStandardMerkleTreeHeight = 8; +export class VCredMerkleTree extends MerkleTree { + constructor() { + super(CredentialStandardMerkleTreeHeight); + } +} + +export class VCredMerkleWitness extends MerkleWitness(CredentialStandardMerkleTreeHeight) {} + export const VCredStructUnsignedFields = { id: VCredId, issuer: IssuerId, @@ -141,6 +149,12 @@ export class VCredStruct extends Struct(VCredStructFields) { */ +// TODO assume additional information that are required to build +// the proof for example to create these: + + // const issuerPubkeyWitness: VCredMerkleWitness = undefined as unknown as VCredMerkleWitness + // const standardIdWitness: VCredMerkleWitness= undefined as unknown as VCredMerkleWitness + export class VCredProofHelper { public readonly claims: ClaimMap; public readonly vcred: VCredStruct; From 8aa6f5f1318c8f07fc352789c597a1d46c51d40c Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 27 Apr 2024 16:45:45 +0200 Subject: [PATCH 32/34] Add improvements around cred validating and its helper + tests. --- .../src/circuit/vcred-proof.ts | 152 +++++++++--------- .../src/data/o1js/vcred.test.ts | 130 ++++++++++----- .../src/data/o1js/vcred.ts | 141 ++++++++++++++-- .../src/dev.ts | 6 + .../src/index.ts | 4 +- 5 files changed, 309 insertions(+), 124 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/dev.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts index f3bf51f..a7c3e04 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts @@ -1,28 +1,40 @@ /** * This module contains the logic for proving the validity of a credential. * It provides a convenient interface for creating proofs. -*/ - -import { DateTime } from "luxon"; -import { Bool, Field, Poseidon, PrivateKey, Provable, PublicKey, Struct, ZkProgram } from "o1js"; -import { UnixTimestamp } from "../data/o1js/common.js"; -import { VCredMerkleWitness, VCredProofHelper, VCredStruct, VCredTypeId } from "../data/o1js/vcred.js"; -import { Credential } from "../data/transit/cred.js"; + */ + +import { DateTime } from 'luxon'; +import { + Bool, + Field, + Poseidon, + PrivateKey, + Provable, + PublicKey, + Struct, + ZkProgram +} from 'o1js'; +import { UnixTimestamp } from '../data/o1js/common.js'; +import { + VCredMerkleWitness, + VCredProofHelper, + VCredStruct +} from '../data/o1js/vcred.js'; /** - * The public input to the proof of a credential's validity. - */ -export class VCredProofPublicInput extends Struct ({ + * The public input to the proof of a credential's validity. + */ +export class VCredProofPublicInput extends Struct({ validFrom: UnixTimestamp, validTo: UnixTimestamp, // Hash of merkle roots credentialTypeMembershipProof: Field, - proverIsSubject: Bool, + proverIsSubject: Bool }) {} /** - * The private input to the proof of a credential's validity. - */ + * The private input to the proof of a credential's validity. + */ export class VCredProofPrivateInput extends Struct({ subjectPrivkey: PrivateKey, credentialData: VCredStruct, @@ -31,22 +43,21 @@ export class VCredProofPrivateInput extends Struct({ }) {} /** - * The public output of the proof of a credential's validity. - */ + * The public output of the proof of a credential's validity. + */ export class VCredProofPublicOutput extends Struct({ credentialHash: Field, subjectPubkey: PublicKey }) {} - /** - * The actual ZkProgram for proving the validity of a credential. - * Some tests that are used to build the proofs constraints are: - * - The credential type matches the expected type. - * - The credential's issuer signature is valid. - * - The credential is within the validity period. - * - The prover is the subject of the credential. (optional) - */ + * The actual ZkProgram for proving the validity of a credential. + * Some tests that are used to build the proofs constraints are: + * - The credential type matches the expected type. + * - The credential's issuer signature is valid. + * - The credential is within the validity period. + * - The prover is the subject of the credential. (optional) + */ export const ValidateVCredProgram = ZkProgram({ name: 'ValidateVCred', publicInput: VCredProofPublicInput, @@ -58,7 +69,6 @@ export const ValidateVCredProgram = ZkProgram({ publicInput: VCredProofPublicInput, privateInput: VCredProofPrivateInput ): VCredProofPublicOutput { - const cred = privateInput.credentialData; // -- verify credential type membership proof @@ -68,15 +78,18 @@ export const ValidateVCredProgram = ZkProgram({ const standardRoot = privateInput.standardIdWitness.calculateRoot( privateInput.credentialData.credentialStandardHash ); - const credentialTypeMembershipProof = Poseidon.hash([issuerRoot, standardRoot]); + const credentialTypeMembershipProof = Poseidon.hash([ + issuerRoot, + standardRoot + ]); publicInput.credentialTypeMembershipProof.assertEquals( credentialTypeMembershipProof, - "Credential type membership proof does not match the expected value." + 'Credential type membership proof does not match the expected value.' ); // -- // Verify the credential's signature. - cred.signature.verify(cred.issuer.pubkey, cred.dataToFields()) + cred.signature.verify(cred.issuer.pubkey, cred.dataToFields()); // Ensure the credential is within the validity period. publicInput.validFrom.unixTimestamp.assertGreaterThanOrEqual( @@ -96,11 +109,9 @@ export const ValidateVCredProgram = ZkProgram({ privateInput.subjectPrivkey.toPublicKey() ); - subjectPubkey.assertEquals( - privateInput.subjectPrivkey.toPublicKey() - ) + subjectPubkey.assertEquals(privateInput.subjectPrivkey.toPublicKey()); - const credentialHash = Poseidon.hash(cred.dataToFields()) + const credentialHash = Poseidon.hash(cred.dataToFields()); const ret = new VCredProofPublicOutput({ credentialHash, @@ -114,61 +125,50 @@ export const ValidateVCredProgram = ZkProgram({ export class ValidateVCredProof extends ZkProgram.Proof(ValidateVCredProgram) {} - -export type SecretInput = { - credential: Credential, - subjectPrivkey: PrivateKey, -} - -export type CredentialValidityProofParameters = { - credentialTypeMembershipProof: Field, +/** + * Proves the validity of a credential. Details of how the will be constructed can be altered by the parameters. + * + * @param validFrom The date from which the credential is requested to be valid. + * @param validTo The date until which the credential is requested to be valid. + * @param credProofHelper The helper object containing the credential and additional data. + * @param subjectPrivkey The private key of the subject of the credential. If not provided, + * the prover will not try to prove that prover is the subject of the credential. + * @param compileProver Whether to compile the prover before running the proof. + * @returns The proof of the credential's validity. + */ +export const proveCredentialValidity = async ( validFrom: DateTime, validTo: DateTime, - proverIsSubject: boolean, -} - -/** - * Proves the validity of a credential. Details of how the will be constructed can be altered by the parameters. - * - * @param secretInput The secret input to the proof. This includes the credential and the subject's private key. - * @param params The parameters for the proof. This includes the credential type ID, the validity range, and whether the prover should be checked for also being the credential's subject. - * @param compileProver Whether to compile the prover before running the proof. - * @returns The proof of the credential's validity. - */ -export const proveCredentialValidity = - async ( - secretInput: SecretInput, - params: CredentialValidityProofParameters, - compileProver = true) -: Promise => { - - // todo - const issuerPubkeyWitness: VCredMerkleWitness = undefined as unknown as VCredMerkleWitness - const standardIdWitness: VCredMerkleWitness= undefined as unknown as VCredMerkleWitness - - // convert parameters to public input + credProofHelper: VCredProofHelper, + subjectPrivkey?: PrivateKey, + compileProver = true +): Promise => { + // create public input const publicInput = new VCredProofPublicInput({ - validFrom: new UnixTimestamp({unixTimestamp: new Field(params.validFrom.toUTC().toUnixInteger())}), - validTo: new UnixTimestamp({ unixTimestamp: new Field(params.validTo.toUTC().toUnixInteger()) }), - credentialTypeMembershipProof: params.credentialTypeMembershipProof, - proverIsSubject: new Bool(params.proverIsSubject) + validFrom: new UnixTimestamp({ + unixTimestamp: new Field(validFrom.toUTC().toUnixInteger()) + }), + validTo: new UnixTimestamp({ + unixTimestamp: new Field(validTo.toUTC().toUnixInteger()) + }), + credentialTypeMembershipProof: + credProofHelper.credentialTypeMembershipProof, + proverIsSubject: Bool(subjectPrivkey !== undefined) }); - const proofHelper = VCredProofHelper.forCredential(secretInput.credential); - + // create private input const privateInput = new VCredProofPrivateInput({ - subjectPrivkey: secretInput.subjectPrivkey, - credentialData: proofHelper.vcred, - issuerPubkeyWitness, - standardIdWitness + subjectPrivkey: subjectPrivkey || PrivateKey.random(), + credentialData: credProofHelper.vcred, + issuerPubkeyWitness: credProofHelper.issuerMembershipHelper.merkleWitness, + standardIdWitness: credProofHelper.standardMembershipHelper.merkleWitness }); if (compileProver) { await ValidateVCredProgram.compile(); } - const prog = await ValidateVCredProgram.validate(publicInput, privateInput); - - return prog; -} + const proof = await ValidateVCredProgram.validate(publicInput, privateInput); + return proof +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts index 49145dd..50290e3 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts @@ -1,14 +1,25 @@ import { sampleCredential1 } from '../..//test_fixtures/transit-data.test.js'; import { CredentialData } from '../transit/cred.js'; import { IssuerId } from './ids.js'; +import * as T from '../transit/cred.js'; import { CredentialStandardMerkleTreeHeight, + IVCredProofReferenceData, VCredDataStruct, + VCredMerkleWitness, VCredProofHelper, VCredStruct, mkCredentialTypeId } from './vcred.js'; -import { Field, MerkleTree, MerkleWitness, Poseidon, PrivateKey, PublicKey, ZkProgram, public_, verify } from 'o1js'; +import { + Field, + MerkleTree, + Poseidon, + PrivateKey, + PublicKey, + ZkProgram, + verify +} from 'o1js'; // import { Logger } from 'tslog'; // const log = new Logger({name: 'claim.tests'}); @@ -37,7 +48,14 @@ describe('o1js vcred tests', () => { }); it('proof helper works as expected', () => { - const ph = VCredProofHelper.forCredential(credential); + const anotherissuer: T.IssuerId = { + pubkey: PrivateKey.random().toPublicKey().toBase58() + }; + const ref: IVCredProofReferenceData = { + acceptedIssuers: [credential.issuer, anotherissuer], + acceptedStandardHashes: [credential.credentialStandardHash] + }; + const ph = new VCredProofHelper(credential, ref); expect(ph).toBeDefined(); }); @@ -75,64 +93,104 @@ describe('o1js vcred tests', () => { test('should compute hash correctly with multiple issuers and standards', () => { const issuers = [ new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }), - new IssuerId({ pubkey: PrivateKey.random().toPublicKey()}) + new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }) ]; const standards = [new Field(1), new Field(2)]; const result = mkCredentialTypeId(issuers, standards); expect(result).toBeDefined(); }); - test('One can recreate the computation in provable code', async () => { + const mkProof = async ( + result: Field, + issuer: PublicKey, + issuerWitness: VCredMerkleWitness, + standard: Field, + standardWitness: VCredMerkleWitness + ) => { + const MyProg = ZkProgram({ + name: 'test', + publicInput: Field, + methods: { + test: { + privateInputs: [ + PublicKey, + Field, + VCredMerkleWitness, + VCredMerkleWitness + ], + method( + publicInput: Field, + issuerPubkey: PublicKey, + standardIdHash: Field, + witness1: VCredMerkleWitness, + witness2: VCredMerkleWitness + ) { + const root1 = witness1.calculateRoot( + Poseidon.hash(issuerPubkey.toFields()) + ); + const root2 = witness2.calculateRoot(standardIdHash); + const result = Poseidon.hash([root1, root2]); + result.assertEquals(publicInput); + } + } + } + }); + + const { verificationKey } = await MyProg.compile(); - class MyMerkleWitness extends MerkleWitness(CredentialStandardMerkleTreeHeight) {} + const proof = await MyProg.test( + result, + issuer, + standard, + issuerWitness, + standardWitness + ); + + await expect(verify(proof, verificationKey)).resolves.toBe(true); + }; - const issuerId1 = new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }); - const issuerId2 = new IssuerId({ pubkey: PrivateKey.random().toPublicKey() }); - const issuers = [ issuerId1, issuerId2 ]; + test('One can recreate the creential type computation in provable code', async () => { + const issuerId1 = new IssuerId({ + pubkey: PrivateKey.random().toPublicKey() + }); + const issuerId2 = new IssuerId({ + pubkey: PrivateKey.random().toPublicKey() + }); + const issuers = [issuerId1, issuerId2]; const m1 = new MerkleTree(CredentialStandardMerkleTreeHeight); m1.fill(issuers.map((issuer) => Poseidon.hash(issuer.pubkey.toFields()))); - const rootIssuers = m1.getRoot(); - const issuer1Witness = new MyMerkleWitness(m1.getWitness(BigInt(0))); + const issuer1Witness = new VCredMerkleWitness(m1.getWitness(BigInt(0))); const standards = [new Field(1), new Field(2)]; const result = mkCredentialTypeId(issuers, standards); const m2 = new MerkleTree(CredentialStandardMerkleTreeHeight); m2.fill(standards); - const rootStandards = m2.getRoot(); - const standard2Witness = new MyMerkleWitness(m2.getWitness(BigInt(1))); - - const MyProg = ZkProgram( - { - name: "test" - , publicInput: Field - , methods: - { - test: - { - privateInputs: [PublicKey, Field, MyMerkleWitness, MyMerkleWitness] - , method(publicInput: Field, issuerPubkey: PublicKey, standardIdHash: Field, witness1: MyMerkleWitness, witness2: MyMerkleWitness) { - const root1 = witness1.calculateRoot(Poseidon.hash(issuerPubkey.toFields())); - const root2 = witness2.calculateRoot(standardIdHash); - const result = Poseidon.hash([root1, root2]); - result.assertEquals(publicInput); - } - } - } - }); + const standard2Witness = new VCredMerkleWitness(m2.getWitness(BigInt(1))); - const { verificationKey } = await MyProg.compile(); - - const proof = await MyProg.test( + await mkProof( result, issuerId1.pubkey, - standards[1], issuer1Witness, + standards[1], standard2Witness ); + }, 100000); - await expect(verify(proof, verificationKey)).resolves.toBe(true); + test('Helpers help create the credential type validation in provable code', async () => { + const helper = new VCredProofHelper(credential, { + acceptedIssuers: [credential.issuer], + acceptedStandardHashes: [credential.credentialStandardHash] + }); + + await mkProof( + helper.credentialTypeMembershipProof, + helper.vcred.issuer.pubkey, + helper.issuerMembershipHelper.merkleWitness, + helper.vcred.credentialStandardHash, + helper.standardMembershipHelper.merkleWitness + ); }, 100000); }); }); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index 1012648..404b00e 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -1,8 +1,21 @@ -import { Struct, Field, Signature, Poseidon, MerkleTree, MerkleWitness } from 'o1js'; +import { + Struct, + Field, + Signature, + Poseidon, + MerkleTree, + MerkleWitness, + PublicKey +} from 'o1js'; import { SignatureSchema, FieldSchema, UnixTimestamp } from './common.js'; import { ClaimMap } from './claim.js'; import { CredSubjectId, IssuerId, VCredId } from './ids.js'; +import * as T from '../transit/cred.js'; import { Credential, CredentialData } from '../transit/cred.js'; +import { FieldString, fieldFromHex } from '../transit/common.js'; +import { mklog } from '../../dev.js' + +const log = mklog('vcred.ts'); /** One can test membership of credential standard and issuer by membership tests in a merkle tree. @@ -16,7 +29,9 @@ export class VCredMerkleTree extends MerkleTree { } } -export class VCredMerkleWitness extends MerkleWitness(CredentialStandardMerkleTreeHeight) {} +export class VCredMerkleWitness extends MerkleWitness( + CredentialStandardMerkleTreeHeight +) {} export const VCredStructUnsignedFields = { id: VCredId, @@ -148,31 +163,97 @@ export class VCredStruct extends Struct(VCredStructFields) { that is ready to be signed by issuer */ +export interface IVCredProofReferenceData { + acceptedIssuers: T.IssuerId[]; + acceptedStandardHashes: FieldString[]; +} -// TODO assume additional information that are required to build -// the proof for example to create these: - - // const issuerPubkeyWitness: VCredMerkleWitness = undefined as unknown as VCredMerkleWitness - // const standardIdWitness: VCredMerkleWitness= undefined as unknown as VCredMerkleWitness +export type MembershipProofHelper = { + merkleTreeRoot: Field; + merkleWitness: VCredMerkleWitness; + merkledValue: Field; +}; export class VCredProofHelper { public readonly claims: ClaimMap; public readonly vcred: VCredStruct; + private readonly membershipHelpers: { + issuer: MembershipProofHelper; + standard: MembershipProofHelper; + }; + public get vcredHash(): Field { return Poseidon.hash(this.vcred.toFields()); } - private constructor(public readonly credential: Credential) { + public get issuerMembershipHelper(): MembershipProofHelper { + return this.membershipHelpers.issuer; + } + + public get standardMembershipHelper(): MembershipProofHelper { + return this.membershipHelpers.standard; + } + + public get credentialTypeMembershipProof(): Field { + return Poseidon.hash([ + this.issuerMembershipHelper.merkleTreeRoot, + this.standardMembershipHelper.merkleTreeRoot + ]); + } + + public constructor( + public readonly credential: Credential, + public readonly referenceData: IVCredProofReferenceData + ) { this.claims = ClaimMap.fromTransit(credential.claims); this.vcred = VCredStruct.fromTransit(credential); this.initialValidityCheck(); + this.membershipHelpers = this.mkMembershipHelpersMembershipHelper(); } - public static forCredential(t: Credential): VCredProofHelper { - return new VCredProofHelper(t); + + private mkMembershipHelpersMembershipHelper(): { + issuer: MembershipProofHelper; + standard: MembershipProofHelper; + } { + // issuer membership + const value1 = Poseidon.hash(this.vcred.issuer.pubkey.toFields()); + const leaves1 = this.acceptedIssuersPubKeys.map((issuer) => + Poseidon.hash(issuer.toFields()) + ); + + // standard membership + const value2 = this.vcred.credentialStandardHash; + const leaves2 = this.acceptedStandardHashes; + + const ret = []; + for (const d of [ + { v: value1, l: leaves1 }, + { v: value2, l: leaves2 } + ]) { + const leaves = d.l.sort(() => Math.random() - 0.5); + const value = d.v; + const m1 = new VCredMerkleTree(); + m1.fill(leaves); + const index = leaves.findIndex((leaf) => leaf.equals(value)); + const witness = m1.getWitness(BigInt(index)); + // sanity check as it should already be checked by initialValidityCheck + if (index === -1) { + throw new Error( + 'Credential data invalid. Standard or issuer not accepted. Proof not possible' + ); + } + ret.push({ + merkleTreeRoot: m1.getRoot(), + merkleWitness: new VCredMerkleWitness(witness), + merkledValue: value + }); + } + return { issuer: ret[0], standard: ret[1] }; } private initialValidityCheck() { + this.initialCredentialTypeValidityCheck(); // claim merkle root was created in an unexpected way if (!this.claims.getRoot().equals(this.vcred.claimsMerkleMapRoot)) { throw new Error('Claims root does not match the credential claims root'); @@ -188,4 +269,44 @@ export class VCredProofHelper { throw new Error('Credential signature is invalid'); } } + + private initialCredentialTypeValidityCheck() { + log('Checking credential type validity...'); + + log('acceptedIssuersPubKeys'); + log(this.referenceData.acceptedIssuers.map((issuer) => issuer.pubkey)); + log(this.credential.issuer.pubkey); + log('acceptedStandardHashes'); + log(this.referenceData.acceptedStandardHashes); + log(this.credential.credentialStandardHash); + + let hasIssuer = false + this.acceptedIssuersPubKeys.forEach((pk) => { + if (pk.equals(this.vcred.issuer.pubkey)) { + hasIssuer = true + } + }); + if (!hasIssuer) { + throw new Error('Credential issuer not accepted. Proof not possible'); + } + + let hasStandard = false + this.acceptedStandardHashes.forEach((hash) => { + if (hash.equals(this.vcred.credentialStandardHash)) { + hasStandard = true + } + }); + if (!hasStandard) { + throw new Error('Credential standard not accepted. Proof not possible'); + } + } + + private get acceptedIssuersPubKeys(): PublicKey[] { + return this.referenceData.acceptedIssuers.map((issuer) => + PublicKey.fromBase58(issuer.pubkey) + ); + } + private get acceptedStandardHashes(): Field[] { + return this.referenceData.acceptedStandardHashes.map(fieldFromHex); + } } diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/dev.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/dev.ts new file mode 100644 index 0000000..0b5ed24 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/dev.ts @@ -0,0 +1,6 @@ +import {Logger} from 'tslog'; + +export const mklog = (name: string) => { + const l = new Logger({name}); + return (x: unknown) => l.debug(x); +} diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index cf178fd..0e1056a 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -122,7 +122,7 @@ if (!credential) { // for proofs we need credential in o1js struct form log.info('Setting up o1js proof helper for the credential'); -const vcredproofhelper = VCredProofHelper.forCredential(credential); +// const vcredproofhelper = VCredProofHelper.forCredential(credential); log.info('(later) Requesting a resource access schema'); @@ -195,7 +195,7 @@ log.info('Compiling the program #2'); log.info('Compiling the program #3'); // there's an issue with compiling // TypeError: Cannot read properties of undefined (reading 'value') -await FieldSecretMembershipClaimProgram.compile() +// await FieldSecretMembershipClaimProgram.compile() // class ClaimProofPublicInput extends Struct({ From 3906a27b3ae58780acdf6b99fa172a7ed45c51d3 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sat, 27 Apr 2024 18:40:57 +0200 Subject: [PATCH 33/34] Recover credential store tests. Fix other issues with running tests. --- .../src/circuit/vcred-proof.test.ts | 54 ++++++++ .../src/circuit/vcred-proof.ts | 30 ++++- .../src/credential-store.test.ts | 122 +++++++++++++++++- .../src/credential.ts | 9 +- .../src/data/o1js/claims.test.ts | 2 +- .../src/data/o1js/vcred.test.ts | 2 +- .../src/data/o1js/vcred.ts | 12 -- .../src/data/transit/common.ts | 2 + .../src/data/transit/cred.test.ts | 2 +- .../src/test_fixtures/claims.test.ts | 0 .../src/test_fixtures/credentials.test.ts | 0 ...ansit-data.test.ts => transit.testdata.ts} | 41 ++++-- .../tsconfig.json | 2 +- 13 files changed, 238 insertions(+), 40 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.test.ts delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/claims.test.ts delete mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/credentials.test.ts rename minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/{transit-data.test.ts => transit.testdata.ts} (71%) diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.test.ts new file mode 100644 index 0000000..3f1af73 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.test.ts @@ -0,0 +1,54 @@ +import { + sampleCredential1, + subjectPrivateKey1 +} from '../test_fixtures/transit.testdata.js'; +import { VCredProofHelper } from '../data/o1js/vcred.js'; +import { Field, verify } from 'o1js'; +import { DateTime } from 'luxon'; +import { proveCredentialValidity } from './vcred-proof.js'; + +describe('o1js vcred validation proofs tests', () => { + const credential = sampleCredential1; + + it('one can build a valid proof for valid data', async () => { + // define proof requirements + const acceptedIssuers = [credential.issuer]; + const acceptedStandardHashes = [credential.credentialStandardHash]; + + // must be valid for at least 7 days + const validFrom = DateTime.now(); + const validTo = DateTime.now().plus({ days: 7 }); + + // create the proof helper + const helper = new VCredProofHelper(credential, { + acceptedIssuers, + acceptedStandardHashes + }); + + const subjectPrivkey = subjectPrivateKey1; + + const requiredVerkeyHash = new Field("9789868679003618500052110428697216004752363886153985162691995294057385998140") + + // create the proof + const { proof, verificationKey } = await proveCredentialValidity( + requiredVerkeyHash, + validFrom, + validTo, + helper, + subjectPrivkey + ); + + // verify the proof + await expect(verify(proof, verificationKey)).resolves.toBe(true); + + // verify the output + const outputHash = proof.publicOutput.credentialHash; + + expect(outputHash.equals(helper.vcredHash).toBoolean()).toBe(true); + + const outputSubjectPubkey = proof.publicOutput.subjectPubkey; + expect( + outputSubjectPubkey.equals(subjectPrivkey.toPublicKey()).toBoolean() + ).toBe(true); + }, 1000000); +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts index a7c3e04..4139917 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/vcred-proof.ts @@ -12,6 +12,7 @@ import { Provable, PublicKey, Struct, + VerificationKey, ZkProgram } from 'o1js'; import { UnixTimestamp } from '../data/o1js/common.js'; @@ -20,6 +21,9 @@ import { VCredProofHelper, VCredStruct } from '../data/o1js/vcred.js'; +import { Logger } from 'tslog'; + +const log = new Logger({name: 'vcred-proof.ts'}); /** * The public input to the proof of a credential's validity. @@ -111,7 +115,7 @@ export const ValidateVCredProgram = ZkProgram({ subjectPubkey.assertEquals(privateInput.subjectPrivkey.toPublicKey()); - const credentialHash = Poseidon.hash(cred.dataToFields()); + const credentialHash = Poseidon.hash(cred.toFields()); const ret = new VCredProofPublicOutput({ credentialHash, @@ -125,6 +129,15 @@ export const ValidateVCredProgram = ZkProgram({ export class ValidateVCredProof extends ZkProgram.Proof(ValidateVCredProgram) {} +export type VCredValidation = { + proof: ValidateVCredProof; + verificationKey: { + data: string; + hash: Field; + }; + verificationKeyValid: boolean; +}; + /** * Proves the validity of a credential. Details of how the will be constructed can be altered by the parameters. * @@ -137,12 +150,13 @@ export class ValidateVCredProof extends ZkProgram.Proof(ValidateVCredProgram) {} * @returns The proof of the credential's validity. */ export const proveCredentialValidity = async ( + verificationKeyHash: Field | undefined, validFrom: DateTime, validTo: DateTime, credProofHelper: VCredProofHelper, subjectPrivkey?: PrivateKey, - compileProver = true -): Promise => { +): Promise => { + log.info('Proving credential validity'); // create public input const publicInput = new VCredProofPublicInput({ validFrom: new UnixTimestamp({ @@ -164,11 +178,13 @@ export const proveCredentialValidity = async ( standardIdWitness: credProofHelper.standardMembershipHelper.merkleWitness }); - if (compileProver) { - await ValidateVCredProgram.compile(); - } + log.info('Compiling the prover program circuits'); + const {verificationKey} = await ValidateVCredProgram.compile(); + + const verificationKeyValid = verificationKeyHash ? verificationKey.hash.equals(verificationKeyHash).toBoolean() : true; + log.info('Proving the credential validity.'); const proof = await ValidateVCredProgram.validate(publicInput, privateInput); - return proof + return { proof, verificationKey, verificationKeyValid }; }; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts index a5f393d..1db842f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential-store.test.ts @@ -1,4 +1,5 @@ import { Field, PrivateKey, Signature } from "o1js"; +import { CredentialStore, IStorage } from "./credential-store.js"; import { CredSubjectIdSchema, Credential, CredentialData, CredentialStandard, IssuerIdSchema, PubKeyId, PubKeyIdSchema, VCredIdSchema } from "./data/transit/cred.js"; import * as DateOfBirth from './zkclaims/date-of-birth.js'; import * as Citizenship from './zkclaims/citizenship.js'; @@ -6,13 +7,38 @@ import { DateTime } from "luxon"; import { DateTimeSchema, FieldSchema } from "./data/transit/common.js"; import { credentialStandardHash, verifyAndIssueCredential } from "./credential.js"; import { ILogObj, Logger } from 'tslog'; +import { claimStandardHash } from "./claim.js"; -export const log = new Logger({ +const log = new Logger({ name: 'credential-store-test.ts' }); +class MockStorage implements IStorage { + private store: Record = {}; -export const prepareTestDataCredential = (): {credential: Credential} => { + async getItem(key: string): Promise { + const r = this.store[key] || null; + log.debug(`getItem(${key}) = ${r}`); + return r; + } + + async setItem(key: string, value: string): Promise { + log.debug(`setItem(${key}, ${value})`); + this.store[key] = value; + } + + async removeItem(key: string): Promise { + log.debug(`removeItem(${key})`); + delete this.store[key]; + } + + async clear(): Promise { + log.debug(`clear()`); + this.store = {}; + } +} + +const prepareTestDataCredential = (): {credential: Credential} => { const KnownUserCredential: CredentialStandard = { standardId: "eth.example.KnownUserCredential-v1.0", @@ -31,7 +57,7 @@ export const prepareTestDataCredential = (): {credential: Credential} => { } const { sign: signIssuer, pubkeyId: issuerId } = createEntity(); - const { sign: _, pubkeyId: subjectId } = createEntity(); + const { sign: signSubject, pubkeyId: subjectId } = createEntity(); // throw new Error('Not implemented'); @@ -62,4 +88,94 @@ export const prepareTestDataCredential = (): {credential: Credential} => { }; +describe('CredentialStore Tests', () => { + let storage: MockStorage; + let credentialStore: CredentialStore; + let credential: Credential; + + beforeAll(() => { + credential = prepareTestDataCredential().credential; + }); + + beforeEach(() => { + storage = new MockStorage(); + credentialStore = new CredentialStore('testCredentials', storage); + }); + + it('successfully adds a valid credential', async () => { + await credentialStore.addCredential(credential); + + // Verify the credential was stored + const storedCredentialJson = await storage.getItem('testCredentials'); + expect(storedCredentialJson).not.toBeNull(); + + const storedCredentials = JSON.parse(storedCredentialJson || '{}'); + expect(storedCredentials[credential.id]).toEqual(credential); + }); + it('retrieves an existing credential by ID', async () => { + // Manually add the credential to the mock storage to simulate existing data + await storage.setItem('testCredentials', JSON.stringify({ [credential.id]: credential })); + + const retrieved = await credentialStore.getCredential(credential.id); + expect(retrieved).toEqual(credential); + }); + + it('successfully removes an existing credential by ID', async () => { + await credentialStore.addCredential(credential); // Assume `credential` is already defined + await credentialStore.removeCredential(credential.id); + + const storedCredential = await credentialStore.getCredential(credential.id); + expect(storedCredential).toBeNull(); + }); + + it('performs gracefully when trying to remove a non-existing credential ID', async () => { + expect(async () => { + await credentialStore.removeCredential('nonExistingId'); + }).not.toThrow(); + }); + + it('returns all credentials for a given issuer', async () => { + log.debug('== test: it returns all credentials for a given issuer'); + await credentialStore.addCredential(credential); // Assume `credential` is correctly defined + + const credentials = await credentialStore.findCredentialsByIssuer(credential.issuer); + expect(credentials).toEqual(expect.arrayContaining([credential])); + }); + + it('returns an empty array if no credentials match the given issuer', async () => { + const credentials = await credentialStore.findCredentialsByIssuer({pubkey:'nonExistingIssuer'}); + expect(credentials).toEqual([]); + }); + + it('returns credentials that match a given issuer ID and all specified claim standard IDs', async () => { + await credentialStore.addCredential(credential); // Assume `credential` is correctly defined + const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + const matchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards); + expect(matchedCredentials.length).toBe(1); + expect(matchedCredentials[0].id).toEqual(credential.id); + }); + + it('returns credentials that match a given issuer ID and all specified claim standard IDs #2', async () => { + await credentialStore.addCredential(credential); // Assume `credential` is correctly defined + const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + const matchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards.slice(0, 1)); + expect(matchedCredentials.length).toBe(1); + expect(matchedCredentials[0].id).toEqual(credential.id); + }); + + it('handles cases where some credentials do not contain any of the specified claim standards', async () => { + let standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + standards[1] = new Field(999); // Intentionally set to a non-matching standard hash + const unmatchedCredentials = await credentialStore.findCredentialsByClaimStandards(credential.issuer, standards); + expect(unmatchedCredentials.length).toBe(0); + }); + + it('returns an empty array if no credentials match the criteria', async () => { + const standards = Object.values(credential.claims).map(claim => claimStandardHash(claim.standard)); + const issuerId = { pubkey: PrivateKey.random().toPublicKey().toBase58() } + const noMatch = await credentialStore.findCredentialsByClaimStandards(issuerId, standards); + expect(noMatch.length).toBe(0); + }); + +}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts index 0c1effa..c596429 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/credential.ts @@ -47,6 +47,13 @@ export const credentialDataHash = (data: CredentialData): Field => { return Poseidon.hash(flds); } +export const mkCredentialSignature = ( + credentialData: CredentialData, + sign: (flds: Field[]) => o1js.Signature +): o1js.Signature => { + return sign([credentialDataHash(credentialData)]); +} + export const verifyAndIssueCredential = ( @@ -62,7 +69,7 @@ export const verifyAndIssueCredential = log.debug('Converting the credential data to o1js fields.'); log.debug('Creating signature for the fields data'); - const signature = sign([credentialDataHash(credentialData)]) + const signature = mkCredentialSignature(credentialData, sign); // create the credential diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts index ee83db9..2d18fed 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/claims.test.ts @@ -1,4 +1,4 @@ -import { dateOfBirthClaim, sampleCredential1 } from '../..//test_fixtures/transit-data.test.js'; +import { dateOfBirthClaim, sampleCredential1 } from '../..//test_fixtures/transit.testdata.js'; import { Claim } from '../transit/cred.js'; import { ClaimData, ClaimMap, mkClaimId, mkClaimMerkleValue } from './claim.js'; // Import the functions to test import { MerkleMap } from 'o1js'; // Ensure all dependencies are imported diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts index 50290e3..655eda6 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.test.ts @@ -1,4 +1,4 @@ -import { sampleCredential1 } from '../..//test_fixtures/transit-data.test.js'; +import { sampleCredential1 } from '../..//test_fixtures/transit.testdata.js'; import { CredentialData } from '../transit/cred.js'; import { IssuerId } from './ids.js'; import * as T from '../transit/cred.js'; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts index 404b00e..4a50527 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/vcred.ts @@ -13,9 +13,6 @@ import { CredSubjectId, IssuerId, VCredId } from './ids.js'; import * as T from '../transit/cred.js'; import { Credential, CredentialData } from '../transit/cred.js'; import { FieldString, fieldFromHex } from '../transit/common.js'; -import { mklog } from '../../dev.js' - -const log = mklog('vcred.ts'); /** One can test membership of credential standard and issuer by membership tests in a merkle tree. @@ -271,15 +268,6 @@ export class VCredProofHelper { } private initialCredentialTypeValidityCheck() { - log('Checking credential type validity...'); - - log('acceptedIssuersPubKeys'); - log(this.referenceData.acceptedIssuers.map((issuer) => issuer.pubkey)); - log(this.credential.issuer.pubkey); - log('acceptedStandardHashes'); - log(this.referenceData.acceptedStandardHashes); - log(this.credential.credentialStandardHash); - let hasIssuer = false this.acceptedIssuersPubKeys.forEach((pk) => { if (pk.equals(this.vcred.issuer.pubkey)) { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts index 2cd532a..0899ea8 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/common.ts @@ -31,6 +31,8 @@ export type FieldsString = z.infer; export const fieldFromHex = (x: FieldString) => new Field(BigInt(x)); export const fieldsFromHex = (x: FieldsString) => x.map(fieldFromHex); +export const fieldToHex = (x: Field) : FieldString => hexViaFieldBigInt(x.toBigInt()); + // ========= Base58 string schemas ========= export const Base58Schema = z.string().regex(/^[A-HJ-NP-Za-km-z1-9]+$/); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts index a3708bc..5e028c9 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/transit/cred.test.ts @@ -1,5 +1,5 @@ // import { Field } from 'o1js'; -import { citizenshipClaim, credentialStandard1, dateOfBirthClaim } from 'src/test_fixtures/transit-data.test.js'; +import { citizenshipClaim, credentialStandard1, dateOfBirthClaim } from '../../test_fixtures/transit.testdata.js'; import { Claim, CredentialDataSchema, CredentialSchema, CredentialStandard, CredentialStandardSchema } from './cred.js'; describe('Credential creation and validation tests', () => { diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/claims.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/claims.test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/credentials.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/credentials.test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit-data.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit.testdata.ts similarity index 71% rename from minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit-data.test.ts rename to minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit.testdata.ts index a4736cd..97409c0 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit-data.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/test_fixtures/transit.testdata.ts @@ -1,4 +1,18 @@ -import { Claim, Credential, CredentialData, CredentialStandard } from '../data/transit/cred.js'; +import { PrivateKey, Signature } from 'o1js'; +import { + Claim, + Credential, + CredentialData, + CredentialStandard +} from '../data/transit/cred.js'; +import { + credentialStandardHash, + mkCredentialSignature +} from '../credential.js'; +import { fieldToHex } from '../data/transit/common.js'; + +export const issuerPrivateKey1 = PrivateKey.random(); +export const subjectPrivateKey1 = PrivateKey.random(); export const credentialStandard1: CredentialStandard = { standardId: 'eth.example.KnownUserCredential-v1.0', @@ -50,27 +64,28 @@ export const citizenshipClaim: Claim = { standard: credentialStandard1.schema.citizenship }; - -export const credentialData1: CredentialData = -{ +export const credentialData1: CredentialData = { claims: { dateOfBirth: dateOfBirthClaim, citizenship: citizenshipClaim }, id: '0x1234567890', - issuer: { - pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' + issuer: { + pubkey: issuerPrivateKey1.toPublicKey().toBase58() }, issuanceDate: '2023-01-01T00:00:00Z', expirationDate: '2028-01-01T00:00:00Z', - subject: { - pubkey: 'B62qnH2ZHFKinYSMEHCcmu7Z7ijeqRTa6KRHF5KUCXnfDvPkysg5TSL' + subject: { + pubkey: subjectPrivateKey1.toPublicKey().toBase58() }, - credentialStandardHash: - '0x25F1E2728547794B6147CBEC641301AEFC2F5ACE1EE5F9C98B52A110460EF661' -} + credentialStandardHash: fieldToHex( + credentialStandardHash(credentialStandard1) + ) +}; export const sampleCredential1: Credential = { ...credentialData1, - signature: '7mX64qh7mUUn5jnWUAAg1o39xwic6vvCq9uwuVSDqTJ7bLD69qtRzn3BzzLu95exgJWxTUUTexdsVv5MFu46RoxrPxF1ZpXE' -} + signature: mkCredentialSignature(credentialData1, (flds) => + Signature.create(issuerPrivateKey1, flds) + ).toBase58() +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json b/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json index 412dfc0..83a508f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/tsconfig.json @@ -24,5 +24,5 @@ "ts-node": { "require": ["tsconfig-paths/register"] }, - "exclude": ["node_modules", "**/*.spec.ts", "src/**/*dev.ts"] + "exclude": ["node_modules", "**/*.spec.ts","**/*.testdata.ts", "src/**/*dev.ts"] } From 0dfe1e47160a61f56909b816886dcad1a9a75ef8 Mon Sep 17 00:00:00 2001 From: adamczykm Date: Sun, 28 Apr 2024 19:59:36 +0200 Subject: [PATCH 34/34] Tests for generic claim proving, other tests improvement, minor fixes --- .../README.md | 10 +- .../src/circuit/generic-claim-proving.test.ts | 107 +++++++++------- .../src/circuit/generic-claim-proving.ts | 121 ++++++++---------- .../src/data/o1js/fieldx.ts | 41 ++++++ .../src/index.ts | 2 +- .../src/zkclaims/citizenship.ts | 22 +++- 6 files changed, 176 insertions(+), 127 deletions(-) create mode 100644 minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/fieldx.ts diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md index 6596759..2cb4310 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/README.md +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/README.md @@ -1,15 +1,9 @@ -# TODO - -- more spec on the structure of claims, verifiable credentials, transformation into verifiable presentations. -- then credentials specs and the registry -- maybe add some diagrams - - - # MinAuth Verified ZK-Document Plugin 🚧 **DISCLAIMER**: The plugin & the documentation under development. +The current TODO list can be found `./todo.org` + This package contains an implementation of a MinAuth plugin. It uses MINA's o1js library for its zero-knowledge proof part. diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts index 06ac699..a02b79b 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.test.ts @@ -1,23 +1,43 @@ -import { Bool, Field, Poseidon } from 'o1js'; +import { Field, MerkleTree, MerkleWitness, Poseidon } from 'o1js'; import { MkValidateClaimsProgram } from './generic-claim-proving.js'; +import { sampleCredential1 } from '../test_fixtures/transit.testdata.js'; +import { VCredProofHelper, VCredStruct } from '../data/o1js/vcred.js'; +import { mkClaimId } from '../data/o1js/claim.js'; +import { DateTime } from 'luxon'; describe('MkValidateClaimsProgram tests + compilation', () => { + const credential = sampleCredential1; + const vcred = VCredStruct.fromTransit(credential); + class Witness10 extends MerkleWitness(10) {} + const MTree10 = new MerkleTree(10); + + let proof1 + const { ValidateClaimsProgram: Prog1, ClaimProofPublicInput, ClaimProofSecretInput - } = MkValidateClaimsProgram(Field, Field, Field)({ - proveClaimIsMember: ({ + } = MkValidateClaimsProgram(Field, Field, Witness10)({ + + // prove that claim data is + // by comparing hashes + proveClaimField1IsGreaterThan: ({ claimData, referenceData, - secretData + }) => { + return { checkValid: claimData.greaterThan(referenceData) }; + }, + + proveClaimIsMember: ({ + claimData, + referenceData: root, + secretData: merkleWitness }) => { - const output = Poseidon.hash([claimData.add(secretData)]); - const checkValid: Bool = output.equals(referenceData); - return { checkValid } + return { checkValid: merkleWitness.calculateRoot(Poseidon.hash([claimData])).equals(root)}; } }); + it('test program compiles', async () => { await expect(Prog1.compile()).resolves.toBeDefined() }); @@ -28,46 +48,41 @@ describe('MkValidateClaimsProgram tests + compilation', () => { await Prog1.compile(); }) - it('test program creates a proof without problems', async () => { - - // class ClaimProofPublicInput extends Struct({ - // credentialHash: Field, - // claimId: Field, - // customInput: ReferenceData - // }) { - // public toFields(): Field[] { - // return [ - // this.credentialHash, - // this.claimId, - // ...this.customInput.toFields() - // ]; - // } - // } - - // class ClaimProofSecretInput extends Struct({ - // credential: VCredDataStruct, - // claimWitness: MerkleMapWitness, - // claimData: ClaimData, - // customSecret: SecretData - // }) {} - - // class ClaimProofOutput extends Struct({ - // proofExecutionTraceHash: Field - // }) {} - - - // const claimData = new ClaimProofPublicInput( - // Field(1), - // Field(1), - // Field(1) - // ); + it('create proof of int being higher than a reference', async () => { + + const claimName = 'dateOfBirth' + + const helper = new VCredProofHelper(credential, { + acceptedIssuers: [credential.issuer], + acceptedStandardHashes: [credential.credentialStandardHash] + }); + + const claimData = helper.claims.claims[claimName].claim.fieldsValue + const referenceData = new Field(DateTime.now().minus({ years: 18 }).toUTC().toUnixInteger()) + + const publicInput = new ClaimProofPublicInput({ + credentialHash: Poseidon.hash(vcred.toFields()), + claimId: mkClaimId(credential.claims[claimName]), + referenceData + }) + + const secretInput = new ClaimProofSecretInput({ + credential: vcred, + claimWitness: helper.claims.getWitness(claimName), + claimData, + customSecret: new Field(0) // not used + }) + + console.log('here') + const proof = await Prog1.proveClaimField1IsGreaterThan( + publicInput, + secretInput + ); + + expect(proof).toBeDefined(); + + proof1 = proof }); - // ); - // const referenceData = Field(1); - // const secretData = Field(1); - // const proof = await Prog1.proveClaimIsMember({ claimData, referenceData, secretData }); - // expect(proof).toBeDefined(); - // }); }); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts index e51f8c1..e0f1fa9 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/circuit/generic-claim-proving.ts @@ -11,10 +11,11 @@ import { ZkProgram } from 'o1js'; import { VCredDataStruct } from '../data/o1js/vcred.js'; +import { mkClaimMerkleValueProvable } from '../data/o1js/claim.js'; /** This is a more nuanced version of the claim validation program. - It is generic and meant to make claim verification very convenient. + It is generic and meant to make claim verification more convenient. One can provide a set of functions that will deal with verification of claim data. @@ -31,7 +32,12 @@ import { VCredDataStruct } from '../data/o1js/vcred.js'; later on, the exact chain of method calls can be verified given the final proof. - For example: + Note that the current limitation is that the shape of the claim data + and private data is fixed. + + If you have an idea how to make it more flexible, please let me know. + + An example usage of this program is as follows: class ReferenceData extends Struct({ fieldData: Field, @@ -71,26 +77,25 @@ import { VCredDataStruct } from '../data/o1js/vcred.js'; ... ); - - - This will prove that: - The claim data belongs to the merklemap + The claim data value belongs to the merklemap with the given root. GIVEN: - - a credentialhash (that corresponds to a valid credential, and already acccepted credential) + - a credentialhash (that corresponds to a valid and already acccepted credential ) - a claim id (todo) - - a merkle map root hash - + - a come custom public input + Additionally proofs can be merged using the mergeProofs method. + DEV NOTE: how to achieve it in a less hardcoded way? + i.e. can proofs created by other zkprograms also be verified? */ // TODO: update checks, they are not useful as of this // form in the generic approach export const MkValidateClaimsProgram = ( - ClaimData: FlexibleProvablePure, + ClaimData: FlexibleProvablePure, // we need it to change from method to method ReferenceData: FlexibleProvablePure, - SecretData: FlexibleProvablePure + SecretData: FlexibleProvablePure // we need it to change from method to method ) => { class ClaimCheckInput extends Struct({ claimData: ClaimData, @@ -111,13 +116,13 @@ export const MkValidateClaimsProgram = ( class ClaimProofPublicInput extends Struct({ credentialHash: Field, claimId: Field, - customInput: ReferenceData + referenceData: ReferenceData }) { public toFields(): Field[] { return [ this.credentialHash, this.claimId, - ...this.customInput.toFields() + ...this.referenceData.toFields() ]; } } @@ -139,42 +144,44 @@ export const MkValidateClaimsProgram = ( methodId: Field, currentMethodClaimCheck: (input: ClaimCheckInput) => ClaimCheckOutput ): Field => { - // verify credential hash - publicInput.credentialHash.assertEquals( - Poseidon.hash(privateInput.credential.toFields()) - ); - - // verify claim data - // claim data along with its id should match the witness - const claimMerkleValue = Poseidon.hash([ - publicInput.claimId, - ...privateInput.claimData.toFields() - ]); - const [root, _] = - privateInput.claimWitness.computeRootAndKey(claimMerkleValue); - privateInput.credential.claimsMerkleMapRoot.assertEquals(root); - - // at this point we know that the claim data in fact comes - // from a credential of the given hash - - // now comes the actual verification of the claim data - // for this methodId, which is an equality check - - const claimInput: ClaimCheckInput = { - claimData: privateInput.claimData, - referenceData: publicInput.customInput, - secretData: privateInput.customSecret - }; + // // verify credential hash + // publicInput.credentialHash.assertEquals( + // Poseidon.hash(privateInput.credential.toFields()) + // ); - const { checkValid } = currentMethodClaimCheck(claimInput); + // // verify claim data + // // claim data along with its id should match the witness + // const claimMerkleValue = mkClaimMerkleValueProvable( + // publicInput.claimId, + // privateInput.claimData.toFields() + // ); - checkValid.assertTrue('Claim data check failed'); + // const [root, _] = + // privateInput.claimWitness.computeRootAndKey(claimMerkleValue); + // privateInput.credential.claimsMerkleMapRoot.assertEquals(root); - // hash that will allow to verify the exact method call - const methodCallHash = Poseidon.hash([ - methodId, - ...publicInput.toFields() - ]); + // // at this point we know that the claim data in fact comes + // // from a credential of the given hash + + // // now comes the actual verification of the claim data + // // for this methodId, which is an equality check + + // const claimInput: ClaimCheckInput = { + // claimData: privateInput.claimData, + // referenceData: publicInput.referenceData, + // secretData: privateInput.customSecret + // }; + + // const { checkValid } = currentMethodClaimCheck(claimInput); + + // checkValid.assertTrue('Claim data check failed'); + + // // hash that will allow to verify the exact method call + // const methodCallHash = Poseidon.hash([ + // methodId, + // ...publicInput.toFields() + // ]); + const methodCallHash = new Field(0); return methodCallHash; }; @@ -246,25 +253,3 @@ export const MkValidateClaimsProgram = ( }; }; }; - -// temp test: example usage -export const { - ValidateClaimsProgram: FieldSecretMembershipClaimProgram, - ClaimProofPublicInput, - ClaimProofSecretInput -} = MkValidateClaimsProgram( - Field, // secret: ClaimData is just a field - Field, // Reference (public data): MerkleMap root - MerkleMapWitness // custom secret -)({ - proveClaimIsMember: ({ - claimData, - referenceData: merkleRoot, - secretData: merkleWitness - }) => { - const [root] = merkleWitness.computeRootAndKey(claimData); - const checkValid: Bool = merkleRoot.equals(root); - - return { checkValid } - } -}); diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/fieldx.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/fieldx.ts new file mode 100644 index 0000000..6b7fd00 --- /dev/null +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/data/o1js/fieldx.ts @@ -0,0 +1,41 @@ +import { Field, Struct } from 'o1js'; + +/** Class that can be used to represent values fitting in 3 Fields + */ +export class Field3 extends Struct({ + f0: Field, + f1: Field, + f2: Field +}) { + public toFields(): Field[] { + return [this.f0, this.f1, this.f2]; + } +} + +export const mkField3 = ( + f0: string | number | bigint, + f1: string | number | bigint, + f2: string | number | bigint +): Field3 => { + return new Field3({ + f0: new Field(f0), + f1: new Field(f1), + f2: new Field(f2) + }); +}; + +export const field3FromFields = (flds: Field[]) => { + const l = flds.length; + let fs = flds; + if (l === 0 || l > 3) { + throw new Error('Field3 must have at least one field and no more than 3'); + } + if (l === 1) { + fs = [...flds, new Field(0), new Field(0)]; + } else if (l === 2) { + fs = [...flds, new Field(0)]; + } else if (l === 3) { + fs = flds; + } + return new Field3({ f0: fs[0], f1: fs[1], f2: fs[2] }); +}; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts index 0e1056a..54042c1 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/index.ts @@ -9,7 +9,7 @@ import { CredSubjectId, CredSubjectIdSchema, Credential, CredentialData, Credent import { credentialStandardHash, verifyAndIssueCredential } from './credential.js'; import { CredentialStore, MockStorage } from './credential-store.js'; import { VCredProofHelper } from './data/o1js/vcred.js'; -import { FieldSecretMembershipClaimProgram } from './circuit/generic-claim-proving.js'; +// import { FieldSecretMembershipClaimProgram } from './circuit/generic-claim-proving.js'; import { Validate1FieldClaimProgram } from './circuit/claim-field1-proving.js'; import { Validate2FieldClaimProgram } from './circuit/claim-field2-proving.js'; diff --git a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts index 9b6b67f..e80040f 100644 --- a/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts +++ b/minauth-plugins/minauth-verified-zkdocument-plugin/src/zkclaims/citizenship.ts @@ -1,5 +1,5 @@ -import { CircuitString } from 'o1js'; -import { FieldSchema } from '../data/transit/common.js'; +import { CircuitString, Poseidon } from 'o1js'; +import { FieldSchema, fieldsFromHex } from '../data/transit/common.js'; import { Claim } from '../data/transit/cred.js'; const CODE_LENGTH = 3; @@ -13,8 +13,8 @@ export const standard = { fieldsConversion: { length: CODE_LENGTH, description: - 'Each of 3 letter is represented as a field using o1js.CircuitString.fromString', - codeExample: `o1js.CircuitString.fromString(cred.citizenship).toFields().slice(0, ${CODE_LENGTH})` + 'Each of 3 letter is represented as a field using o1js.CircuitString.fromString. Then the Poseidon hash is taken.', + codeExample: `o1js.Poseidon.hash(o1js.CircuitString.fromString(cred.citizenship).toFields().slice(0, ${CODE_LENGTH}))` } }; @@ -298,3 +298,17 @@ const mkNameToCodeMap = () => { }; const nameToCode = mkNameToCodeMap(); + +const hash_collision_test = () => { + const codes = Object.keys(CODES); + for (let i = 0; i< codes.length; i++) { + for (let j = i+1; j< codes.length; j++) { + const claimflds = fieldsFromHex(mkCitizenshipClaim(codes[i]).fieldsValue); + const claim2flds = fieldsFromHex(mkCitizenshipClaim(codes[j]).fieldsValue); + if(Poseidon.hash(claimflds).equals(Poseidon.hash(claim2flds))) { + throw new Error(`Hash collision for ${codes[i]} and ${codes[j]}`); + } + } + } +} +hash_collision_test();