From bd88b58d44a87f89f71291a42a2140b216f5a96a Mon Sep 17 00:00:00 2001 From: skaunov Date: Wed, 3 Jul 2024 05:28:45 +0300 Subject: [PATCH 1/6] Smoke test passes --- javascript/.appveyor.yml | 11 + javascript/.github/dependabot.yml | 8 + javascript/.gitignore | 15 +- javascript/.npmignore | 14 - javascript/.travis.yml | 69 + javascript/Cargo.toml | 47 + javascript/README.MD | 48 - javascript/README.md | 84 + javascript/jest.config.js | 5 - javascript/package.json | 44 - javascript/pnpm-lock.yaml | 2695 --------------------------- javascript/src/index.ts | 1 - javascript/src/lib.rs | 292 +++ javascript/src/signals.ts | 133 -- javascript/src/utils.rs | 10 + javascript/src/utils/curve.ts | 20 - javascript/src/utils/encoding.ts | 59 - javascript/src/utils/hashToCurve.ts | 53 - javascript/test/consts.ts | 42 - javascript/test/encoding.test.ts | 43 - javascript/test/hashToCurve.test.ts | 21 - javascript/test/signals.test.ts | 166 -- javascript/tsconfig.build.json | 5 - javascript/tsconfig.json | 21 - 24 files changed, 527 insertions(+), 3379 deletions(-) create mode 100644 javascript/.appveyor.yml create mode 100644 javascript/.github/dependabot.yml delete mode 100644 javascript/.npmignore create mode 100644 javascript/.travis.yml create mode 100644 javascript/Cargo.toml delete mode 100644 javascript/README.MD create mode 100644 javascript/README.md delete mode 100644 javascript/jest.config.js delete mode 100644 javascript/package.json delete mode 100644 javascript/pnpm-lock.yaml delete mode 100644 javascript/src/index.ts create mode 100644 javascript/src/lib.rs delete mode 100644 javascript/src/signals.ts create mode 100644 javascript/src/utils.rs delete mode 100644 javascript/src/utils/curve.ts delete mode 100644 javascript/src/utils/encoding.ts delete mode 100644 javascript/src/utils/hashToCurve.ts delete mode 100644 javascript/test/consts.ts delete mode 100644 javascript/test/encoding.test.ts delete mode 100644 javascript/test/hashToCurve.test.ts delete mode 100644 javascript/test/signals.test.ts delete mode 100644 javascript/tsconfig.build.json delete mode 100644 javascript/tsconfig.json diff --git a/javascript/.appveyor.yml b/javascript/.appveyor.yml new file mode 100644 index 0000000..50910bd --- /dev/null +++ b/javascript/.appveyor.yml @@ -0,0 +1,11 @@ +install: + - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --locked diff --git a/javascript/.github/dependabot.yml b/javascript/.github/dependabot.yml new file mode 100644 index 0000000..7377d37 --- /dev/null +++ b/javascript/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + time: "08:00" + open-pull-requests-limit: 10 diff --git a/javascript/.gitignore b/javascript/.gitignore index a7c8136..4e30131 100644 --- a/javascript/.gitignore +++ b/javascript/.gitignore @@ -1,9 +1,6 @@ -# Swap the comments on the following lines if you don't wish to use zero-installs -# Documentation here: https://yarnpkg.com/features/zero-installs -# !.yarn/cache -.pnp.* - -# node.js -/node_modules -/dist - +/target +**/*.rs.bk +Cargo.lock +bin/ +pkg/ +wasm-pack.log diff --git a/javascript/.npmignore b/javascript/.npmignore deleted file mode 100644 index 5a11e6d..0000000 --- a/javascript/.npmignore +++ /dev/null @@ -1,14 +0,0 @@ -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions - -# Swap the comments on the following lines if you don't wish to use zero-installs -# Documentation here: https://yarnpkg.com/features/zero-installs -# !.yarn/cache -.pnp.* - -# node.js -/node_modules diff --git a/javascript/.travis.yml b/javascript/.travis.yml new file mode 100644 index 0000000..7a91325 --- /dev/null +++ b/javascript/.travis.yml @@ -0,0 +1,69 @@ +language: rust +sudo: false + +cache: cargo + +matrix: + include: + + # Builds with wasm-pack. + - rust: beta + env: RUST_BACKTRACE=1 + addons: + firefox: latest + chrome: stable + before_script: + - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) + - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) + - cargo install-update -a + - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f + script: + - cargo generate --git . --name testing + # Having a broken Cargo.toml (in that it has curlies in fields) anywhere + # in any of our parent dirs is problematic. + - mv Cargo.toml Cargo.toml.tmpl + - cd testing + - wasm-pack build + - wasm-pack test --chrome --firefox --headless + + # Builds on nightly. + - rust: nightly + env: RUST_BACKTRACE=1 + before_script: + - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) + - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) + - cargo install-update -a + - rustup target add wasm32-unknown-unknown + script: + - cargo generate --git . --name testing + - mv Cargo.toml Cargo.toml.tmpl + - cd testing + - cargo check + - cargo check --target wasm32-unknown-unknown + - cargo check --no-default-features + - cargo check --target wasm32-unknown-unknown --no-default-features + - cargo check --no-default-features --features console_error_panic_hook + - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook + - cargo check --no-default-features --features "console_error_panic_hook wee_alloc" + - cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc" + + # Builds on beta. + - rust: beta + env: RUST_BACKTRACE=1 + before_script: + - (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update) + - (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate) + - cargo install-update -a + - rustup target add wasm32-unknown-unknown + script: + - cargo generate --git . --name testing + - mv Cargo.toml Cargo.toml.tmpl + - cd testing + - cargo check + - cargo check --target wasm32-unknown-unknown + - cargo check --no-default-features + - cargo check --target wasm32-unknown-unknown --no-default-features + - cargo check --no-default-features --features console_error_panic_hook + - cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook + # Note: no enabling the `wee_alloc` feature here because it requires + # nightly for now. diff --git a/javascript/Cargo.toml b/javascript/Cargo.toml new file mode 100644 index 0000000..0de3ce6 --- /dev/null +++ b/javascript/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "plume-sig" +version = "3.0.0-rc.0" +authors = ["skaunov"] +edition = "2018" +keywords = ["nullifier", "zero-knowledge", "ECDSA", "PLUME"] +repository = "https://github.com/plume-sig/zk-nullifier-sig/" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +[dependencies] +wasm-bindgen = "~0.2.84" + +# The `console_error_panic_hook` crate provides better debugging of panics by +# logging them with `console.error`. This is great for development, but requires +# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for +# code size when deploying. +console_error_panic_hook = { version = "0.1.7", optional = true } + +js-sys = "0.3" + +plume_rustcrypto = "0.2" # TODO change to +rand_chacha = "0.3" +sec1 = "0.7.3" # match with `k256` +elliptic-curve = {version = "0.13.8", features = ["sec1"]} # match with `k256` +hex = "0.4" +k256 = "~0.13.3" # match with `k256` +zeroize = "1.8" +signature = "^2.2.0" +getrandom = { version = "0.2", features = ["js"] } +# getrandom_or_panic = "0.0.3" +rand = {version = "0.8"} +anyhow = "1" + +web-sys = { version = "0.3", features = ["CryptoKey", "SubtleCrypto", "Crypto", "EcKeyImportParams"] } +wasm-bindgen-futures = "0.4" + +[dev-dependencies] +wasm-bindgen-test = "~0.3.34" + +[profile.release] +# Tell `rustc` to optimize for small code size. +# opt-level = "s" diff --git a/javascript/README.MD b/javascript/README.MD deleted file mode 100644 index be240e5..0000000 --- a/javascript/README.MD +++ /dev/null @@ -1,48 +0,0 @@ -`plume-sig` -============== -TypeScript implementation of the ERC-7524 PLUME signature scheme. - -A new type of cryptographic signature that would allow for anonymous and unique digital identities on the Ethereum blockchain in a verifiable way. - -## Installation -`npm install plume-sig` - -## Usage - -```ts -import { computeAllInputs, PlumeVersion } from 'plume-sig'; - -return computeAllInputs(message, secretKey); -``` - -The function returns the signature w.r.t. to given arguments as the object of the following structure. -### `plume` -`secp256k1` point -### `s` -`secp256k1` scalar hexstring -### `pk` -Public key of the signer; SEC1 encoded. -### `c` -SHA-256 hash. It's value depends on `PlumeVersion` of the signature. -### `rPoint` -`secp256k1` point representing the unique random scalar used for signing. V1 specific. -### `hashedToCurveR` -`secp256k1` point. V1 specific. - -## Signature variants -The scheme comes in two variants. V2 is default for this implementation. - -### Version 1: Verifier Optimized - -In a situation where there is a verifier who must *not* know the signer's `pk`, but the signer must nevertheless prove that they know `secretKey` corresponding to the signature given `message`, a zero-knowledge proof is required. - -The following verification function may be described via a circuit as part of a non-interactive zero-knowledge proving system, such as Groth16. To create a proof, the prover supplies the following inputs: - -### Version 2: Prover Optimized - -Currently, SHA-256 hashing operations are particularly expensive with zk proofs in the browser. In the context of PLUME, the computation of $c$ is a bottleneck for efficient proof times, so one modification suggested by the Poseidon team was to move this hash computation outside the circuit, into the verifier. - -Due to SHA-256 being a native precompile on Ethereum, this operation will still be efficient for smart contract verifiers. - -## License -MIT \ No newline at end of file diff --git a/javascript/README.md b/javascript/README.md new file mode 100644 index 0000000..6b68408 --- /dev/null +++ b/javascript/README.md @@ -0,0 +1,84 @@ +
+ +

wasm-pack-template

+ + A template for kick starting a Rust and WebAssembly project using wasm-pack. + +

+ Build Status +

+ +

+ Tutorial + | + Chat +

+ + Built with 🦀🕸 by The Rust and WebAssembly Working Group +
+ +## About + +[**📚 Read this template tutorial! 📚**][template-docs] + +This template is designed for compiling Rust libraries into WebAssembly and +publishing the resulting package to NPM. + +Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other +templates and usages of `wasm-pack`. + +[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html +[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html + +## 🚴 Usage + +### 🐑 Use `cargo generate` to Clone this Template + +[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate) + +``` +cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project +cd my-project +``` + +### 🛠️ Build with `wasm-pack build` + +``` +wasm-pack build +``` + +### 🔬 Test in Headless Browsers with `wasm-pack test` + +``` +wasm-pack test --headless --firefox +``` + +### 🎁 Publish to NPM with `wasm-pack publish` + +``` +wasm-pack publish +``` + +## 🔋 Batteries Included + +* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating + between WebAssembly and JavaScript. +* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) + for logging panic messages to the developer console. +* `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/javascript/jest.config.js b/javascript/jest.config.js deleted file mode 100644 index 3abcbd9..0000000 --- a/javascript/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - preset: "ts-jest", - testEnvironment: "node", -}; diff --git a/javascript/package.json b/javascript/package.json deleted file mode 100644 index 7a128ca..0000000 --- a/javascript/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "plume-sig", - "version": "2.0.9", - "keywords": ["nullifier", "zero-knowledge", "ECDSA", "PLUME"], - "repository": "https://github.com/plume-sig/zk-nullifier-sig/", - "pnpm": { - "overrides": { - "@noble/secp256k1": "$@noble/secp256k1" - } - }, - "engines": { - "node": ">=16 <19" - }, - "devDependencies": { - "@types/jest": "^29.5.0", - "@types/js-sha512": "^0", - "@types/node": "^18.11.9", - "@types/nodemon": "^1.19.2", - "jest": "^29.7.0", - "nodemon": "^2.0.20", - "prettier": "^3.0.3", - "ts-jest": "^29.0.3", - "ts-node": "^10.9.1", - "typescript": "^4.9.3" - }, - "dependencies": { - "@noble/secp256k1": "^1.7.0", - "amcl-js": "^3.1.0", - "js-sha256": "^0.10.1" - }, - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "preinstall": "npx only-allow pnpm", - "start": "nodemon", - "build": "tsc -p tsconfig.build.json", - "prettier": "prettier -c . --config ../.prettierrc --ignore-path ../.prettierignore", - "prettier:fix": "prettier -w . --config ../.prettierrc --ignore-path ../.prettierignore", - "types": "tsc -p tsconfig.json --noEmit", - "test": "jest", - "test:coverage": "pnpm run test --coverage", - "publish": "pnpm run build && pnpm publish" - } -} diff --git a/javascript/pnpm-lock.yaml b/javascript/pnpm-lock.yaml deleted file mode 100644 index dfa830f..0000000 --- a/javascript/pnpm-lock.yaml +++ /dev/null @@ -1,2695 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -overrides: - '@noble/secp256k1': ^1.7.0 - -dependencies: - '@noble/secp256k1': - specifier: ^1.7.0 - version: 1.7.1 - amcl-js: - specifier: ^3.1.0 - version: 3.1.0 - js-sha256: - specifier: ^0.10.1 - version: 0.10.1 - -devDependencies: - '@types/jest': - specifier: ^29.5.0 - version: 29.5.8 - '@types/js-sha512': - specifier: ^0 - version: 0.8.0 - '@types/node': - specifier: ^18.11.9 - version: 18.18.9 - '@types/nodemon': - specifier: ^1.19.2 - version: 1.19.5 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@18.18.9)(ts-node@10.9.1) - nodemon: - specifier: ^2.0.20 - version: 2.0.22 - prettier: - specifier: ^3.0.3 - version: 3.0.3 - ts-jest: - specifier: ^29.0.3 - version: 29.1.1(@babel/core@7.23.2)(jest@29.7.0)(typescript@4.9.5) - ts-node: - specifier: ^10.9.1 - version: 10.9.1(@types/node@18.18.9)(typescript@4.9.5) - typescript: - specifier: ^4.9.3 - version: 4.9.5 - -packages: - - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 - dev: true - - /@babel/code-frame@7.22.13: - resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.22.20 - chalk: 2.4.2 - dev: true - - /@babel/compat-data@7.23.2: - resolution: {integrity: sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.23.2: - resolution: {integrity: sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.22.13 - '@babel/generator': 7.23.0 - '@babel/helper-compilation-targets': 7.22.15 - '@babel/helper-module-transforms': 7.23.0(@babel/core@7.23.2) - '@babel/helpers': 7.23.2 - '@babel/parser': 7.23.0 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.2 - '@babel/types': 7.23.0 - convert-source-map: 2.0.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.23.0: - resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.0 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 - jsesc: 2.5.2 - dev: true - - /@babel/helper-compilation-targets@7.22.15: - resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.23.2 - '@babel/helper-validator-option': 7.22.15 - browserslist: 4.22.1 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.0 - dev: true - - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.0 - dev: true - - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.0 - dev: true - - /@babel/helper-module-transforms@7.23.0(@babel/core@7.23.2): - resolution: {integrity: sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.2 - '@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 - dev: true - - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.0 - dev: true - - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.0 - dev: true - - /@babel/helper-string-parser@7.22.5: - resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-option@7.22.15: - resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helpers@7.23.2: - resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.2 - '@babel/types': 7.23.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/highlight@7.22.20: - resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - - /@babel/parser@7.23.0: - resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.23.0 - dev: true - - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.2): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.2): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.2): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.2): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.2): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.2): - resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.2): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.2): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.2): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.2): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.2): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.2): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.2): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.23.2): - resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.2 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/template@7.22.15: - resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.22.13 - '@babel/parser': 7.23.0 - '@babel/types': 7.23.0 - dev: true - - /@babel/traverse@7.23.2: - resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.22.13 - '@babel/generator': 7.23.0 - '@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.23.0 - '@babel/types': 7.23.0 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.23.0: - resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - dev: true - - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - - /@colors/colors@1.5.0: - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - dev: false - - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true - - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - dev: true - - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true - - /@jest/console@29.7.0: - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - dev: true - - /@jest/core@29.7.0(ts-node@10.9.1): - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - 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 - 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': 18.18.9 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.18.9)(ts-node@10.9.1) - 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.5 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /@jest/environment@29.7.0: - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - jest-mock: 29.7.0 - dev: true - - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - dev: true - - /@jest/expect@29.7.0: - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/fake-timers@29.7.0: - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 18.18.9 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - - /@jest/globals@29.7.0: - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/reporters@29.7.0: - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - 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 - 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.20 - '@types/node': 18.18.9 - chalk: 4.1.2 - collect-v8-coverage: 1.0.2 - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.1 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.6 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 - slash: 3.0.0 - string-length: 4.0.2 - strip-ansi: 6.0.1 - v8-to-istanbul: 9.1.3 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@sinclair/typebox': 0.27.8 - dev: true - - /@jest/source-map@29.6.3: - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jridgewell/trace-mapping': 0.3.20 - callsites: 3.1.0 - graceful-fs: 4.2.11 - dev: true - - /@jest/test-result@29.7.0: - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2 - dev: true - - /@jest/test-sequencer@29.7.0: - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - slash: 3.0.0 - dev: true - - /@jest/transform@29.7.0: - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.23.2 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.20 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.5 - pirates: 4.0.6 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 18.18.9 - '@types/yargs': 17.0.31 - chalk: 4.1.2 - dev: true - - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.20 - dev: true - - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true - - /@jridgewell/trace-mapping@0.3.20: - resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@noble/secp256k1@1.7.1: - resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} - dev: false - - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - dev: true - - /@sinonjs/commons@3.0.0: - resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==} - dependencies: - type-detect: 4.0.8 - dev: true - - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - dependencies: - '@sinonjs/commons': 3.0.0 - dev: true - - /@tsconfig/node10@1.0.9: - resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} - dev: true - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true - - /@types/babel__core@7.20.4: - resolution: {integrity: sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==} - dependencies: - '@babel/parser': 7.23.0 - '@babel/types': 7.23.0 - '@types/babel__generator': 7.6.7 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.4 - dev: true - - /@types/babel__generator@7.6.7: - resolution: {integrity: sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==} - dependencies: - '@babel/types': 7.23.0 - dev: true - - /@types/babel__template@7.4.4: - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - dependencies: - '@babel/parser': 7.23.0 - '@babel/types': 7.23.0 - dev: true - - /@types/babel__traverse@7.20.4: - resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==} - dependencies: - '@babel/types': 7.23.0 - dev: true - - /@types/graceful-fs@4.1.9: - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - dependencies: - '@types/node': 18.18.9 - dev: true - - /@types/istanbul-lib-coverage@2.0.6: - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - dev: true - - /@types/istanbul-lib-report@3.0.3: - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - dev: true - - /@types/istanbul-reports@3.0.4: - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - dependencies: - '@types/istanbul-lib-report': 3.0.3 - dev: true - - /@types/jest@29.5.8: - resolution: {integrity: sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==} - dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 - dev: true - - /@types/js-sha512@0.8.0: - resolution: {integrity: sha512-y+GnsWv7/8I3XkMt36KBy6XJfmbKHutMs4Kqj9uj8KImUd7zkLlDSGPDi/Y2CFPcx1rMk6hi9ZohtRqOqcMj9Q==} - deprecated: This is a stub types definition. js-sha512 provides its own type definitions, so you do not need this installed. - dependencies: - js-sha512: 0.8.0 - dev: true - - /@types/node@18.18.9: - resolution: {integrity: sha512-0f5klcuImLnG4Qreu9hPj/rEfFq6YRc5n2mAjSsH+ec/mJL+3voBH0+8T7o8RpFjH7ovc+TRsL/c7OYIQsPTfQ==} - dependencies: - undici-types: 5.26.5 - dev: true - - /@types/nodemon@1.19.5: - resolution: {integrity: sha512-jUKYdrnwLp4jMztMdQEJnF4lBhthCfqE7P6cYCIy0txMJrSFtKqs2HjmyEsyQueLjZjve0IjJ1S+20DtgJpUjA==} - dependencies: - '@types/node': 18.18.9 - dev: true - - /@types/stack-utils@2.0.3: - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - dev: true - - /@types/yargs-parser@21.0.3: - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - dev: true - - /@types/yargs@17.0.31: - resolution: {integrity: sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==} - dependencies: - '@types/yargs-parser': 21.0.3 - dev: true - - /abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - dev: true - - /acorn-walk@8.3.0: - resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn@8.11.2: - resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /amcl-js@3.1.0: - resolution: {integrity: sha512-36dd2w+cqK2NPww9w3ATPqbUeFgDHyTgeyXAk9jd7PXQh3uqSIdjiVCiqijIyAMDCzlkXdotkr8Sv0nmd1/UMQ==} - dependencies: - prompt: 1.3.0 - dev: false - - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.21.3 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true - - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true - - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - - /async@2.6.4: - resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} - dependencies: - lodash: 4.17.21 - dev: false - - /async@3.2.3: - resolution: {integrity: sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==} - dev: false - - /babel-jest@29.7.0(@babel/core@7.23.2): - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - dependencies: - '@babel/core': 7.23.2 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.4 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.23.2) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - dependencies: - '@babel/helper-plugin-utils': 7.22.5 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.0 - '@types/babel__core': 7.20.4 - '@types/babel__traverse': 7.20.4 - dev: true - - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.2): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.2 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.2) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.2) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.2) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.2) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.2) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.2) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.2) - dev: true - - /babel-preset-jest@29.6.3(@babel/core@7.23.2): - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.2 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.2) - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /browserslist@4.22.1: - resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001561 - electron-to-chromium: 1.4.578 - node-releases: 2.0.13 - update-browserslist-db: 1.0.13(browserslist@4.22.1) - dev: true - - /bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - dependencies: - fast-json-stable-stringify: 2.1.0 - dev: true - - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - dependencies: - node-int64: 0.4.0 - dev: true - - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - dev: true - - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true - - /caniuse-lite@1.0.30001561: - resolution: {integrity: sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==} - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true - - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - dev: true - - /cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - dev: true - - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true - - /collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /colors@1.0.3: - resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} - engines: {node: '>=0.1.90'} - dev: false - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - - /create-jest@29.7.0(@types/node@18.18.9)(ts-node@10.9.1): - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.18.9)(ts-node@10.9.1) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /cycle@1.0.3: - resolution: {integrity: sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==} - engines: {node: '>=0.4.0'} - dev: false - - /debug@3.2.7(supports-color@5.5.0): - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - supports-color: 5.5.0 - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /dedent@1.5.1: - resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - dev: true - - /deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - dev: true - - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true - - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true - - /electron-to-chromium@1.4.578: - resolution: {integrity: sha512-V0ZhSu1BQZKfG0yNEL6Dadzik8E1vAzfpVOapdSiT9F6yapEJ3Bk+4tZ4SMPdWiUchCgnM/ByYtBzp5ntzDMIA==} - dev: true - - /emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true - - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - dev: true - - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - 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 - dev: true - - /eyes@0.1.8: - resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} - engines: {node: '> 0.1.90'} - dev: false - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - dependencies: - bser: 2.1.1 - dev: true - - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true - - /get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true - - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - dev: true - - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true - - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true - - /ignore-by-default@1.0.1: - resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} - dev: true - - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 - dev: true - - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true - - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.2.0 - dev: true - - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - dependencies: - hasown: 2.0.0 - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - dev: false - - /istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - dev: true - - /istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - dependencies: - '@babel/core': 7.23.2 - '@babel/parser': 7.23.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-lib-instrument@6.0.1: - resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} - engines: {node: '>=10'} - dependencies: - '@babel/core': 7.23.2 - '@babel/parser': 7.23.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - dev: true - - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - dependencies: - debug: 4.3.4 - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-reports@3.1.6: - resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} - engines: {node: '>=8'} - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - dev: true - - /jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - execa: 5.1.1 - jest-util: 29.7.0 - p-limit: 3.1.0 - dev: true - - /jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - chalk: 4.1.2 - co: 4.6.0 - dedent: 1.5.1 - is-generator-fn: 2.1.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.4 - slash: 3.0.0 - stack-utils: 2.0.6 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - - /jest-cli@29.7.0(@types/node@18.18.9)(ts-node@10.9.1): - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.18.9)(ts-node@10.9.1) - exit: 0.1.2 - import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.18.9)(ts-node@10.9.1) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /jest-config@29.7.0(@types/node@18.18.9)(ts-node@10.9.1): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - 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 - dependencies: - '@babel/core': 7.23.2 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - babel-jest: 29.7.0(@babel/core@7.23.2) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - 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.5 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - ts-node: 10.9.1(@types/node@18.18.9)(typescript@4.9.5) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - - /jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - detect-newline: 3.1.0 - dev: true - - /jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 - dev: true - - /jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 18.18.9 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.5 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.22.13 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.3 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.5 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 - dev: true - - /jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - jest-util: 29.7.0 - dev: true - - /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: - jest-resolve: 29.7.0 - dev: true - - /jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.8 - resolve.exports: 2.0.2 - slash: 3.0.0 - dev: true - - /jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@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': 18.18.9 - chalk: 4.1.2 - emittery: 0.13.1 - graceful-fs: 4.2.11 - 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 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - 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': 18.18.9 - chalk: 4.1.2 - cjs-module-lexer: 1.2.3 - collect-v8-coverage: 1.0.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - 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 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.23.2 - '@babel/generator': 7.23.0 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.2) - '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.23.2) - '@babel/types': 7.23.0 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.2) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.11 - 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.4 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - dev: true - - /jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.6.3 - leven: 3.1.0 - pretty-format: 29.7.0 - dev: true - - /jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.18.9 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 29.7.0 - string-length: 4.0.2 - dev: true - - /jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@types/node': 18.18.9 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - - /jest@29.7.0(@types/node@18.18.9)(ts-node@10.9.1): - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1) - '@jest/types': 29.6.3 - import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.18.9)(ts-node@10.9.1) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - - /js-sha256@0.10.1: - resolution: {integrity: sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw==} - dev: false - - /js-sha512@0.8.0: - resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true - - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true - - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true - - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - dev: true - - /lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - dev: true - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - dependencies: - semver: 7.5.4 - dev: true - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - dependencies: - tmpl: 1.0.5 - dev: true - - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - dev: true - - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - dev: false - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true - - /node-releases@2.0.13: - resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} - dev: true - - /nodemon@2.0.22: - resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} - engines: {node: '>=8.10.0'} - hasBin: true - dependencies: - chokidar: 3.5.3 - debug: 3.2.7(supports-color@5.5.0) - ignore-by-default: 1.0.1 - minimatch: 3.1.2 - pstree.remy: 1.1.8 - semver: 5.7.2 - simple-update-notifier: 1.1.0 - supports-color: 5.5.0 - touch: 3.1.0 - undefsafe: 2.0.5 - dev: true - - /nopt@1.0.10: - resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} - hasBin: true - dependencies: - abbrev: 1.1.1 - dev: true - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - dev: true - - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - dependencies: - p-try: 2.2.0 - dev: true - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - dependencies: - p-limit: 2.3.0 - dev: true - - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - dev: true - - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.22.13 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - dev: true - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - - /pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - dev: true - - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - dev: true - - /prettier@3.0.3: - resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} - engines: {node: '>=14'} - hasBin: true - dev: true - - /pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.2.0 - dev: true - - /prompt@1.3.0: - resolution: {integrity: sha512-ZkaRWtaLBZl7KKAKndKYUL8WqNT+cQHKRZnT4RYYms48jQkFw3rrBL+/N5K/KtdEveHkxs982MX2BkDKub2ZMg==} - engines: {node: '>= 6.0.0'} - dependencies: - '@colors/colors': 1.5.0 - async: 3.2.3 - read: 1.0.7 - revalidator: 0.1.8 - winston: 2.4.7 - dev: false - - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - dev: true - - /pstree.remy@1.1.8: - resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} - dev: true - - /pure-rand@6.0.4: - resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} - dev: true - - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true - - /read@1.0.7: - resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} - engines: {node: '>=0.8'} - dependencies: - mute-stream: 0.0.8 - dev: false - - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - dev: true - - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true - - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - dependencies: - resolve-from: 5.0.0 - dev: true - - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true - - /resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - dev: true - - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /revalidator@0.1.8: - resolution: {integrity: sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg==} - engines: {node: '>= 0.4.0'} - dev: false - - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - dev: true - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /semver@7.0.0: - resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} - hasBin: true - dev: true - - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true - - /simple-update-notifier@1.1.0: - resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} - engines: {node: '>=8.10.0'} - dependencies: - semver: 7.0.0 - dev: true - - /sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true - - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true - - /source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true - - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true - - /stack-trace@0.0.10: - resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} - dev: false - - /stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - dev: true - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true - - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true - - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true - - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - - /touch@3.1.0: - resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} - hasBin: true - dependencies: - nopt: 1.0.10 - dev: true - - /ts-jest@29.1.1(@babel/core@7.23.2)(jest@29.7.0)(typescript@4.9.5): - resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - '@babel/core': 7.23.2 - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.18.9)(ts-node@10.9.1) - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.5.4 - typescript: 4.9.5 - yargs-parser: 21.1.1 - dev: true - - /ts-node@10.9.1(@types/node@18.18.9)(typescript@4.9.5): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} - hasBin: true - 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 - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 18.18.9 - acorn: 8.11.2 - acorn-walk: 8.3.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 4.9.5 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true - - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true - - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - - /undefsafe@2.0.5: - resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} - dev: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /update-browserslist-db@1.0.13(browserslist@4.22.1): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.22.1 - escalade: 3.1.1 - picocolors: 1.0.0 - dev: true - - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true - - /v8-to-istanbul@9.1.3: - resolution: {integrity: sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==} - engines: {node: '>=10.12.0'} - dependencies: - '@jridgewell/trace-mapping': 0.3.20 - '@types/istanbul-lib-coverage': 2.0.6 - convert-source-map: 2.0.0 - dev: true - - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - dependencies: - makeerror: 1.0.12 - dev: true - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /winston@2.4.7: - resolution: {integrity: sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==} - engines: {node: '>= 0.10.0'} - dependencies: - async: 2.6.4 - colors: 1.0.3 - cycle: 1.0.3 - eyes: 0.1.8 - isstream: 0.1.2 - stack-trace: 0.0.10 - dev: false - - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - dev: true - - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true - - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - 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.8 - yargs-parser: 21.1.1 - dev: true - - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true diff --git a/javascript/src/index.ts b/javascript/src/index.ts deleted file mode 100644 index 8df9d11..0000000 --- a/javascript/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { computeAllInputs, PlumeVersion } from "./signals"; diff --git a/javascript/src/lib.rs b/javascript/src/lib.rs new file mode 100644 index 0000000..63f4fa7 --- /dev/null +++ b/javascript/src/lib.rs @@ -0,0 +1,292 @@ +//! Will this add module JSdoc? +// TODO add interop testing for JSON +// TODO should I do examples rustdoc style or javadoc? +/* +I want to have a look at good and *small* example for... +* JS tests and CI +* documenting +* setters/getters/exporting, general tricks, API, constructors */ + +mod utils; // TODO I guess this one isn't panicing, + +// use std::convert::{TryFrom, TryInto}; + +use k256::pkcs8::DecodePrivateKey; +use k256::SecretKey; +use plume_rustcrypto::AffinePoint; +use wasm_bindgen::prelude::*; + +use elliptic_curve::sec1::FromEncodedPoint; +use zeroize::Zeroize; +use elliptic_curve::rand_core::SeedableRng; +use elliptic_curve::sec1::ToEncodedPoint; +use signature::RandomizedSigner; + +use wasm_bindgen_futures::JsFuture; + +#[wasm_bindgen(getter_with_clone)] +/// @typedef {Object} PlumeSignature - Wrapper around [`plume_rustcrypto::PlumeSignature`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/struct.PlumeSignature.html). +/// [`plume_rustcrypto::AffinePoint`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/struct.AffinePoint.html) is represented as a `Uint8Array` containing SEC1 encoded point. +/// [`plume_rustcrypto::NonZeroScalar`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/type.NonZeroScalar.html) is represented as a `BigInt`. +/// `Option` can be `undefined` or instance of [`PlumeSignatureV1Fields`]. +pub struct PlumeSignature { + pub message: Vec, + pub pk: Vec, // TODO protect with public `web_sys::CryptoKey` + pub nullifier: Vec, + pub c: web_sys::CryptoKey, + pub s: js_sys::BigInt, // it's overprotected in the crate, no need for `CryptoKey` here + pub v1specific: Option, +} + +#[wasm_bindgen(getter_with_clone)] +/// @typedef {Object} PlumeSignatureV1Fields - Wrapper around [`plume_rustcrypto::PlumeSignatureV1Fields`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/struct.PlumeSignatureV1Fields.html). +#[derive(Clone)] +pub struct PlumeSignatureV1Fields { + pub r_point: Vec, + pub hashed_to_curve_r: Vec, +} +#[wasm_bindgen()] +impl PlumeSignatureV1Fields { + #[wasm_bindgen(constructor)] + pub fn new(r_point: Vec, hashed_to_curve_r: Vec) -> PlumeSignatureV1Fields { + PlumeSignatureV1Fields { r_point, hashed_to_curve_r } + } +} + +#[wasm_bindgen] +impl PlumeSignature { + // #[wasm_bindgen(setter)] + // pub fn set_message(&mut self, field: Vec) { + // self.message = field; + // } + + /// `v1specific` discriminates if it's V1 or V2 scheme used. Pls, see wrapped docs for details. + #[wasm_bindgen(constructor)] + pub fn new( + message: Vec, + pk: Vec, + nullifier: Vec, + c: web_sys::CryptoKey, + s: js_sys::BigInt, + v1specific: Option + ) -> PlumeSignature { + PlumeSignature { + /* I really wonder how good is this pattern. But taking so much of args isn't good, and builder pattern seems redundant as all + of the fields are required, and setters are just assignments. */ + // TODO solve/test v1 field: start with adding its constructor + message, pk, nullifier, c, s, + v1specific//: if v1specific.is_falsy() {None} else {Some(v1specific)} + } + + // js_sys::Object::from_entries(&values)? + // values.get + } +} + +#[wasm_bindgen(skip_jsdoc)] +/// @throws a "crypto error" in case of a problem with the secret key +/// @param {boolean} v1 - is the flag to choose between V1 and V2 output. +/// @param {Uint8Array} sk - must be exactly 32 bytes, and strictly represent a non-zero scalar of `secp256` in big-endian. +/// @param {Uint8Array} msg +/// @returns {PlumeSignature} +// Wasm environment doesn't have a suitable way to get randomness for the signing process, so this instantiates ChaCha20 RNG with the provided seed. +// @throws a "crypto error" in case of a problem with the secret key, and a verbal error on a problem with `seed` +// @param {Uint8Array} seed - must be exactly 32 bytes. +// pub fn sign(seed: &mut [u8], v1: bool, sk: &mut [u8], msg: &[u8]) -> Result { +pub async fn sign(v1: bool, sk: web_sys::CryptoKey, msg: &[u8]) -> Result { + if sk.type_() != "secret" {return Err(JsError::new("`sk` must be secret key"))} + if !js_sys::Object::values(&sk.algorithm().map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?).includes(&JsValue::from_str("P-256"), 0) {return Err(JsError::new("`sk` must be from `secp256`"))} + + // this was my approach, but seems I got what they did at + // js_sys::global().entries().find(); // TODO throw if no Crypto in global + + let global_the: Global = js_sys::global().unchecked_into(); // is it not `dyn_into` here for speed? https://github.com/rust-random/getrandom/commit/120a1d7f4796356a1f60cd84bd7a0ceafbac9d0e#commitcomment-143690574 + let crypto_the: web_sys::Crypto = global_the.crypto(); + let subtle_the = crypto_the.subtle(); + // let sk = JsFuture::from(subtle_the.export_key("pkcs8", &sk)?).await?; + + let mut sk_z = + // plume_rustcrypto::SecretKey + // ::from(plume_rustcrypto::NonZeroScalar::try_from(sk.as_ref())?); + // ::from_pkcs8_der(js_sys::ArrayBuffer::from(sk).try_into()?)?; + zeroize::Zeroizing::new(js_sys::Uint8Array::from(JsFuture::from(subtle_the.export_key("pkcs8", &sk).map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?).await.map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?).to_vec()); + let sk = plume_rustcrypto::SecretKey::from_pkcs8_der(sk_z.as_ref())?; + sk_z.zeroize(); + let signer = plume_rustcrypto::randomizedsigner::PlumeSigner::new(&sk, v1); + // let seed_z: zeroize::Zeroizing<[u8; 32]> = zeroize::Zeroizing::new(seed.try_into()?); + // // TODO protect `seed` with ~~zeroization~~ and so on + // seed.zeroize(); + + // TODO switch to `wasi-random` when that will be ready for crypto + // let sig = match v1 { + // true => plume_rustcrypto::PlumeSignature::sign_v1( + // &sk_z, msg, &mut rand_chacha::ChaCha20Rng::from_seed(seed_z) + // ), + // false => plume_rustcrypto::PlumeSignature::sign_v2( + // &sk_z, msg, &mut rand_chacha::ChaCha20Rng::from_seed(seed_z) + // ), + // }; + + /* current implementation does bad job protecting few parts meant to be private, see + I feel it doesn't make sense to try mitigating that in the wrapper, but just to update this when the issue is solved */ + let sig_the = signer.sign_with_rng( + // &mut rand_chacha::ChaCha20Rng::from_seed(*seed_z), + &mut rand::rngs::OsRng, + msg + ); + // I had the trait for this, but due to `async` it seems more natural to just move that code here. + // impl From for PlumeSignature { + // fn from(value: plume_rustcrypto::PlumeSignature) -> Self { + let nonzeroscalartobigint = |v: plume_rustcrypto::NonZeroScalar| -> js_sys::BigInt { + js_sys::BigInt::new(&JsValue::from_str(("0x".to_owned() + v.to_string().as_str()).as_str())).expect("`BigInt` always can be created from hex string, and `v.to_string()` always produce that") + }; + + Ok(PlumeSignature { + message: msg.to_vec(), + pk: sig_the.pk.to_encoded_point(true).as_bytes().to_vec(), + nullifier: sig_the.nullifier.to_encoded_point(true).as_bytes().to_vec(), + c: JsFuture::from(subtle_the.import_key_with_object( + "pkcs8", + js_sys::Uint8Array::from(SecretKey::from(sig_the.c).to_sec1_der()?.as_ref()).as_ref(), + web_sys::EcKeyImportParams::new("ECDSA").named_curve("P-256"), + true, + js_sys::Array::new().as_ref(), // I can't see a valid usage for this among + ).map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?).await.map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?.dyn_into().map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?, + s: nonzeroscalartobigint(sig_the.s), + v1specific: if let Some(v1) = sig_the.v1specific {Some( + PlumeSignatureV1Fields { + r_point: v1.r_point.to_encoded_point(true).as_bytes().to_vec(), + hashed_to_curve_r: v1.hashed_to_curve_r.to_encoded_point(true).as_bytes().to_vec(), + } + )} else {None}, + }) + // } + // } + + // let debugging = signer.sign_with_rng( + // &mut rand_chacha::ChaCha20Rng::from_seed(*seed_z), msg + // ); + // js_sys::BigInt::new(&JsValue::from_str(("0x".to_owned() + debugging.c.to_string().as_str()).as_str())).expect("`BigInt` always can be created from decimal string, and `c.to_string()` always produce that"); + // // Err(JsError::new(debugging.c.to_string().as_str())) + // Ok( + // PlumeSignature{ message: Default::default(), pk: Default::default(), nullifier: Default::default(), c: Default::default(), s: Default::default(), v1specific: Default::default() } + // ) +} +#[wasm_bindgen] +extern "C" { + // Return type of js_sys::global() + type Global; + // // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/) + // type WebCrypto; + // Getters for the WebCrypto API + #[wasm_bindgen(method, getter)] + fn crypto(this: &Global) -> web_sys::Crypto; +} + +// this was a `PlumeSignature` method, but thanks to `async` it been moved to standalone +/// @deprecated Use this only for testing purposes. +/// @throws a error if the data in the object doesn't let it to properly run verification; message contains nature of the problem and indicates relevant property of the object. In case of other (crypto) problems returns `false`. +#[wasm_bindgen] +pub async fn verify(self_: PlumeSignature) -> Result { + // #async #traits + // impl TryInto for PlumeSignature { + // type Error = JsError; + + // fn try_into(self) -> Result { + // if let Some(v1) = self.v1specific {Some( + // plume_rustcrypto::PlumeSignatureV1Fields{ + // r_point: v1.r_point.try_into()?, + // hashed_to_curve_r: v1.hashed_to_curve_r.try_into()?, + // } + // )} + + // let mut points = [self.pk, self.nullifier]; //, self.v1specific); + // if Some(points_v1) = self.v1specific {po} + + let point_check = |/* name_field: &str, */ point_bytes: Vec| -> Result { + let point_encoded = sec1::point::EncodedPoint::from_bytes(point_bytes)?; // TODO improve formatting (quotes e.g.) + let result = plume_rustcrypto::AffinePoint::from_encoded_point(&point_encoded); + if result.is_none().into() {Err(anyhow::Error::msg("the point isn't on the curve"))} + else {Ok(result.expect(EXPECT_NONEALREADYCHECKED))} + }; + + // plume_rustcrypto::Scalar::try_from(self.c.to_string(16)?.as_string()?); + // k256::Scalar::from_repr(hex::decode(self.c.to_string(16)?.as_ref())?); // TODO test endianness here and correctness + let scalar_from_bigint = + |/* name_field: &str, */ n: js_sys::BigInt| -> Result { + let result = plume_rustcrypto::NonZeroScalar::from_repr(k256::FieldBytes::from_slice( + hex::decode({ + let hexstring_freelen = n.to_string(16).map_err( + |er| + anyhow::Error::msg(er.as_string().expect("`RangeError` can be printed out")) + )?.as_string().expect("on `JsString` this always produce a `String`"); + let l = hexstring_freelen.len(); + if l > 32*2 {return Err(anyhow::Error::msg("too many digits"))} + else {["0".repeat(64-l), hexstring_freelen].concat()} + })?.as_slice() + ).to_owned()); + if result.is_none().into() {Err(anyhow::Error::msg("isn't valid `secp256` non-zero scalar"))} + else {Ok(result.expect(EXPECT_NONEALREADYCHECKED))} + }; + const EXPECT_NONEALREADYCHECKED: &'static str = "`None` is processed the line above"; + + let err_field_wrap = |name_field: &str, er: anyhow::Error| -> JsError {JsError::new( + ("while proccessing ".to_owned() + name_field + " :" + er.to_string().as_str()).as_str() + /* "while proccessing ".to_owned().join(), + name_field, + " :", + er.to_string().as_str() + ].concat()) */)}; + + // zeroization protection ommitted here due to deprecation // + // mostly boilerplate from signing; also some excessive ops left for the same reason + // TODO align error-handling in this part + if self_.c.type_() != "secret" {return Err(JsError::new("`c` must be secret key"))} + if !js_sys::Object::values(&self_.c.algorithm().map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?).includes(&JsValue::from_str("P-256"), 0) {return Err(JsError::new("`c` must be from `secp256`"))} + // TODO finish + // this was my approach, but seems I got what they did at + // js_sys::global().entries().find(); // TODO throw if no Crypto in global + let global_the: Global = js_sys::global().unchecked_into(); + let crypto_the: web_sys::Crypto = global_the.crypto(); + let subtle_the = crypto_the.subtle(); + let c_pkcs = //zeroize::Zeroizing::new( + js_sys::Uint8Array::from(JsFuture::from(subtle_the.export_key("pkcs8", &self_.c).map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?).await.map_err( + |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) + )?).to_vec(); + // ); + let c_scalar = &plume_rustcrypto::SecretKey::from_pkcs8_der(&c_pkcs)?.to_nonzero_scalar(); + // sk_z.zeroize(); + + Ok(plume_rustcrypto::PlumeSignature{ + message: self_.message, + pk: point_check(self_.pk).map_err(|er| err_field_wrap("`pk`", er))?, + // plume_rustcrypto::AffinePoint::try_from(self.pk)?, //.try_into<[u8; 33]>()?.into(), + nullifier: point_check(self_.nullifier).map_err(|er| err_field_wrap("`nullifier`", er))?, + c: *c_scalar, + s: scalar_from_bigint(self_.s).map_err(|er| err_field_wrap("`s`", er))?, + v1specific: if let Some(v1) = self_.v1specific {Some( + plume_rustcrypto::PlumeSignatureV1Fields{ + r_point: point_check(v1.r_point).map_err(|er| err_field_wrap("`r_point`", er))?, + hashed_to_curve_r: point_check(v1.hashed_to_curve_r).map_err(|er| err_field_wrap("`hashed_to_curve_r`", er))?, + } + )} else {None}, + }.verify()) + // } + // } +} \ No newline at end of file diff --git a/javascript/src/signals.ts b/javascript/src/signals.ts deleted file mode 100644 index 33fbd5e..0000000 --- a/javascript/src/signals.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { CURVE, getPublicKey, Point, utils } from "@noble/secp256k1"; -import { - concatUint8Arrays, - hexToBigInt, - hexToUint8Array, - messageToUint8Array, - uint8ArrayToBigInt, -} from "./utils/encoding"; -import hashToCurve from "./utils/hashToCurve"; -import { HashedPoint, multiplyPoint } from "./utils/curve"; -import { sha256 } from "js-sha256"; - -// PLUME version -export enum PlumeVersion { - V1 = 1, - V2 = 2, -} - -export function computeHashToCurve( - message: Uint8Array, - pk: Uint8Array, -): HashedPoint { - // Concatenate message and publicKey - const preimage = new Uint8Array(message.length + pk.length); - preimage.set(message); - preimage.set(pk, message.length); - return hashToCurve(Array.from(preimage)); -} - -export function computeC_V2( - nullifier: Point, - rPoint: Point, - hashedToCurveR: Point, -) { - const nullifierBytes = nullifier.toRawBytes(true); - const preimage = concatUint8Arrays([ - nullifierBytes, - rPoint.toRawBytes(true), - hashedToCurveR.toRawBytes(true), - ]); - return sha256.create().update(preimage).hex(); -} - -export function computeC_V1( - pkBytes: Uint8Array, - hashedToCurve: HashedPoint, - nullifier: Point, - rPoint: Point, - hashedToCurveR: Point, -) { - const nullifierBytes = nullifier.toRawBytes(true); - const preimage = concatUint8Arrays([ - Point.BASE.toRawBytes(true), - pkBytes, - new Point( - hexToBigInt(hashedToCurve.x.toString()), - hexToBigInt(hashedToCurve.y.toString()), - ).toRawBytes(true), - nullifierBytes, - rPoint.toRawBytes(true), - hashedToCurveR.toRawBytes(true), - ]); - return sha256.create().update(preimage).hex(); -} - -export function computeNullifer(hashedToCurve: HashedPoint, sk: Uint8Array) { - return multiplyPoint(hashedToCurve, sk); -} - -export function computeRPoint(rScalar: Uint8Array) { - return Point.fromPrivateKey(rScalar); -} - -export function computeHashToCurveR( - hashedToCurve: HashedPoint, - rScalar: Uint8Array, -) { - return multiplyPoint(hashedToCurve, rScalar); -} - -export function computeS(rScalar: Uint8Array, sk: Uint8Array, c: string) { - return ( - (((uint8ArrayToBigInt(sk) * hexToBigInt(c)) % CURVE.n) + - uint8ArrayToBigInt(rScalar)) % - CURVE.n - ).toString(16); -} - -/** - * Computes and returns the Plume and other signals for the prover. - * @param {string | Uint8Array} message - Message to sign, in either string or UTF-8 array format. - * @param {string | Uint8Array} sk - ECDSA secret key to sign with. - * @param {string| Uint8Array} rScalar - Optional seed for randomness. - * @returns Object containing Plume and other signals - public key, s, c, gPowR, and hashMPKPowR. - */ -export function computeAllInputs( - message: string | Uint8Array, - sk: string | Uint8Array, - rScalar?: string | Uint8Array, - version: PlumeVersion = PlumeVersion.V2, -) { - const skBytes = typeof sk === "string" ? hexToUint8Array(sk) : sk; - const messageBytes = - typeof message === "string" ? messageToUint8Array(message) : message; - const pkBytes = getPublicKey(skBytes, true); - - let rScalarBytes: Uint8Array; - if (rScalar) { - rScalarBytes = - typeof rScalar === "string" ? hexToUint8Array(rScalar) : rScalar; - } else { - rScalarBytes = utils.randomPrivateKey(); - } - - const hashedToCurve = computeHashToCurve(messageBytes, pkBytes); - const nullifier = computeNullifer(hashedToCurve, skBytes); - const hashedToCurveR = computeHashToCurveR(hashedToCurve, rScalarBytes); - const rPoint = computeRPoint(rScalarBytes); - const c = - version == PlumeVersion.V1 - ? computeC_V1(pkBytes, hashedToCurve, nullifier, rPoint, hashedToCurveR) - : computeC_V2(nullifier, rPoint, hashedToCurveR); - const s = computeS(rScalarBytes, skBytes, c); - - return { - plume: nullifier, - s, - pk: pkBytes, - c, - rPoint, - hashedToCurveR, - }; -} diff --git a/javascript/src/utils.rs b/javascript/src/utils.rs new file mode 100644 index 0000000..b1d7929 --- /dev/null +++ b/javascript/src/utils.rs @@ -0,0 +1,10 @@ +pub fn set_panic_hook() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); +} diff --git a/javascript/src/utils/curve.ts b/javascript/src/utils/curve.ts deleted file mode 100644 index efe1750..0000000 --- a/javascript/src/utils/curve.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Point } from "@noble/secp256k1"; -import { uint8ArrayToHex } from "./encoding"; - -export interface HashedPoint { - x: { - toString(): string; - }; - y: { - toString(): string; - }; -} - -export function multiplyPoint(h: HashedPoint, secretKey: Uint8Array) { - const hashPoint = new Point( - BigInt("0x" + h.x.toString()), - BigInt("0x" + h.y.toString()), - ); - - return hashPoint.multiply(BigInt("0x" + uint8ArrayToHex(secretKey))); -} diff --git a/javascript/src/utils/encoding.ts b/javascript/src/utils/encoding.ts deleted file mode 100644 index a0c694e..0000000 --- a/javascript/src/utils/encoding.ts +++ /dev/null @@ -1,59 +0,0 @@ -const utf8Encoder = new TextEncoder(); - -export function messageToUint8Array(message: string): Uint8Array { - return utf8Encoder.encode(message); -} - -export function hexToUint8Array(hexString: string): Uint8Array { - // Source: https://stackoverflow.com/questions/38987784/how-to-convert-a-hexadecimal-string-to-uint8array-and-back-in-javascript/50868276#50868276 - return Uint8Array.from( - hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)), - ); -} - -export function uint8ArrayToHex(uint8Array: Uint8Array) { - // Source: https://stackoverflow.com/questions/38987784/how-to-convert-a-hexadecimal-string-to-uint8array-and-back-in-javascript/50868276#50868276 - return uint8Array.reduce( - (str, byte) => str + byte.toString(16).padStart(2, "0"), - "", - ); -} - -export function hexToBigInt(hex: string): bigint { - return BigInt("0x" + hex); -} - -export function uint8ArrayToBigInt(buffer: Uint8Array): bigint { - return hexToBigInt(uint8ArrayToHex(buffer)); -} - -export function asciitobytes(s: string): number[] { - const b: number[] = []; - - for (let i = 0; i < s.length; i++) { - b.push(s.charCodeAt(i)); - } - - return b; -} - -export function concatUint8Arrays(arrays: Uint8Array[]) { - // sum of individual array lengths - const totalLength = arrays.reduce((acc, value) => acc + value.length, 0); - - const result = new Uint8Array(totalLength); - - if (!arrays.length) { - return result; - } - - // for each array - copy it over result - // next array is copied right after the previous one - let length = 0; - for (let array of arrays) { - result.set(array, length); - length += array.length; - } - - return result; -} diff --git a/javascript/src/utils/hashToCurve.ts b/javascript/src/utils/hashToCurve.ts deleted file mode 100644 index 31599bb..0000000 --- a/javascript/src/utils/hashToCurve.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { CTX } from "amcl-js"; -import { asciitobytes } from "./encoding"; - -// Refactored from miracl-core -const ctx = new CTX("SECP256K1") as any; -const ro = "QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_"; -const hlen = ctx.ECP.HASH_TYPE; - -function ceil(a, b) { - return Math.floor((a - 1) / b + 1); -} - -function hashToField(ctx, hash, hlen, DST, M, ctr) { - const u = []; - const q = new ctx.BIG(0); - q.rcopy(ctx.ROM_FIELD.Modulus); - const k = q.nbits(); - const r = new ctx.BIG(0); - r.rcopy(ctx.ROM_CURVE.CURVE_Order); - const m = r.nbits(); - const L = ceil(k + ceil(m, 2), 8); - const OKM = ctx.HMAC.XMD_Expand(hash, hlen, L * ctr, DST, M); - const fd = []; - - for (let i = 0; i < ctr; i++) { - for (let j = 0; j < L; j++) { - fd[j] = OKM[i * L + j]; - } - - const dx = ctx.DBIG.fromBytes(fd); - const w = new ctx.FP(dx.mod(q)); - u[i] = new ctx.FP(w); - } - - return u; -} - -// Taken from https://github.com/miracl/core/blob/master/javascript/examples/node/TestHTP.js#L37 -function hashToPairing(ctx, M, ro, hlen) { - const DSTRO = asciitobytes(ro); - const u = hashToField(ctx, ctx.HMAC.MC_SHA2, hlen, DSTRO, M, 2); - const P = ctx.ECP.map2point(u[0]); - const P1 = ctx.ECP.map2point(u[1]); - P.add(P1); - P.cfp(); - P.affine(); - - return P; -} - -export default function hashToCurve(bytes: number[]) { - return hashToPairing(ctx, bytes, ro, hlen); -} diff --git a/javascript/test/consts.ts b/javascript/test/consts.ts deleted file mode 100644 index 945847f..0000000 --- a/javascript/test/consts.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { getPublicKey, Point } from "@noble/secp256k1"; -import { - computeC_V1, - computeC_V2, - computeRPoint, - computeHashToCurve, - computeHashToCurveR, - computeNullifer, - computeS, -} from "../src/signals"; -import { hexToUint8Array, messageToUint8Array } from "../src/utils/encoding"; - -export const testSecretKey = hexToUint8Array( - "519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464", -); - -export const testPublicKeyPoint = Point.fromPrivateKey(testSecretKey); -export const testPublicKey = getPublicKey(testSecretKey, true); - -export const testR = hexToUint8Array( - "93b9323b629f251b8f3fc2dd11f4672c5544e8230d493eceea98a90bda789808", -); -export const testMessageString = "An example app message string"; -export const testMessage = messageToUint8Array(testMessageString); -export const hashMPk = computeHashToCurve( - testMessage, - Buffer.from(testPublicKey), -); -export const nullifier = computeNullifer(hashMPk, testSecretKey); -export const hashedToCurveR = computeHashToCurveR(hashMPk, testR); -export const rPoint = computeRPoint(testR); -export const c_v1 = computeC_V1( - testPublicKey, - hashMPk, - nullifier as unknown as Point, - rPoint, - hashedToCurveR, -); -export const s_v1 = computeS(testR, testSecretKey, c_v1); - -export const c_v2 = computeC_V2(nullifier, rPoint, hashedToCurveR); -export const s_v2 = computeS(testR, testSecretKey, c_v2); diff --git a/javascript/test/encoding.test.ts b/javascript/test/encoding.test.ts deleted file mode 100644 index 62bc4d0..0000000 --- a/javascript/test/encoding.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - hexToBigInt, - hexToUint8Array, - uint8ArrayToBigInt, - uint8ArrayToHex, -} from "../src/utils/encoding"; - -const TEST_VALS = [ - { - hex: "a413bc5f", - uint8: Uint8Array.from([164, 19, 188, 95]), - bigint: 2752756831n, - }, - { - hex: "f09f8fb3efb88fe2808df09f8c88", - uint8: Uint8Array.from([ - 240, 159, 143, 179, 239, 184, 143, 226, 128, 141, 240, 159, 140, 136, - ]), - bigint: 4880420056602345253094210752449672n, - }, -]; - -describe("encoding", () => { - it("hexToUint8Array", () => { - expect(hexToUint8Array(TEST_VALS[0].hex)).toEqual(TEST_VALS[0].uint8); - expect(hexToUint8Array(TEST_VALS[1].hex)).toEqual(TEST_VALS[1].uint8); - }); - - it("uint8ArrayToHex", () => { - expect(uint8ArrayToHex(TEST_VALS[0].uint8)).toEqual(TEST_VALS[0].hex); - expect(uint8ArrayToHex(TEST_VALS[1].uint8)).toEqual(TEST_VALS[1].hex); - }); - - it("hexToBigInt", () => { - expect(hexToBigInt(TEST_VALS[0].hex)).toEqual(TEST_VALS[0].bigint); - expect(hexToBigInt(TEST_VALS[1].hex)).toEqual(TEST_VALS[1].bigint); - }); - - it("uint8ArrayToBigInt", () => { - expect(uint8ArrayToBigInt(TEST_VALS[0].uint8)).toEqual(TEST_VALS[0].bigint); - expect(uint8ArrayToBigInt(TEST_VALS[1].uint8)).toEqual(TEST_VALS[1].bigint); - }); -}); diff --git a/javascript/test/hashToCurve.test.ts b/javascript/test/hashToCurve.test.ts deleted file mode 100644 index 4e970d3..0000000 --- a/javascript/test/hashToCurve.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import hashToCurve from "../src/utils/hashToCurve"; - -describe("hashToCurve", () => { - it("successfully hashes correct values", () => { - const testPreimage = [ - 65, 110, 32, 101, 120, 97, 109, 112, 108, 101, 32, 97, 112, 112, 32, 109, - 101, 115, 115, 97, 103, 101, 32, 115, 116, 114, 105, 110, 103, 3, 12, 236, - 2, 142, 224, 141, 9, 224, 38, 114, 166, 131, 16, 129, 67, 84, 249, 234, - 191, 255, 13, 230, 218, 204, 28, 211, 167, 116, 73, 96, 118, 174, - ]; - - const hash = hashToCurve(testPreimage); - - expect(hash.x.toString()).toEqual( - "bcac2d0e12679f23c218889395abcdc01f2affbc49c54d1136a2190db0800b65", - ); - expect(hash.y.toString()).toEqual( - "3bcfb339c974c0e757d348081f90a123b0a91a53e32b3752145d87f0cd70966e", - ); - }); -}); diff --git a/javascript/test/signals.test.ts b/javascript/test/signals.test.ts deleted file mode 100644 index f6b8894..0000000 --- a/javascript/test/signals.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { - hashMPk, - nullifier, - hashedToCurveR, - rPoint, - c_v1, - s_v1, - c_v2, - s_v2, - testPublicKey, - testSecretKey, - testMessage, - testR, -} from "./consts"; - -import { computeAllInputs } from "../src"; -import { PlumeVersion } from "../src/signals"; - -describe("signals", () => { - it("generates hash(m, pk)", () => { - expect(hashMPk.x.toString()).toEqual( - "bcac2d0e12679f23c218889395abcdc01f2affbc49c54d1136a2190db0800b65", - ); - expect(hashMPk.y.toString()).toEqual( - "3bcfb339c974c0e757d348081f90a123b0a91a53e32b3752145d87f0cd70966e", - ); - }); - - it("generates nullifier (hash(m, pk))^sk", () => { - expect(nullifier.x.toString(16)).toEqual( - "57bc3ed28172ef8adde4b9e0c2cce745fcc5a66473a45c1e626f1d0c67e55830", - ); - expect(nullifier.y.toString(16)).toEqual( - "6a2f41488d58f33ae46edd2188e111609f9f3ae67ea38fa891d6087fe59ecb73", - ); - }); - - describe("Plume V1", () => { - it("generates c and intermediate values correctly", () => { - expect(hashedToCurveR.x.toString(16)).toEqual( - "6d017c6f63c59fa7a5b1e9a654e27d2869579f4d152131db270558fccd27b97c", - ); - - expect(hashedToCurveR.y.toString(16)).toEqual( - "586c43fb5c99818c564a8f80a88a65f83e3f44d3c6caf5a1a4e290b777ac56ed", - ); - - expect(rPoint.x.toString(16)).toEqual( - "9d8ca4350e7e2ad27abc6d2a281365818076662962a28429590e2dc736fe9804", - ); - expect(rPoint.y.toString(16)).toEqual( - "ff08c30b8afd4e854623c835d9c3aac6bcebe45112472d9b9054816a7670c5a1", - ); - - expect(c_v1).toEqual( - "c6a7fc2c926ddbaf20731a479fb6566f2daa5514baae5223fe3b32edbce83254", - ); - }); - - it("generates an s signal", () => { - expect(s_v1).toEqual( - "e69f027d84cb6fe5f761e333d12e975fb190d163e8ea132d7de0bd6079ba28ca", - ); - }); - - it("generates all signals", () => { - const { plume, s, pk, c, rPoint, hashedToCurveR } = computeAllInputs( - testMessage, - testSecretKey, - testR, - PlumeVersion.V1, - ); - - expect(pk).toEqual(testPublicKey); - expect(rPoint.x.toString(16)).toEqual( - "9d8ca4350e7e2ad27abc6d2a281365818076662962a28429590e2dc736fe9804", - ); - expect(rPoint.y.toString(16)).toEqual( - "ff08c30b8afd4e854623c835d9c3aac6bcebe45112472d9b9054816a7670c5a1", - ); - expect(plume.x.toString(16)).toEqual( - "57bc3ed28172ef8adde4b9e0c2cce745fcc5a66473a45c1e626f1d0c67e55830", - ); - expect(plume.y.toString(16)).toEqual( - "6a2f41488d58f33ae46edd2188e111609f9f3ae67ea38fa891d6087fe59ecb73", - ); - expect(hashedToCurveR.x.toString(16)).toEqual( - "6d017c6f63c59fa7a5b1e9a654e27d2869579f4d152131db270558fccd27b97c", - ); - expect(c).toEqual( - "c6a7fc2c926ddbaf20731a479fb6566f2daa5514baae5223fe3b32edbce83254", - ); - expect(s).toEqual( - "e69f027d84cb6fe5f761e333d12e975fb190d163e8ea132d7de0bd6079ba28ca", - ); - expect(hashedToCurveR.y.toString(16)).toEqual( - "586c43fb5c99818c564a8f80a88a65f83e3f44d3c6caf5a1a4e290b777ac56ed", - ); - }); - }); - - describe("Plume V2", () => { - it("generates c and intermediate values correctly", () => { - expect(hashedToCurveR.x.toString(16)).toEqual( - "6d017c6f63c59fa7a5b1e9a654e27d2869579f4d152131db270558fccd27b97c", - ); - - expect(hashedToCurveR.y.toString(16)).toEqual( - "586c43fb5c99818c564a8f80a88a65f83e3f44d3c6caf5a1a4e290b777ac56ed", - ); - - expect(rPoint.x.toString(16)).toEqual( - "9d8ca4350e7e2ad27abc6d2a281365818076662962a28429590e2dc736fe9804", - ); - - expect(rPoint.y.toString(16)).toEqual( - "ff08c30b8afd4e854623c835d9c3aac6bcebe45112472d9b9054816a7670c5a1", - ); - - expect(c_v2).toEqual( - "3dbfb717705010d4f44a70720c95e74b475bd3a783ab0b9e8a6b3b363434eb96", - ); - }); - - it("generates an s signal", () => { - expect(s_v2).toEqual( - "528e8fbb6452f82200797b1a73b2947a92524bd611085a920f1177cb8098136b", - ); - }); - - it("generates all signals", () => { - const { plume, s, pk, c, rPoint, hashedToCurveR } = computeAllInputs( - testMessage, - testSecretKey, - testR, - PlumeVersion.V2, - ); - - expect(pk).toEqual(testPublicKey); - expect(rPoint.x.toString(16)).toEqual( - "9d8ca4350e7e2ad27abc6d2a281365818076662962a28429590e2dc736fe9804", - ); - expect(rPoint.y.toString(16)).toEqual( - "ff08c30b8afd4e854623c835d9c3aac6bcebe45112472d9b9054816a7670c5a1", - ); - expect(plume.x.toString(16)).toEqual( - "57bc3ed28172ef8adde4b9e0c2cce745fcc5a66473a45c1e626f1d0c67e55830", - ); - expect(plume.y.toString(16)).toEqual( - "6a2f41488d58f33ae46edd2188e111609f9f3ae67ea38fa891d6087fe59ecb73", - ); - expect(hashedToCurveR.x.toString(16)).toEqual( - "6d017c6f63c59fa7a5b1e9a654e27d2869579f4d152131db270558fccd27b97c", - ); - expect(c).toEqual( - "3dbfb717705010d4f44a70720c95e74b475bd3a783ab0b9e8a6b3b363434eb96", - ); - expect(s).toEqual( - "528e8fbb6452f82200797b1a73b2947a92524bd611085a920f1177cb8098136b", - ); - expect(hashedToCurveR.y.toString(16)).toEqual( - "586c43fb5c99818c564a8f80a88a65f83e3f44d3c6caf5a1a4e290b777ac56ed", - ); - }); - }); -}); diff --git a/javascript/tsconfig.build.json b/javascript/tsconfig.build.json deleted file mode 100644 index 60a5925..0000000 --- a/javascript/tsconfig.build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["src"], - "exclude": ["test/**/*.test.ts"] -} diff --git a/javascript/tsconfig.json b/javascript/tsconfig.json deleted file mode 100644 index 9fd84ab..0000000 --- a/javascript/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "es2021", - "allowJs": true, - "declaration": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "baseUrl": ".", - "noFallthroughCasesInSwitch": true, - "typeRoots": ["./node_modules/@types"], - "outDir": "./dist" - }, - "compileOnSave": true, - "include": ["src", "test"] -} From e011081e707ef01fbf8729cb9870f9ba522c73f5 Mon Sep 17 00:00:00 2001 From: skaunov Date: Sun, 7 Jul 2024 15:32:00 +0300 Subject: [PATCH 2/6] Logic finished # Subtle I was really late to understand that Subtle crypto supports the different curve `secp256r`, *and* it doesn't provide a facility to store secret values. So implementation for `web_sys::SecretKey` turned out to be just extra miles leading nowhere. ```toml web-sys = { version = "0.3", features = ["CryptoKey", "SubtleCrypto", "Crypto", "EcKeyImportParams"] } wasm-bindgen-futures = "0.4" ``` ```rust #[wasm_bindgen] extern "C" { // Return type of js_sys::global() type Global; // // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/) // type WebCrypto; // Getters for the WebCrypto API #[wasm_bindgen(method, getter)] fn crypto(this: &Global) -> web_sys::Crypto; } // `fn sign` if sk.type_() != "secret" {return Err(JsError::new("`sk` must be secret key"))} if !js_sys::Object::values(&sk.algorithm().map_err( |er| JsError::new(er.as_string().expect("TODO check this failing").as_str()) )?).includes(&JsValue::from_str("P-256"), 0) {return Err(JsError::new("`sk` must be from `secp256`"))} // this was my approach, but seems I got what they did at // js_sys::global().entries().find(); // TODO throw if no Crypto in global let global_the: Global = js_sys::global().unchecked_into(); let crypto_the: web_sys::Crypto = global_the.crypto(); let subtle_the = crypto_the.subtle(); let sk = JsFuture::from(subtle_the.export_key("pkcs8", &sk)?).await?; // ... ::from_pkcs8_der(js_sys::ArrayBuffer::from(sk).try_into()?)?; zeroize::Zeroizing::new(js_sys::Uint8Array::from(JsFuture::from(subtle_the.export_key("pkcs8", &sk).map_err( |er| Err(JsError::new(er.as_string().expect("TODO check this failing").as_str())) )?).await?).to_vec()); // ... // `fn try_into` // ... // zeroization protection ommitted here due to deprecation // // mostly boilerplate from signing; also some excessive ops left for the same reason // TODO align error-handling in this part if self.c.type_() != "secret" {return Err(JsError::new("`c` must be secret key"))} if !js_sys::Object::values(&self.c.algorithm()?).includes(js_sys::JsString::from("P-256").into(), 0) {return Err(JsError::new("`c` must be from `secp256`"))} this was my approach, but seems I got what they did at js_sys::global().entries().find(); // TODO throw if no Crypto in global let global_the: Global = js_sys::global().unchecked_into(); let crypto_the: web_sys::Crypto = global_the.crypto(); let subtle_the = crypto_the.subtle(); let c_pkcs = //zeroize::Zeroizing::new( js_sys::Uint8Array::from(JsFuture::from(subtle_the.export_key("pkcs8", &self.c)?).await?).to_vec(); // ); let c_scalar = &plume_rustcrypto::SecretKey::from_pkcs8_der(&c_pkcs)?.to_nonzero_scalar(); sk_z.zeroize(); // ... ``` # randomness Somehow I thought Wasm doesn't have access to RNG, so I used a seedable one and required the seed. Here's how `sign` `fn` was different. ```rust // Wasm environment doesn't have a suitable way to get randomness for the signing process, so this instantiates ChaCha20 RNG with the provided seed. // @throws a "crypto error" in case of a problem with the secret key, and a verbal error on a problem with `seed` // @param {Uint8Array} seed - must be exactly 32 bytes. pub fn sign(seed: &mut [u8], v1: bool, sk: &mut [u8], msg: &[u8]) -> Result { // ... let seed_z: zeroize::Zeroizing<[u8; 32]> = zeroize::Zeroizing::new(seed.try_into()?); seed.zeroize(); // TODO switch to `wasi-random` when that will be ready for crypto let sig = match v1 { true => plume_rustcrypto::PlumeSignature::sign_v1( &sk_z, msg, &mut rand_chacha::ChaCha20Rng::from_seed(seed_z) ), false => plume_rustcrypto::PlumeSignature::sign_v2( &sk_z, msg, &mut rand_chacha::ChaCha20Rng::from_seed(seed_z) ), }; let sig = signer.sign_with_rng( &mut rand_chacha::ChaCha20Rng::from_seed(*seed_z), msg ); // ... } ``` # `BigInt` conversion It was appealing to leave `s` as `BigInt` (see the comments), but that seems to be confusing and hinder downstream code reusage. There's an util function left for anybody who would want to have it as `BigInt`, but leaving the contraty function makes less sense and also makes the thing larger. So let me left it here for reference. ```rust let scalar_from_bigint = |n: js_sys::BigInt| -> Result { let result = plume_rustcrypto::NonZeroScalar::from_repr(k256::FieldBytes::from_slice( hex::decode({ let hexstring_freelen = n.to_string(16).map_err( |er| anyhow::Error::msg(er.as_string().expect("`RangeError` can be printed out")) )?.as_string().expect("on `JsString` this always produce a `String`"); let l = hexstring_freelen.len(); if l > 32*2 {return Err(anyhow::Error::msg("too many digits"))} else {["0".repeat(64-l), hexstring_freelen].concat()} })?.as_slice() ).to_owned()); if result.is_none().into() {Err(anyhow::Error::msg("isn't valid `secp256` non-zero scalar"))} else {Ok(result.expect(EXPECT_NONEALREADYCHECKED))} }; ``` --- Cargo.toml | 2 +- javascript/Cargo.toml | 30 ++-- javascript/src/lib.rs | 309 ++++++++++++---------------------------- javascript/src/utils.rs | 10 -- 4 files changed, 103 insertions(+), 248 deletions(-) delete mode 100644 javascript/src/utils.rs diff --git a/Cargo.toml b/Cargo.toml index 7197ef6..97028a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] resolver = "2" -members = ["rust-arkworks", "rust-k256"] +members = ["rust-arkworks", "rust-k256", "javascript"] [patch.crates-io] ark-ec = { git = "https://github.com/FindoraNetwork/ark-algebra" } diff --git a/javascript/Cargo.toml b/javascript/Cargo.toml index 0de3ce6..81c345f 100644 --- a/javascript/Cargo.toml +++ b/javascript/Cargo.toml @@ -10,38 +10,30 @@ repository = "https://github.com/plume-sig/zk-nullifier-sig/" crate-type = ["cdylib", "rlib"] [features] -default = ["console_error_panic_hook"] +# I'd alias this to `sec1` if that won't be trickyt +verify = ["dep:sec1"] [dependencies] wasm-bindgen = "~0.2.84" - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. -console_error_panic_hook = { version = "0.1.7", optional = true } - js-sys = "0.3" -plume_rustcrypto = "0.2" # TODO change to -rand_chacha = "0.3" -sec1 = "0.7.3" # match with `k256` -elliptic-curve = {version = "0.13.8", features = ["sec1"]} # match with `k256` -hex = "0.4" -k256 = "~0.13.3" # match with `k256` +plume_rustcrypto = {version = "~0.2.1", default-features = false} +# rand_chacha = "0.3" +sec1 = {version = "0.7.3", optional = true} # match with `k256` +# elliptic-curve = {version = "0.13.8", features = ["sec1"]} # match with `k256` +elliptic-curve = {version = "0.13.8"} +# hex = "0.4" +# k256 = "~0.13.3" # match with `k256` zeroize = "1.8" signature = "^2.2.0" getrandom = { version = "0.2", features = ["js"] } # getrandom_or_panic = "0.0.3" -rand = {version = "0.8"} +# rand = {version = "0.8"} anyhow = "1" -web-sys = { version = "0.3", features = ["CryptoKey", "SubtleCrypto", "Crypto", "EcKeyImportParams"] } -wasm-bindgen-futures = "0.4" - [dev-dependencies] wasm-bindgen-test = "~0.3.34" -[profile.release] +[profile.release] # This comes from template; didn't touch this yet - docs doesn't tell much about it. # Tell `rustc` to optimize for small code size. # opt-level = "s" diff --git a/javascript/src/lib.rs b/javascript/src/lib.rs index 63f4fa7..906a698 100644 --- a/javascript/src/lib.rs +++ b/javascript/src/lib.rs @@ -1,40 +1,33 @@ -//! Will this add module JSdoc? -// TODO add interop testing for JSON +//! TODO is it possible to add top-level? // TODO should I do examples rustdoc style or javadoc? /* I want to have a look at good and *small* example for... * JS tests and CI -* documenting -* setters/getters/exporting, general tricks, API, constructors */ +* documenting */ -mod utils; // TODO I guess this one isn't panicing, +use std::convert::TryFrom; +#[cfg(feature = "verify")] +use std::convert::TryInto; -// use std::convert::{TryFrom, TryInto}; - -use k256::pkcs8::DecodePrivateKey; -use k256::SecretKey; -use plume_rustcrypto::AffinePoint; use wasm_bindgen::prelude::*; +#[cfg(feature = "verify")] use elliptic_curve::sec1::FromEncodedPoint; use zeroize::Zeroize; -use elliptic_curve::rand_core::SeedableRng; use elliptic_curve::sec1::ToEncodedPoint; use signature::RandomizedSigner; -use wasm_bindgen_futures::JsFuture; - #[wasm_bindgen(getter_with_clone)] /// @typedef {Object} PlumeSignature - Wrapper around [`plume_rustcrypto::PlumeSignature`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/struct.PlumeSignature.html). /// [`plume_rustcrypto::AffinePoint`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/struct.AffinePoint.html) is represented as a `Uint8Array` containing SEC1 encoded point. -/// [`plume_rustcrypto::NonZeroScalar`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/type.NonZeroScalar.html) is represented as a `BigInt`. +/// [`plume_rustcrypto::NonZeroScalar`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/type.NonZeroScalar.html) is represented as a `Uint8Array` containing SEC1 DER secret key. /// `Option` can be `undefined` or instance of [`PlumeSignatureV1Fields`]. pub struct PlumeSignature { pub message: Vec, - pub pk: Vec, // TODO protect with public `web_sys::CryptoKey` + pub pk: Vec, pub nullifier: Vec, - pub c: web_sys::CryptoKey, - pub s: js_sys::BigInt, // it's overprotected in the crate, no need for `CryptoKey` here + pub c: Vec, + pub s: Vec, pub v1specific: Option, } @@ -55,25 +48,26 @@ impl PlumeSignatureV1Fields { #[wasm_bindgen] impl PlumeSignature { - // #[wasm_bindgen(setter)] - // pub fn set_message(&mut self, field: Vec) { - // self.message = field; - // } - + #[cfg(feature = "verify")] + /// @deprecated Use this only for testing purposes. + /// @throws an error if the data in the object doesn't let it to properly run verification; message contains nature of the problem and indicates relevant property of the object. In case of other (crypto) problems returns `false`. + pub fn verify(self) -> Result {Ok(plume_rustcrypto::PlumeSignature::verify(&self.try_into()?))} + + /// there's no case for constructing it from values, so this only used internally and for testing /// `v1specific` discriminates if it's V1 or V2 scheme used. Pls, see wrapped docs for details. #[wasm_bindgen(constructor)] pub fn new( message: Vec, pk: Vec, nullifier: Vec, - c: web_sys::CryptoKey, - s: js_sys::BigInt, + c: Vec, + s: Vec, v1specific: Option ) -> PlumeSignature { PlumeSignature { /* I really wonder how good is this pattern. But taking so much of args isn't good, and builder pattern seems redundant as all of the fields are required, and setters are just assignments. */ - // TODO solve/test v1 field: start with adding its constructor + // Actually there's no case for constructing it from values, so this only used internally and for testing. message, pk, nullifier, c, s, v1specific//: if v1specific.is_falsy() {None} else {Some(v1specific)} } @@ -81,6 +75,12 @@ impl PlumeSignature { // js_sys::Object::from_entries(&values)? // values.get } + + /// Depending on your context you may want to zeroize from Wasm memory private parts of the result after getting the values. + pub fn zeroize_privateparts(&mut self) { + self.c.zeroize(); + self.pk.zeroize(); + } } #[wasm_bindgen(skip_jsdoc)] @@ -89,204 +89,77 @@ impl PlumeSignature { /// @param {Uint8Array} sk - must be exactly 32 bytes, and strictly represent a non-zero scalar of `secp256` in big-endian. /// @param {Uint8Array} msg /// @returns {PlumeSignature} -// Wasm environment doesn't have a suitable way to get randomness for the signing process, so this instantiates ChaCha20 RNG with the provided seed. -// @throws a "crypto error" in case of a problem with the secret key, and a verbal error on a problem with `seed` -// @param {Uint8Array} seed - must be exactly 32 bytes. -// pub fn sign(seed: &mut [u8], v1: bool, sk: &mut [u8], msg: &[u8]) -> Result { -pub async fn sign(v1: bool, sk: web_sys::CryptoKey, msg: &[u8]) -> Result { - if sk.type_() != "secret" {return Err(JsError::new("`sk` must be secret key"))} - if !js_sys::Object::values(&sk.algorithm().map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?).includes(&JsValue::from_str("P-256"), 0) {return Err(JsError::new("`sk` must be from `secp256`"))} - - // this was my approach, but seems I got what they did at - // js_sys::global().entries().find(); // TODO throw if no Crypto in global +pub fn sign(v1: bool, sk: &mut [u8], msg: &[u8]) -> Result { + let sk_z = + plume_rustcrypto::SecretKey + ::from(plume_rustcrypto::NonZeroScalar::try_from(sk.as_ref())?); + sk.zeroize(); + let signer = plume_rustcrypto::randomizedsigner::PlumeSigner::new(&sk_z, v1); - let global_the: Global = js_sys::global().unchecked_into(); // is it not `dyn_into` here for speed? https://github.com/rust-random/getrandom/commit/120a1d7f4796356a1f60cd84bd7a0ceafbac9d0e#commitcomment-143690574 - let crypto_the: web_sys::Crypto = global_the.crypto(); - let subtle_the = crypto_the.subtle(); - // let sk = JsFuture::from(subtle_the.export_key("pkcs8", &sk)?).await?; + Ok(signer.sign_with_rng( + &mut signature::rand_core::OsRng, + msg + ).into()) +} - let mut sk_z = - // plume_rustcrypto::SecretKey - // ::from(plume_rustcrypto::NonZeroScalar::try_from(sk.as_ref())?); - // ::from_pkcs8_der(js_sys::ArrayBuffer::from(sk).try_into()?)?; - zeroize::Zeroizing::new(js_sys::Uint8Array::from(JsFuture::from(subtle_the.export_key("pkcs8", &sk).map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?).await.map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?).to_vec()); - let sk = plume_rustcrypto::SecretKey::from_pkcs8_der(sk_z.as_ref())?; - sk_z.zeroize(); - let signer = plume_rustcrypto::randomizedsigner::PlumeSigner::new(&sk, v1); - // let seed_z: zeroize::Zeroizing<[u8; 32]> = zeroize::Zeroizing::new(seed.try_into()?); - // // TODO protect `seed` with ~~zeroization~~ and so on - // seed.zeroize(); +// TODO deprecate when `verify` gone +#[cfg(feature = "verify")] +impl TryInto for PlumeSignature { + type Error = JsError; - // TODO switch to `wasi-random` when that will be ready for crypto - // let sig = match v1 { - // true => plume_rustcrypto::PlumeSignature::sign_v1( - // &sk_z, msg, &mut rand_chacha::ChaCha20Rng::from_seed(seed_z) - // ), - // false => plume_rustcrypto::PlumeSignature::sign_v2( - // &sk_z, msg, &mut rand_chacha::ChaCha20Rng::from_seed(seed_z) - // ), - // }; + fn try_into(self) -> Result { + let point_check = |point_bytes: Vec| -> Result { + let point_encoded = sec1::point::EncodedPoint::from_bytes(point_bytes)?; // TODO improve formatting (quotes e.g.) + let result = plume_rustcrypto::AffinePoint::from_encoded_point(&point_encoded); + if result.is_none().into() {Err(anyhow::Error::msg("the point isn't on the curve"))} + else {Ok(result.expect("`None` is processed the line above"))} + }; - /* current implementation does bad job protecting few parts meant to be private, see - I feel it doesn't make sense to try mitigating that in the wrapper, but just to update this when the issue is solved */ - let sig_the = signer.sign_with_rng( - // &mut rand_chacha::ChaCha20Rng::from_seed(*seed_z), - &mut rand::rngs::OsRng, - msg - ); - // I had the trait for this, but due to `async` it seems more natural to just move that code here. - // impl From for PlumeSignature { - // fn from(value: plume_rustcrypto::PlumeSignature) -> Self { - let nonzeroscalartobigint = |v: plume_rustcrypto::NonZeroScalar| -> js_sys::BigInt { - js_sys::BigInt::new(&JsValue::from_str(("0x".to_owned() + v.to_string().as_str()).as_str())).expect("`BigInt` always can be created from hex string, and `v.to_string()` always produce that") - }; - - Ok(PlumeSignature { - message: msg.to_vec(), - pk: sig_the.pk.to_encoded_point(true).as_bytes().to_vec(), - nullifier: sig_the.nullifier.to_encoded_point(true).as_bytes().to_vec(), - c: JsFuture::from(subtle_the.import_key_with_object( - "pkcs8", - js_sys::Uint8Array::from(SecretKey::from(sig_the.c).to_sec1_der()?.as_ref()).as_ref(), - web_sys::EcKeyImportParams::new("ECDSA").named_curve("P-256"), - true, - js_sys::Array::new().as_ref(), // I can't see a valid usage for this among - ).map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?).await.map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?.dyn_into().map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?, - s: nonzeroscalartobigint(sig_the.s), - v1specific: if let Some(v1) = sig_the.v1specific {Some( - PlumeSignatureV1Fields { - r_point: v1.r_point.to_encoded_point(true).as_bytes().to_vec(), - hashed_to_curve_r: v1.hashed_to_curve_r.to_encoded_point(true).as_bytes().to_vec(), - } - )} else {None}, - }) - // } - // } - - // let debugging = signer.sign_with_rng( - // &mut rand_chacha::ChaCha20Rng::from_seed(*seed_z), msg - // ); - // js_sys::BigInt::new(&JsValue::from_str(("0x".to_owned() + debugging.c.to_string().as_str()).as_str())).expect("`BigInt` always can be created from decimal string, and `c.to_string()` always produce that"); - // // Err(JsError::new(debugging.c.to_string().as_str())) - // Ok( - // PlumeSignature{ message: Default::default(), pk: Default::default(), nullifier: Default::default(), c: Default::default(), s: Default::default(), v1specific: Default::default() } - // ) + let err_field_wrap = |name_field: &str, er: anyhow::Error| -> JsError {JsError::new( + ("while proccessing ".to_owned() + name_field + " :" + er.to_string().as_str()).as_str() + )}; + + Ok(plume_rustcrypto::PlumeSignature{ + message: self.message, + pk: point_check(self.pk).map_err(|er| err_field_wrap("`pk`", er))?, + // plume_rustcrypto::AffinePoint::try_from(self.pk)?, //.try_into<[u8; 33]>()?.into(), + nullifier: point_check(self.nullifier).map_err(|er| err_field_wrap("`nullifier`", er))?, + c: plume_rustcrypto::SecretKey::from_sec1_der(&self.c)?.into(), + s: plume_rustcrypto::SecretKey::from_sec1_der(&self.s)?.into(),//scalar_from_bigint(self.s).map_err(|er| err_field_wrap("`s`", er))?, + v1specific: if let Some(v1) = self.v1specific {Some( + plume_rustcrypto::PlumeSignatureV1Fields{ + r_point: point_check(v1.r_point).map_err(|er| err_field_wrap("`r_point`", er))?, + hashed_to_curve_r: point_check(v1.hashed_to_curve_r).map_err(|er| err_field_wrap("`hashed_to_curve_r`", er))?, + } + )} else {None}, + }) + } } -#[wasm_bindgen] -extern "C" { - // Return type of js_sys::global() - type Global; - // // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/) - // type WebCrypto; - // Getters for the WebCrypto API - #[wasm_bindgen(method, getter)] - fn crypto(this: &Global) -> web_sys::Crypto; + +impl From for PlumeSignature { + fn from(value: plume_rustcrypto::PlumeSignature) -> Self { + PlumeSignature { + message: value.message, + pk: value.pk.to_encoded_point(true).as_bytes().to_vec(), + nullifier: value.nullifier.to_encoded_point(true).as_bytes().to_vec(), + c: plume_rustcrypto::SecretKey::from(value.c).to_sec1_der().expect("`k256` restricts this type to proper keys, so it's serialized representation shouldn't have a chance to fail") + .to_vec(), + s: plume_rustcrypto::SecretKey::from(value.s).to_sec1_der().expect("`k256` restricts this type to proper keys, so it's serialized representation shouldn't have a chance to fail") + .to_vec(), + v1specific: value.v1specific.map(|v1| {PlumeSignatureV1Fields { + r_point: v1.r_point.to_encoded_point(true).as_bytes().to_vec(), + hashed_to_curve_r: v1.hashed_to_curve_r.to_encoded_point(true).as_bytes().to_vec(), + }}) + } + } } -// this was a `PlumeSignature` method, but thanks to `async` it been moved to standalone -/// @deprecated Use this only for testing purposes. -/// @throws a error if the data in the object doesn't let it to properly run verification; message contains nature of the problem and indicates relevant property of the object. In case of other (crypto) problems returns `false`. -#[wasm_bindgen] -pub async fn verify(self_: PlumeSignature) -> Result { - // #async #traits - // impl TryInto for PlumeSignature { - // type Error = JsError; - - // fn try_into(self) -> Result { - // if let Some(v1) = self.v1specific {Some( - // plume_rustcrypto::PlumeSignatureV1Fields{ - // r_point: v1.r_point.try_into()?, - // hashed_to_curve_r: v1.hashed_to_curve_r.try_into()?, - // } - // )} - - // let mut points = [self.pk, self.nullifier]; //, self.v1specific); - // if Some(points_v1) = self.v1specific {po} - - let point_check = |/* name_field: &str, */ point_bytes: Vec| -> Result { - let point_encoded = sec1::point::EncodedPoint::from_bytes(point_bytes)?; // TODO improve formatting (quotes e.g.) - let result = plume_rustcrypto::AffinePoint::from_encoded_point(&point_encoded); - if result.is_none().into() {Err(anyhow::Error::msg("the point isn't on the curve"))} - else {Ok(result.expect(EXPECT_NONEALREADYCHECKED))} - }; - - // plume_rustcrypto::Scalar::try_from(self.c.to_string(16)?.as_string()?); - // k256::Scalar::from_repr(hex::decode(self.c.to_string(16)?.as_ref())?); // TODO test endianness here and correctness - let scalar_from_bigint = - |/* name_field: &str, */ n: js_sys::BigInt| -> Result { - let result = plume_rustcrypto::NonZeroScalar::from_repr(k256::FieldBytes::from_slice( - hex::decode({ - let hexstring_freelen = n.to_string(16).map_err( - |er| - anyhow::Error::msg(er.as_string().expect("`RangeError` can be printed out")) - )?.as_string().expect("on `JsString` this always produce a `String`"); - let l = hexstring_freelen.len(); - if l > 32*2 {return Err(anyhow::Error::msg("too many digits"))} - else {["0".repeat(64-l), hexstring_freelen].concat()} - })?.as_slice() - ).to_owned()); - if result.is_none().into() {Err(anyhow::Error::msg("isn't valid `secp256` non-zero scalar"))} - else {Ok(result.expect(EXPECT_NONEALREADYCHECKED))} - }; - const EXPECT_NONEALREADYCHECKED: &'static str = "`None` is processed the line above"; - - let err_field_wrap = |name_field: &str, er: anyhow::Error| -> JsError {JsError::new( - ("while proccessing ".to_owned() + name_field + " :" + er.to_string().as_str()).as_str() - /* "while proccessing ".to_owned().join(), - name_field, - " :", - er.to_string().as_str() - ].concat()) */)}; - - // zeroization protection ommitted here due to deprecation // - // mostly boilerplate from signing; also some excessive ops left for the same reason - // TODO align error-handling in this part - if self_.c.type_() != "secret" {return Err(JsError::new("`c` must be secret key"))} - if !js_sys::Object::values(&self_.c.algorithm().map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?).includes(&JsValue::from_str("P-256"), 0) {return Err(JsError::new("`c` must be from `secp256`"))} - // TODO finish - // this was my approach, but seems I got what they did at - // js_sys::global().entries().find(); // TODO throw if no Crypto in global - let global_the: Global = js_sys::global().unchecked_into(); - let crypto_the: web_sys::Crypto = global_the.crypto(); - let subtle_the = crypto_the.subtle(); - let c_pkcs = //zeroize::Zeroizing::new( - js_sys::Uint8Array::from(JsFuture::from(subtle_the.export_key("pkcs8", &self_.c).map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?).await.map_err( - |er| JsError::new(er.as_string().expect("TODO check how this is failing").as_str()) - )?).to_vec(); - // ); - let c_scalar = &plume_rustcrypto::SecretKey::from_pkcs8_der(&c_pkcs)?.to_nonzero_scalar(); - // sk_z.zeroize(); - - Ok(plume_rustcrypto::PlumeSignature{ - message: self_.message, - pk: point_check(self_.pk).map_err(|er| err_field_wrap("`pk`", er))?, - // plume_rustcrypto::AffinePoint::try_from(self.pk)?, //.try_into<[u8; 33]>()?.into(), - nullifier: point_check(self_.nullifier).map_err(|er| err_field_wrap("`nullifier`", er))?, - c: *c_scalar, - s: scalar_from_bigint(self_.s).map_err(|er| err_field_wrap("`s`", er))?, - v1specific: if let Some(v1) = self_.v1specific {Some( - plume_rustcrypto::PlumeSignatureV1Fields{ - r_point: point_check(v1.r_point).map_err(|er| err_field_wrap("`r_point`", er))?, - hashed_to_curve_r: point_check(v1.hashed_to_curve_r).map_err(|er| err_field_wrap("`hashed_to_curve_r`", er))?, - } - )} else {None}, - }.verify()) - // } - // } +#[wasm_bindgen(js_name = sec1DerScalarToBigint)] +/// This might leave values in memory! Don't use for private values. +/// JS most native format for scalar is `BigInt`, but it's not really transportable or secure, so for uniformity of approach `s` in `PlumeSignature` is defined similar to `c`; +/// but if you want to have it as a `BigInt` this util is left here. +pub fn sec1derscalar_to_bigint(scalar: &[u8]) -> Result { + Ok(js_sys::BigInt::new(&JsValue::from_str(( + "0x".to_owned() + plume_rustcrypto::SecretKey::from_sec1_der(scalar)?.to_nonzero_scalar().to_string().as_str() + ).as_str())).expect("`BigInt` always can be created from hex string, and `v.to_string()` always produce that")) } \ No newline at end of file diff --git a/javascript/src/utils.rs b/javascript/src/utils.rs deleted file mode 100644 index b1d7929..0000000 --- a/javascript/src/utils.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub fn set_panic_hook() { - // When the `console_error_panic_hook` feature is enabled, we can call the - // `set_panic_hook` function at least once during initialization, and then - // we will get better error messages if our code ever panics. - // - // For more details see - // https://github.com/rustwasm/console_error_panic_hook#readme - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); -} From 533bf8423307e11d79544e1ca06070d1981d3cf7 Mon Sep 17 00:00:00 2001 From: skaunov Date: Mon, 8 Jul 2024 23:52:55 +0300 Subject: [PATCH 3/6] feels like the thing is finished will give it a look like tomorrow I should check that `rc` makes it opt-in and publish to NPM --- javascript/Cargo.toml | 10 +--- javascript/README.md | 117 ++++++++++++++++++------------------------ javascript/src/lib.rs | 33 +++++++----- 3 files changed, 71 insertions(+), 89 deletions(-) diff --git a/javascript/Cargo.toml b/javascript/Cargo.toml index 81c345f..4ac44f9 100644 --- a/javascript/Cargo.toml +++ b/javascript/Cargo.toml @@ -18,17 +18,11 @@ wasm-bindgen = "~0.2.84" js-sys = "0.3" plume_rustcrypto = {version = "~0.2.1", default-features = false} -# rand_chacha = "0.3" -sec1 = {version = "0.7.3", optional = true} # match with `k256` -# elliptic-curve = {version = "0.13.8", features = ["sec1"]} # match with `k256` -elliptic-curve = {version = "0.13.8"} -# hex = "0.4" -# k256 = "~0.13.3" # match with `k256` +sec1 = {version = "~0.7.3", optional = true} # match with `k256` +elliptic-curve = {version = "~0.13.8"} zeroize = "1.8" signature = "^2.2.0" getrandom = { version = "0.2", features = ["js"] } -# getrandom_or_panic = "0.0.3" -# rand = {version = "0.8"} anyhow = "1" [dev-dependencies] diff --git a/javascript/README.md b/javascript/README.md index 6b68408..9e2f5c4 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -1,84 +1,67 @@ -
+This is wrapper around `plume_rustcrypto` crate to produce PLUME signatures in JS contexts using Wasm. -

wasm-pack-template

+TODO add here couple of examples from systems which uses this. - A template for kick starting a Rust and WebAssembly project using wasm-pack. +# Getting Started -

- Build Status -

- -

- Tutorial - | - Chat -

- - Built with 🦀🕸 by The Rust and WebAssembly Working Group -
- -## About - -[**📚 Read this template tutorial! 📚**][template-docs] - -This template is designed for compiling Rust libraries into WebAssembly and -publishing the resulting package to NPM. - -Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other -templates and usages of `wasm-pack`. - -[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html -[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html - -## 🚴 Usage - -### 🐑 Use `cargo generate` to Clone this Template - -[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate) +Get the package from NPM. The repository contains Rust code for generating Wasm and packaging it. -``` -cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project -cd my-project +The package usage outline; see the details in subsections. +```js +// ... +let result = plume.sign(true, secretKeySec1Der, msg); +console.log(result.nullifier); +result.zeroizePrivateParts(); ``` -### 🛠️ Build with `wasm-pack build` +Please, refer to the JS-doc for types description, function signatures, and exceptions notes. -``` -wasm-pack build -``` - -### 🔬 Test in Headless Browsers with `wasm-pack test` +Values in the following examples are in line with tests in the wrapped crate. +## producing the signature +```js +import * as plume from "TODO"; +let result = plume.sign( + false, + new Uint8Array([48, 107, 2, 1, 1, 4, 32, 81, 155, 66, 61, 113, 95, 139, 88, 31, 79, 168, 238, 89, 244, 119, 26, 91, 68, 200, 19, 11, 78, 62, 172, 202, 84, 165, 109, 218, 114, 180, 100, 161, 68, 3, 66, 0, 4, 12, 236, 2, 142, 224, 141, 9, 224, 38, 114, 166, 131, 16, 129, 67, 84, 249, 234, 191, 255, 13, 230, 218, 204, 28, 211, 167, 116, 73, 96, 118, 174, 239, 244, 113, 251, 160, 64, 152, 151, 182, 164, 142, 136, 1, 173, 18, 249, 93, 0, 9, 183, 83, 207, 143, 81, 193, 40, 191, 107, 11, 210, 127, 189]), + new Uint8Array([ + 65, 110, 32, 101, 120, 97, 109, 112, 108, 101, 32, 97, 112, 112, 32, 109, 101, 115, 115, 97, 103, 101, 32, 115, 116, 114, 105, 110, 103 + ]) +); ``` -wasm-pack test --headless --firefox +## getters +`PlumeSignature` provide getters for each property of it, so you have access to any of them upon signing. +```js +// ... +console.log(result.nullifier); +console.log(result.s); +console.log(result.c); +console.log(result.pk); +console.log(result.message); ``` - -### 🎁 Publish to NPM with `wasm-pack publish` - +Note that variant is specified by `v1specific`; if it's `undefined` then the object contains V2, otherwise it's V1. +```js +// ... +console.log(result.v1specific.r_point); +console.log(result.v1specific.hashed_to_curve_r); ``` -wasm-pack publish +Also there's #convertion utility provided. +## zeroization +Depending on your context you might want to clear values of the result from Wasm memory after getting the values. +```js +// ... +result.zeroizePrivateParts(); +result.zeroizeAll(); ``` -## 🔋 Batteries Included - -* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating - between WebAssembly and JavaScript. -* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) - for logging panic messages to the developer console. -* `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you - -## License - -Licensed under either of +# #convertion of `s` to `BigInt` +JS most native format for scalar is `BigInt`, but it's not really transportable or secure, so for uniformity of approach `s` in `PlumeSignature` is defined similar to `c`; but if you want to have it as a `BigInt` there's `sec1DerScalarToBigint` helper funtion. -* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) -* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +# Working with source files -at your option. +This package is built with the tech provided by which contains everything needed to work with it. Also the wrapper crate was initiated with `wasm-pack-template`. -### Contribution +Note that the wrapper crate has `verify` feature which can check the resulting signature. -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. +# License +See . \ No newline at end of file diff --git a/javascript/src/lib.rs b/javascript/src/lib.rs index 906a698..f037c53 100644 --- a/javascript/src/lib.rs +++ b/javascript/src/lib.rs @@ -1,11 +1,5 @@ -//! TODO is it possible to add top-level? -// TODO should I do examples rustdoc style or javadoc? -/* -I want to have a look at good and *small* example for... -* JS tests and CI -* documenting */ - -use std::convert::TryFrom; +//! sadly `wasm-bindgen` doesn't support top-level @module docs yet + #[cfg(feature = "verify")] use std::convert::TryInto; @@ -76,23 +70,34 @@ impl PlumeSignature { // values.get } - /// Depending on your context you may want to zeroize from Wasm memory private parts of the result after getting the values. + #[wasm_bindgen(js_name = zeroizePrivateParts)] + /// Zeroize private values of the object from Wasm memory. pub fn zeroize_privateparts(&mut self) { self.c.zeroize(); self.pk.zeroize(); } + #[wasm_bindgen(js_name = zeroizeAll)] + /// Zeroize all values of the object from Wasm memory. + pub fn zeroize_all(&mut self) { + self.zeroize_privateparts(); + self.message.zeroize(); + self.nullifier.zeroize(); + self.s.zeroize(); + if let Some(v1) = self.v1specific.as_mut() { + v1.hashed_to_curve_r.zeroize(); + v1.r_point.zeroize(); + } + } } #[wasm_bindgen(skip_jsdoc)] /// @throws a "crypto error" in case of a problem with the secret key /// @param {boolean} v1 - is the flag to choose between V1 and V2 output. -/// @param {Uint8Array} sk - must be exactly 32 bytes, and strictly represent a non-zero scalar of `secp256` in big-endian. +/// @param {Uint8Array} sk - secret key in SEC1 DER format. /// @param {Uint8Array} msg /// @returns {PlumeSignature} pub fn sign(v1: bool, sk: &mut [u8], msg: &[u8]) -> Result { - let sk_z = - plume_rustcrypto::SecretKey - ::from(plume_rustcrypto::NonZeroScalar::try_from(sk.as_ref())?); + let sk_z = plume_rustcrypto::SecretKey::from_sec1_der(sk)?; sk.zeroize(); let signer = plume_rustcrypto::randomizedsigner::PlumeSigner::new(&sk_z, v1); @@ -136,7 +141,7 @@ impl TryInto for PlumeSignature { } } -impl From for PlumeSignature { +impl From for PlumeSignature { fn from(value: plume_rustcrypto::PlumeSignature) -> Self { PlumeSignature { message: value.message, From 6b18e3d069ee8e7dd55b3319d015dd67fbfaffa9 Mon Sep 17 00:00:00 2001 From: skaunov Date: Tue, 9 Jul 2024 23:42:16 +0300 Subject: [PATCH 4/6] remove GA this one should be tested like a package I guess, ideas for such tests are welcome as issues --- .github/workflows/javascript.yml | 41 -------------- javascript/Cargo.toml | 4 +- javascript/README.md | 31 +++++++++-- javascript/src/lib.rs | 93 ++++++++++++++++++++------------ 4 files changed, 90 insertions(+), 79 deletions(-) delete mode 100644 .github/workflows/javascript.yml diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml deleted file mode 100644 index fac4db9..0000000 --- a/.github/workflows/javascript.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Javascript checks -on: - workflow_dispatch: - - push: - branches: [main] - - pull_request: - branches: [main] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - checks: - strategy: - fail-fast: false - matrix: - node-version: [18] - command: ["prettier", "types", "test:coverage"] - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: pnpm/action-setup@v2 - with: - version: latest - - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - - name: Check javascript - run: | - pnpm install --no-frozen-lockfile --prefer-offline - pnpm run build - pnpm run ${{ matrix.command }} - working-directory: "./javascript" diff --git a/javascript/Cargo.toml b/javascript/Cargo.toml index 4ac44f9..b5e9040 100644 --- a/javascript/Cargo.toml +++ b/javascript/Cargo.toml @@ -5,12 +5,14 @@ authors = ["skaunov"] edition = "2018" keywords = ["nullifier", "zero-knowledge", "ECDSA", "PLUME"] repository = "https://github.com/plume-sig/zk-nullifier-sig/" +description = "wrapper around `plume_rustcrypto` crate to produce PLUME signatures in JS contexts using Wasm" +license = "MIT" [lib] crate-type = ["cdylib", "rlib"] [features] -# I'd alias this to `sec1` if that won't be trickyt +# I'd alias this to `sec1` if that won't be tricky verify = ["dep:sec1"] [dependencies] diff --git a/javascript/README.md b/javascript/README.md index 9e2f5c4..1c8ee1f 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -9,7 +9,7 @@ Get the package from NPM. The repository contains Rust code for generating Wasm The package usage outline; see the details in subsections. ```js // ... -let result = plume.sign(true, secretKeySec1Der, msg); +let result = plume.sign(isV1, secretKeySec1Der, msg); console.log(result.nullifier); result.zeroizePrivateParts(); ``` @@ -19,7 +19,7 @@ Please, refer to the JS-doc for types description, function signatures, and exce Values in the following examples are in line with tests in the wrapped crate. ## producing the signature ```js -import * as plume from "TODO"; +import * as plume from "plume-sig"; let result = plume.sign( false, @@ -34,16 +34,39 @@ let result = plume.sign( ```js // ... console.log(result.nullifier); +/* Uint8Array(33) [ + 3, 87, 188, 62, 210, 129, 114, 239, + 138, 221, 228, 185, 224, 194, 204, 231, + 69, 252, 197, 166, 100, 115, 164, 92, + 30, 98, 111, 29, 12, 103, 229, 88, + 48 +] */ console.log(result.s); +/* Uint8Array(109) [ + 48, 107, 2, 1, 1, 4, 32, 73, 27, 195, 183, 106, + 202, 136, 167, 50, 193, 119, 152, 153, 233, 56, 176, 58, + 221, 183, 4, 126, 189, 69, 201, 173, 102, 98, 248, 36, + 112, 183, 176, 161, 68, 3, 66, 0, 4, 13, 18, 115, + 220, 215, 120, 156, 20, 128, 225, 106, 29, 255, 16, 218, + 5, 19, 179, 80, 204, 25, 144, 61, 150, 121, 83, 76, + 174, 21, 232, 58, 153, 97, 227, 239, 78, 114, 199, 53, + 138, 93, 108, 150, 98, 141, 89, 159, 219, 243, 182, 188, + 22, 224, 154, 171, + ... 9 more items +] */ console.log(result.c); console.log(result.pk); console.log(result.message); +console.log(result.v1specific); +// undefined ``` Note that variant is specified by `v1specific`; if it's `undefined` then the object contains V2, otherwise it's V1. ```js // ... -console.log(result.v1specific.r_point); -console.log(result.v1specific.hashed_to_curve_r); +if (result.v1specific) { + console.log(result.v1specific.r_point); + console.log(result.v1specific.hashed_to_curve_r); +} ``` Also there's #convertion utility provided. ## zeroization diff --git a/javascript/src/lib.rs b/javascript/src/lib.rs index f037c53..5d0c76a 100644 --- a/javascript/src/lib.rs +++ b/javascript/src/lib.rs @@ -7,9 +7,9 @@ use wasm_bindgen::prelude::*; #[cfg(feature = "verify")] use elliptic_curve::sec1::FromEncodedPoint; -use zeroize::Zeroize; use elliptic_curve::sec1::ToEncodedPoint; use signature::RandomizedSigner; +use zeroize::Zeroize; #[wasm_bindgen(getter_with_clone)] /// @typedef {Object} PlumeSignature - Wrapper around [`plume_rustcrypto::PlumeSignature`](https://docs.rs/plume_rustcrypto/latest/plume_rustcrypto/struct.PlumeSignature.html). @@ -18,10 +18,10 @@ use signature::RandomizedSigner; /// `Option` can be `undefined` or instance of [`PlumeSignatureV1Fields`]. pub struct PlumeSignature { pub message: Vec, - pub pk: Vec, + pub pk: Vec, pub nullifier: Vec, - pub c: Vec, - pub s: Vec, + pub c: Vec, + pub s: Vec, pub v1specific: Option, } @@ -36,7 +36,10 @@ pub struct PlumeSignatureV1Fields { impl PlumeSignatureV1Fields { #[wasm_bindgen(constructor)] pub fn new(r_point: Vec, hashed_to_curve_r: Vec) -> PlumeSignatureV1Fields { - PlumeSignatureV1Fields { r_point, hashed_to_curve_r } + PlumeSignatureV1Fields { + r_point, + hashed_to_curve_r, + } } } @@ -45,7 +48,9 @@ impl PlumeSignature { #[cfg(feature = "verify")] /// @deprecated Use this only for testing purposes. /// @throws an error if the data in the object doesn't let it to properly run verification; message contains nature of the problem and indicates relevant property of the object. In case of other (crypto) problems returns `false`. - pub fn verify(self) -> Result {Ok(plume_rustcrypto::PlumeSignature::verify(&self.try_into()?))} + pub fn verify(self) -> Result { + Ok(plume_rustcrypto::PlumeSignature::verify(&self.try_into()?)) + } /// there's no case for constructing it from values, so this only used internally and for testing /// `v1specific` discriminates if it's V1 or V2 scheme used. Pls, see wrapped docs for details. @@ -56,14 +61,18 @@ impl PlumeSignature { nullifier: Vec, c: Vec, s: Vec, - v1specific: Option + v1specific: Option, ) -> PlumeSignature { PlumeSignature { - /* I really wonder how good is this pattern. But taking so much of args isn't good, and builder pattern seems redundant as all + /* I really wonder how good is this pattern. But taking so much of args isn't good, and builder pattern seems redundant as all of the fields are required, and setters are just assignments. */ // Actually there's no case for constructing it from values, so this only used internally and for testing. - message, pk, nullifier, c, s, - v1specific//: if v1specific.is_falsy() {None} else {Some(v1specific)} + message, + pk, + nullifier, + c, + s, + v1specific, //: if v1specific.is_falsy() {None} else {Some(v1specific)} } // js_sys::Object::from_entries(&values)? @@ -101,10 +110,9 @@ pub fn sign(v1: bool, sk: &mut [u8], msg: &[u8]) -> Result for PlumeSignature { let point_check = |point_bytes: Vec| -> Result { let point_encoded = sec1::point::EncodedPoint::from_bytes(point_bytes)?; // TODO improve formatting (quotes e.g.) let result = plume_rustcrypto::AffinePoint::from_encoded_point(&point_encoded); - if result.is_none().into() {Err(anyhow::Error::msg("the point isn't on the curve"))} - else {Ok(result.expect("`None` is processed the line above"))} + if result.is_none().into() { + Err(anyhow::Error::msg("the point isn't on the curve")) + } else { + Ok(result.expect("`None` is processed the line above")) + } }; - let err_field_wrap = |name_field: &str, er: anyhow::Error| -> JsError {JsError::new( - ("while proccessing ".to_owned() + name_field + " :" + er.to_string().as_str()).as_str() - )}; + let err_field_wrap = |name_field: &str, er: anyhow::Error| -> JsError { + JsError::new( + ("while proccessing ".to_owned() + name_field + " :" + er.to_string().as_str()) + .as_str(), + ) + }; - Ok(plume_rustcrypto::PlumeSignature{ + Ok(plume_rustcrypto::PlumeSignature { message: self.message, pk: point_check(self.pk).map_err(|er| err_field_wrap("`pk`", er))?, // plume_rustcrypto::AffinePoint::try_from(self.pk)?, //.try_into<[u8; 33]>()?.into(), - nullifier: point_check(self.nullifier).map_err(|er| err_field_wrap("`nullifier`", er))?, + nullifier: point_check(self.nullifier) + .map_err(|er| err_field_wrap("`nullifier`", er))?, c: plume_rustcrypto::SecretKey::from_sec1_der(&self.c)?.into(), - s: plume_rustcrypto::SecretKey::from_sec1_der(&self.s)?.into(),//scalar_from_bigint(self.s).map_err(|er| err_field_wrap("`s`", er))?, - v1specific: if let Some(v1) = self.v1specific {Some( - plume_rustcrypto::PlumeSignatureV1Fields{ - r_point: point_check(v1.r_point).map_err(|er| err_field_wrap("`r_point`", er))?, - hashed_to_curve_r: point_check(v1.hashed_to_curve_r).map_err(|er| err_field_wrap("`hashed_to_curve_r`", er))?, - } - )} else {None}, + s: plume_rustcrypto::SecretKey::from_sec1_der(&self.s)?.into(), //scalar_from_bigint(self.s).map_err(|er| err_field_wrap("`s`", er))?, + v1specific: if let Some(v1) = self.v1specific { + Some(plume_rustcrypto::PlumeSignatureV1Fields { + r_point: point_check(v1.r_point) + .map_err(|er| err_field_wrap("`r_point`", er))?, + hashed_to_curve_r: point_check(v1.hashed_to_curve_r) + .map_err(|er| err_field_wrap("`hashed_to_curve_r`", er))?, + }) + } else { + None + }, }) } } @@ -161,10 +180,18 @@ impl From for PlumeSignature { #[wasm_bindgen(js_name = sec1DerScalarToBigint)] /// This might leave values in memory! Don't use for private values. -/// JS most native format for scalar is `BigInt`, but it's not really transportable or secure, so for uniformity of approach `s` in `PlumeSignature` is defined similar to `c`; +/// JS most native format for scalar is `BigInt`, but it's not really transportable or secure, so for uniformity of approach `s` in `PlumeSignature` is defined similar to `c`; /// but if you want to have it as a `BigInt` this util is left here. pub fn sec1derscalar_to_bigint(scalar: &[u8]) -> Result { - Ok(js_sys::BigInt::new(&JsValue::from_str(( - "0x".to_owned() + plume_rustcrypto::SecretKey::from_sec1_der(scalar)?.to_nonzero_scalar().to_string().as_str() - ).as_str())).expect("`BigInt` always can be created from hex string, and `v.to_string()` always produce that")) -} \ No newline at end of file + Ok(js_sys::BigInt::new(&JsValue::from_str( + ("0x".to_owned() + + plume_rustcrypto::SecretKey::from_sec1_der(scalar)? + .to_nonzero_scalar() + .to_string() + .as_str()) + .as_str(), + )) + .expect( + "`BigInt` always can be created from hex string, and `v.to_string()` always produce that", + )) +} From c261a1ea4b05377c49f2fec7feb943342a79dbed Mon Sep 17 00:00:00 2001 From: skaunov Date: Tue, 9 Jul 2024 23:55:07 +0300 Subject: [PATCH 5/6] seems people think that `rc` are 1-based --- javascript/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/Cargo.toml b/javascript/Cargo.toml index b5e9040..fd4d09b 100644 --- a/javascript/Cargo.toml +++ b/javascript/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "plume-sig" -version = "3.0.0-rc.0" +version = "3.0.0-rc.1" authors = ["skaunov"] edition = "2018" keywords = ["nullifier", "zero-knowledge", "ECDSA", "PLUME"] From 4b5828fd4bfabb6cf28c70e103df20052f87f3aa Mon Sep 17 00:00:00 2001 From: skaunov Date: Wed, 17 Jul 2024 03:09:36 +0300 Subject: [PATCH 6/6] conventional quotations --- javascript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/README.md b/javascript/README.md index 1c8ee1f..d7d8947 100644 --- a/javascript/README.md +++ b/javascript/README.md @@ -19,7 +19,7 @@ Please, refer to the JS-doc for types description, function signatures, and exce Values in the following examples are in line with tests in the wrapped crate. ## producing the signature ```js -import * as plume from "plume-sig"; +import * as plume from 'plume-sig'; let result = plume.sign( false,