diff --git a/CHANGES.md b/CHANGES.md index 2c2e0a84..87c9654f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,37 @@ +# Version 2.0.0 + +Breaking: + +- The protobuf schema has changed to support additional enum variants for + backing datastructures. This means prior protobufs using earlier library + versions will not work with `2.0.0+`. We made this change to ensure additional + variants will not break the schema. In general, storing serialized protobufs + is not a pattern the protocol recommends since every intersection calculation + should be a new protocol exchange (setup, request, response, intersection). + +Feat: + +- A `Raw` datastructure enum variant has been added which when specified, + computes an intersection against 'raw' encrypted strings, but with zero + false-positives (`fpr` is ignored). It is intended for applications that + depend on 100% accuracy, but it may have a performance impact. + +Bufgix: + +- Previously, only the `CPP` bindings supported the datastructure enum to allow + the user to select which backing datastructure to use in the protocol (`GCS`, + `BloomFilter`, and now `Raw`). This meant we were not feature-compatible in + the languages that depended on the (incomplete) `C` bindings. In this release, + all languages support the same features, namely, we've updated the `C` + bindings which allowed us to get `Go` and `Rust` to be feature compatible. + +Chore: + +- All languages now have common integration tests and use unit tests where + relevant. We make a distinction between unit and integration tests. Unit tests + are for language-specific edge cases whereas the integration tests will test + the common APIs for correctness. + # Version 1.1.1 Chore: @@ -17,13 +51,20 @@ Bugfix: Bugfix: -- The Python builds were using the older `manylinux2014` tagging convention which was causing issues on systems that expected a specific glibc version (Ubuntu 20.04 uses [2.31](https://launchpad.net/ubuntu/+source/glibc)). We now use the latest `manylinux_x_y` tagging convention to accomodate different glibc versions across linux when building wheels. This means we must support `python 3.8.10+, 3.9.5+, 3.10.0+` and `pip >= 20.3` in accordance with [PEP 600](https://github.com/pypa/manylinux) +- The Python builds were using the older `manylinux2014` tagging convention + which was causing issues on systems that expected a specific glibc version + (Ubuntu 20.04 uses [2.31](https://launchpad.net/ubuntu/+source/glibc)). We now + use the latest `manylinux_x_y` tagging convention to accomodate different + glibc versions across linux when building wheels. This means we must support + `python 3.8.10+, 3.9.5+, 3.10.0+` and `pip >= 20.3` in accordance with [PEP + 600](https://github.com/pypa/manylinux) # Version 1.0.2 Feat: -- This patch version relaxes the Python requirement to allow for older `protobuf` libraries to work with the PSI library. +- This patch version relaxes the Python requirement to allow for older + `protobuf` libraries to work with the PSI library. # Version 1.0.1 @@ -32,8 +73,8 @@ Feat: - Update the Python bindings to take in an optional `DataStructure` argument for `CreateSetupMessage`. This allows the user to customize the behavior of the backing datastructure - i.e. to select between the default (`GCS`) or specify - `BLOOM_FILTER`. The previous behavior always selected `GCS` so if the parameter - is omitted, the behavior will remain the same. + `BLOOM_FILTER`. The previous behavior always selected `GCS` so if the + parameter is omitted, the behavior will remain the same. Ex: diff --git a/package-lock.json b/package-lock.json index ef19e220..e9302fd6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,52 +1,52 @@ { "name": "@openmined/psi.js", - "version": "1.1.1", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@openmined/psi.js", - "version": "1.1.1", + "version": "2.0.0", "license": "Apache-2.0", "dependencies": { - "@grpc/grpc-js": "^1.8.4", + "@grpc/grpc-js": "^1.8.8", "google-protobuf": "^3.21.2", "ts-protoc-gen": "^0.15.0" }, "devDependencies": { - "@babel/core": "^7.20.5", - "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/core": "^7.20.12", + "@babel/plugin-transform-modules-commonjs": "^7.20.11", "@babel/preset-env": "^7.20.2", "@bazel/bazelisk": "^1.7.5", "@bazel/typescript": "^5.7.3", - "@rollup/plugin-alias": "^4.0.2", - "@rollup/plugin-commonjs": "^23.0.4", - "@rollup/plugin-json": "^5.0.2", + "@rollup/plugin-alias": "^4.0.3", + "@rollup/plugin-commonjs": "^24.0.1", + "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.1", - "@rollup/plugin-replace": "^5.0.1", - "@rollup/plugin-terser": "^0.2.0", - "@rollup/plugin-typescript": "^10.0.1", + "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-terser": "^0.4.0", + "@rollup/plugin-typescript": "^11.0.0", "@types/google-protobuf": "^3.15.6", - "@types/jest": "^29.2.4", - "@types/node": "^18.11.13", - "@typescript-eslint/eslint-plugin": "^5.46.0", - "@typescript-eslint/parser": "^5.46.0", + "@types/jest": "^29.4.0", + "@types/node": "^18.13.0", + "@typescript-eslint/eslint-plugin": "^5.52.0", + "@typescript-eslint/parser": "^5.52.0", "buffer": "^6.0.3", - "eslint": "^8.29.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-jest": "^27.1.6", - "eslint-plugin-jsdoc": "^39.6.4", + "eslint": "^8.34.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jsdoc": "^40.0.0", "eslint-plugin-prettier": "^4.2.1", "esm": "^3.2.25", - "jest": "^29.3.1", + "jest": "^29.4.2", "path": "^0.12.7", - "prettier": "^2.8.1", - "rollup": "^2.32.1", + "prettier": "^2.8.4", + "rollup": "^3.15.0", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-typescript2": "^0.34.1", - "ts-jest": "^29.0.3", - "typescript": "^4.9.4" + "ts-jest": "^29.0.5", + "typescript": "^4.9.5" } }, "node_modules/@ampproject/remapping": { @@ -84,25 +84,25 @@ } }, "node_modules/@babel/core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", - "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.0", - "@babel/helper-module-transforms": "^7.20.2", - "@babel/helpers": "^7.20.5", - "@babel/parser": "^7.20.5", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", + "json5": "^2.2.2", "semver": "^6.3.0" }, "engines": { @@ -114,12 +114,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", "dev": true, "dependencies": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.20.7", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -167,14 +167,15 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.20.0", + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "engines": { @@ -184,6 +185,21 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz", @@ -309,9 +325,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", @@ -319,9 +335,9 @@ "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -461,14 +477,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", - "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -489,9 +505,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1268,14 +1284,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", - "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.19.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-simple-access": "^7.19.4" + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -1651,33 +1667,33 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1686,9 +1702,9 @@ } }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -1777,15 +1793,15 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1800,9 +1816,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1827,9 +1843,9 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.4.tgz", - "integrity": "sha512-oaETBotls7FTBpySg5dhyUCyXSxSeCMmkBBXHXG1iw57MiNoB6D7VRhkrXYbwyHM3Q3Afjp4KlsBX0Zb+ELZXw==", + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.8.tgz", + "integrity": "sha512-4gfDqMLXTrorvYTKA1jL22zLvVwiHJ73t6Re1OHwdCFRjdGTDOVtSJuaWhtHaivyeDGg0LeCkmU77MTKoV3wPA==", "dependencies": { "@grpc/proto-loader": "^0.7.0", "@types/node": ">=12.12.47" @@ -1884,9 +1900,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -1973,16 +1989,16 @@ } }, "node_modules/@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.4.2.tgz", + "integrity": "sha512-0I/rEJwMpV9iwi9cDEnT71a5nNGK9lj8Z4+1pRAU2x/thVXCDnaTGrvxyK+cAqZTFVFCiR+hfVrP4l2m+dCmQg==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2", "slash": "^3.0.0" }, "engines": { @@ -2060,37 +2076,37 @@ } }, "node_modules/@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.4.2.tgz", + "integrity": "sha512-KGuoQah0P3vGNlaS/l9/wQENZGNKGoWb+OPxh3gz+YzG7/XExvYu34MzikRndQCdM2S0tzExN4+FL37i6gZmCQ==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/reporters": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", + "jest-changed-files": "^29.4.2", + "jest-config": "^29.4.2", + "jest-haste-map": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-resolve-dependencies": "^29.4.2", + "jest-runner": "^29.4.2", + "jest-runtime": "^29.4.2", + "jest-snapshot": "^29.4.2", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", + "jest-watcher": "^29.4.2", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -2177,88 +2193,88 @@ } }, "node_modules/@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.4.2.tgz", + "integrity": "sha512-JKs3VUtse0vQfCaFGJRX1bir9yBdtasxziSyu+pIiEllAQOe4oQhdCYIf3+Lx+nGglFktSKToBnRJfD5QKp+NQ==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/fake-timers": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", - "jest-mock": "^29.3.1" + "jest-mock": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.4.2.tgz", + "integrity": "sha512-NUAeZVApzyaeLjfWIV/64zXjA2SS+NuUPHpAlO7IwVMGd5Vf9szTl9KEDlxY3B4liwLO31os88tYNHl6cpjtKQ==", "dev": true, "dependencies": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" + "expect": "^29.4.2", + "jest-snapshot": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.4.2.tgz", + "integrity": "sha512-Dd3ilDJpBnqa0GiPN7QrudVs0cczMMHtehSo2CSTjm3zdHx0RcpmhFNVEltuEFeqfLIyWKFI224FsMSQ/nsJQA==", "dev": true, "dependencies": { - "jest-get-type": "^29.2.0" + "jest-get-type": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.4.2.tgz", + "integrity": "sha512-Ny1u0Wg6kCsHFWq7A/rW/tMhIedq2siiyHyLpHCmIhP7WmcAmd2cx95P+0xtTZlj5ZbJxIRQi4OPydZZUoiSQQ==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.4.2", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-message-util": "^29.4.2", + "jest-mock": "^29.4.2", + "jest-util": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.4.2.tgz", + "integrity": "sha512-zCk70YGPzKnz/I9BNFDPlK+EuJLk21ur/NozVh6JVM86/YYZtZHqxFFQ62O9MWq7uf3vIZnvNA0BzzrtxD9iyg==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" + "@jest/environment": "^29.4.2", + "@jest/expect": "^29.4.2", + "@jest/types": "^29.4.2", + "jest-mock": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.4.2.tgz", + "integrity": "sha512-10yw6YQe75zCgYcXgEND9kw3UZZH5tJeLzWv4vTk/2mrS1aY50A37F+XT2hPO5OqQFFnUWizXD8k1BMiATNfUw==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -2271,9 +2287,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2", + "jest-worker": "^29.4.2", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -2349,36 +2365,6 @@ "node": ">=8" } }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/@jest/reporters/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2392,21 +2378,21 @@ } }, "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.2.tgz", + "integrity": "sha512-ZrGzGfh31NtdVH8tn0mgJw4khQuNHiKqdzJAFbCaERbyCP9tHlxWuL/mnMu8P7e/+k4puWjI1NOzi/sFsjce/g==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.24.1" + "@sinclair/typebox": "^0.25.16" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.2.tgz", + "integrity": "sha512-tIoqV5ZNgYI9XCKXMqbYe5JbumcvyTgNN+V5QW4My033lanijvCD0D4PI9tBw4pRTqWOc00/7X3KVvUh+qnF4Q==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.15", @@ -2418,13 +2404,13 @@ } }, "node_modules/@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.4.2.tgz", + "integrity": "sha512-HZsC3shhiHVvMtP+i55MGR5bPcc3obCFbA5bzIOb8pCjwBZf11cZliJncCgaVUbC5yoQNuGqCkC0Q3t6EItxZA==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/types": "^29.4.2", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -2433,14 +2419,14 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.4.2.tgz", + "integrity": "sha512-9Z2cVsD6CcObIVrWigHp2McRJhvCxL27xHtrZFgNC1RwnoSpDx6fZo8QYjJmziFlW9/hr78/3sxF54S8B6v8rg==", "dev": true, "dependencies": { - "@jest/test-result": "^29.3.1", + "@jest/test-result": "^29.4.2", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.4.2", "slash": "^3.0.0" }, "engines": { @@ -2448,26 +2434,26 @@ } }, "node_modules/@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.4.2.tgz", + "integrity": "sha512-kf1v5iTJHn7p9RbOsBuc/lcwyPtJaZJt5885C98omWz79NIeD3PfoiiaPSu7JyCyFzNOIzKhmMhQLUhlTL9BvQ==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-util": "^29.4.2", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -2550,12 +2536,12 @@ } }, "node_modules/@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.4.2.tgz", + "integrity": "sha512-CKlngyGP0fwlgC1BRUtPZSiWLBhyS9dKwKmyGxk8Z6M82LBEGB2aLQSg+U1MyLsU+M7UjnlLllBM2BLWKVm/Uw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.2", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -2797,9 +2783,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@rollup/plugin-alias": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-4.0.2.tgz", - "integrity": "sha512-1hv7dBOZZwo3SEupxn4UA2N0EDThqSSS+wI1St1TNTBtOZvUchyIClyHcnDcjjrReTPZ47Faedrhblv4n+T5UQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-4.0.3.tgz", + "integrity": "sha512-ZuDWE1q4PQDhvm/zc5Prun8sBpLJy41DMptYrS6MhAy9s9kL/doN1613BWfEchGVfKxzliJ3BjbOPizXX38DbQ==", "dev": true, "dependencies": { "slash": "^4.0.0" @@ -2829,9 +2815,9 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "23.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.4.tgz", - "integrity": "sha512-bOPJeTZg56D2MCm+TT4psP8e8Jmf1Jsi7pFUMl8BN5kOADNzofNHe47+84WVCt7D095xPghC235/YKuNDEhczg==", + "version": "24.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz", + "integrity": "sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -2839,7 +2825,7 @@ "estree-walker": "^2.0.2", "glob": "^8.0.3", "is-reference": "1.2.1", - "magic-string": "^0.26.4" + "magic-string": "^0.27.0" }, "engines": { "node": ">=14.0.0" @@ -2894,9 +2880,9 @@ } }, "node_modules/@rollup/plugin-json": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-5.0.2.tgz", - "integrity": "sha512-D1CoOT2wPvadWLhVcmpkDnesTzjhNIQRWLsc3fA49IFOP2Y84cFOOJ+nKGYedvXHKUsPeq07HR4hXpBBr+CHlA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.0.tgz", + "integrity": "sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1" @@ -2939,13 +2925,13 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.1.tgz", - "integrity": "sha512-Z3MfsJ4CK17BfGrZgvrcp/l6WXoKb0kokULO+zt/7bmcyayokDaQ2K3eDJcRLCTAlp5FPI4/gz9MHAsosz4Rag==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", + "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.26.4" + "magic-string": "^0.27.0" }, "engines": { "node": ">=14.0.0" @@ -2960,9 +2946,9 @@ } }, "node_modules/@rollup/plugin-terser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.2.0.tgz", - "integrity": "sha512-UBr4WNXBFipKW2C2db9JIzIdq9bFZsaTZwKeAd9Y0N9Pv9G2XgRhaimGdotx1+Wf/2XTuTJ+FVS2SO+y2WyiUQ==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.0.tgz", + "integrity": "sha512-Ipcf3LPNerey1q9ZMjiaWHlNPEHNU/B5/uh9zXLltfEQ1lVSLLeZSgAtTPWGyw8Ip1guOeq+mDtdOlEj/wNxQw==", "dev": true, "dependencies": { "serialize-javascript": "^6.0.0", @@ -2991,9 +2977,9 @@ } }, "node_modules/@rollup/plugin-typescript": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-10.0.1.tgz", - "integrity": "sha512-wBykxRLlX7EzL8BmUqMqk5zpx2onnmRMSw/l9M1sVfkJvdwfxogZQVNUM9gVMJbjRLDR5H6U0OMOrlDGmIV45A==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.0.0.tgz", + "integrity": "sha512-goPyCWBiimk1iJgSTgsehFD5OOFHiAknrRJjqFCudcW8JtWiBlK284Xnn4flqMqg6YAjVG/EE+3aVzrL5qNSzQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -3039,37 +3025,37 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "version": "0.25.21", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.21.tgz", + "integrity": "sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==", "dev": true }, "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^2.0.0" } }, "node_modules/@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -3116,9 +3102,9 @@ "dev": true }, "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "dependencies": { "@types/node": "*" @@ -3149,9 +3135,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.4.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", + "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -3170,14 +3156,14 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "node_modules/@types/node": { - "version": "18.11.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz", - "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w==" + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==" }, "node_modules/@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "node_modules/@types/resolve": { @@ -3214,15 +3200,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz", - "integrity": "sha512-QrZqaIOzJAjv0sfjY4EjbXUi3ZOFpKfzntx22gPGr9pmFcTjcFw/1sS1LJhEubfAGwuLjNrPV0rH+D1/XZFy7Q==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", + "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/type-utils": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/type-utils": "5.52.0", + "@typescript-eslint/utils": "5.52.0", "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", @@ -3262,14 +3249,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz", - "integrity": "sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", + "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/typescript-estree": "5.46.0", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", "debug": "^4.3.4" }, "engines": { @@ -3289,13 +3276,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz", - "integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0" + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3306,13 +3293,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.0.tgz", - "integrity": "sha512-dwv4nimVIAsVS2dTA0MekkWaRnoYNXY26dKz8AN5W3cBFYwYGFQEqm/cG+TOoooKlncJS4RTbFKgcFY/pOiBCg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", + "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/utils": "5.52.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -3333,9 +3320,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3346,13 +3333,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz", - "integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3388,16 +3375,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.0.tgz", - "integrity": "sha512-4O+Ps1CRDw+D+R40JYh5GlKLQERXRKW5yIQoNDpmXPJ+C7kaPF9R7GWl+PxGgXjB3PQCqsaaZUpZ9dG4U6DO7g==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", + "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/typescript-estree": "5.46.0", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -3429,12 +3416,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.52.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -3591,15 +3578,15 @@ "dev": true }, "node_modules/babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.4.2.tgz", + "integrity": "sha512-vcghSqhtowXPG84posYkkkzcZsdayFkubUgbE3/1tuGbX7AQtwCkkNA/wIbB0BMjuCPoqTkiDyKN7Ty7d3uwNQ==", "dev": true, "dependencies": { - "@jest/transform": "^29.3.1", + "@jest/transform": "^29.4.2", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", + "babel-preset-jest": "^29.4.2", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -3698,9 +3685,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.4.2.tgz", + "integrity": "sha512-5HZRCfMeWypFEonRbEkwWXtNS1sQK159LhRVyRuLzyfVBxDy/34Tr/rg4YVi0SScSJ4fqeaR/OIeceJ/LaQ0pQ==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -3775,12 +3762,12 @@ } }, "node_modules/babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.4.2.tgz", + "integrity": "sha512-ecWdaLY/8JyfUDr0oELBMpj3R5I1L6ZqG+kRJmwqfHtLWuPrJStR0LUkvUhfykJWTsXXMnohsayN/twltBbDrQ==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^29.2.0", + "babel-plugin-jest-hoist": "^29.4.2", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { @@ -4440,9 +4427,9 @@ } }, "node_modules/diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.2.tgz", + "integrity": "sha512-R6P0Y6PrsH3n4hUXxL3nns0rbRk6Q33js3ygJBeEpbzLzgcNuJ61+u0RXasFpTKISw99TxUzFnumSnRLsjhLaw==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4572,13 +4559,13 @@ } }, "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -4597,7 +4584,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -4628,9 +4615,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -4640,9 +4627,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.1.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.1.6.tgz", - "integrity": "sha512-XA7RFLSrlQF9IGtAmhddkUkBuICCTuryfOTfCSWcZHiHb69OilIH05oozH2XA6CEOtztnOd0vgXyvxZodkxGjg==", + "version": "27.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz", + "integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -4664,9 +4651,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "39.6.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.4.tgz", - "integrity": "sha512-fskvdLCfwmPjHb6e+xNGDtGgbF8X7cDwMtVLAP2WwSf9Htrx68OAx31BESBM1FAwsN2HTQyYQq7m4aW4Q4Nlag==", + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-40.0.0.tgz", + "integrity": "sha512-LOPyIu1vAVvGPkye3ci0moj0iNf3f8bmin6do2DYDj+77NRXWnkmhKRy8swWsatUs3mB5jYPWPUsFg9pyfEiyA==", "dev": true, "dependencies": { "@es-joy/jsdoccomment": "~0.36.1", @@ -4881,9 +4868,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -5130,16 +5117,16 @@ } }, "node_modules/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.4.2.tgz", + "integrity": "sha512-+JHYg9O3hd3RlICG90OPVjRkPBoiUH7PxvDVMnRiaq1g6JUgZStX514erMl0v2Dc5SkfVbm7ztqbd6qHHPn+mQ==", "dev": true, "dependencies": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" + "@jest/expect-utils": "^29.4.2", + "jest-get-type": "^29.4.2", + "jest-matcher-utils": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -5886,15 +5873,15 @@ } }, "node_modules/jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.4.2.tgz", + "integrity": "sha512-+5hLd260vNIHu+7ZgMIooSpKl7Jp5pHKb51e73AJU3owd5dEo/RfVwHbA/na3C/eozrt3hJOLGf96c7EWwIAzg==", "dev": true, "dependencies": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.4.2", + "@jest/types": "^29.4.2", "import-local": "^3.0.2", - "jest-cli": "^29.3.1" + "jest-cli": "^29.4.2" }, "bin": { "jest": "bin/jest.js" @@ -5912,9 +5899,9 @@ } }, "node_modules/jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.4.2.tgz", + "integrity": "sha512-Qdd+AXdqD16PQa+VsWJpxR3kN0JyOCX1iugQfx5nUgAsI4gwsKviXkpclxOK9ZnwaY2IQVHz+771eAvqeOlfuw==", "dev": true, "dependencies": { "execa": "^5.0.0", @@ -5940,28 +5927,28 @@ } }, "node_modules/jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.4.2.tgz", + "integrity": "sha512-wW3ztp6a2P5c1yOc1Cfrt5ozJ7neWmqeXm/4SYiqcSriyisgq63bwFj1NuRdSR5iqS0CMEYwSZd89ZA47W9zUg==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.4.2", + "@jest/expect": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-each": "^29.4.2", + "jest-matcher-utils": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-runtime": "^29.4.2", + "jest-snapshot": "^29.4.2", + "jest-util": "^29.4.2", "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -6055,21 +6042,21 @@ } }, "node_modules/jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.4.2.tgz", + "integrity": "sha512-b+eGUtXq/K2v7SH3QcJvFvaUaCDS1/YAZBYz0m28Q/Ppyr+1qNaHmVYikOrbHVbZqYQs2IeI3p76uy6BWbXq8Q==", "dev": true, "dependencies": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/types": "^29.4.2", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-config": "^29.4.2", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -6159,31 +6146,31 @@ } }, "node_modules/jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.4.2.tgz", + "integrity": "sha512-919CtnXic52YM0zW4C1QxjG6aNueX1kBGthuMtvFtRTAxhKfJmiXC9qwHmi6o2josjbDz8QlWyY55F1SIVmCWA==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", + "@jest/test-sequencer": "^29.4.2", + "@jest/types": "^29.4.2", + "babel-jest": "^29.4.2", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-circus": "^29.4.2", + "jest-environment-node": "^29.4.2", + "jest-get-type": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-runner": "^29.4.2", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -6274,15 +6261,15 @@ } }, "node_modules/jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.4.2.tgz", + "integrity": "sha512-EK8DSajVtnjx9sa1BkjZq3mqChm2Cd8rIzdXkQMA8e0wuXq53ypz6s5o5V8HRZkoEt2ywJ3eeNWFKWeYr8HK4g==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "diff-sequences": "^29.4.2", + "jest-get-type": "^29.4.2", + "pretty-format": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -6359,9 +6346,9 @@ } }, "node_modules/jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.2.tgz", + "integrity": "sha512-dV2JdahgClL34Y5vLrAHde3nF3yo2jKRH+GIYJuCpfqwEJZcikzeafVTGAjbOfKPG17ez9iWXwUYp7yefeCRag==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" @@ -6371,16 +6358,16 @@ } }, "node_modules/jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.4.2.tgz", + "integrity": "sha512-trvKZb0JYiCndc55V1Yh0Luqi7AsAdDWpV+mKT/5vkpnnFQfuQACV72IoRV161aAr6kAVIBpmYzwhBzm34vQkA==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.2", + "jest-util": "^29.4.2", + "pretty-format": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -6457,46 +6444,46 @@ } }, "node_modules/jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.4.2.tgz", + "integrity": "sha512-MLPrqUcOnNBc8zTOfqBbxtoa8/Ee8tZ7UFW7hRDQSUT+NGsvS96wlbHGTf+EFAT9KC3VNb7fWEM6oyvmxtE/9w==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.4.2", + "@jest/fake-timers": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-mock": "^29.4.2", + "jest-util": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.2.tgz", + "integrity": "sha512-vERN30V5i2N6lqlFu4ljdTqQAgrkTFMC9xaIIfOPYBw04pufjXRty5RuXBiB1d72tGbURa/UgoiHB90ruOSivg==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.4.2.tgz", + "integrity": "sha512-WkUgo26LN5UHPknkezrBzr7lUtV1OpGsp+NfXbBwHztsFruS3gz+AMTTBcEklvi8uPzpISzYjdKXYZQJXBnfvw==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-regex-util": "^29.4.2", + "jest-util": "^29.4.2", + "jest-worker": "^29.4.2", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -6507,68 +6494,29 @@ "fsevents": "^2.3.2" } }, - "node_modules/jest-haste-map/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.4.2.tgz", + "integrity": "sha512-Wa62HuRJmWXtX9F00nUpWlrbaH5axeYCdyRsOs/+Rb1Vb6+qWTlB5rKwCCRKtorM7owNwKsyJ8NRDUcZ8ghYUA==", "dev": true, "dependencies": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.2", + "pretty-format": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.4.2.tgz", + "integrity": "sha512-EZaAQy2je6Uqkrm6frnxBIdaWtSYFoR8SVb2sNLAtldswlR/29JAgx+hy67llT3+hXBaLB0zAm5UfeqerioZyg==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-diff": "^29.4.2", + "jest-get-type": "^29.4.2", + "pretty-format": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -6645,18 +6593,18 @@ } }, "node_modules/jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.4.2.tgz", + "integrity": "sha512-SElcuN4s6PNKpOEtTInjOAA8QvItu0iugkXqhYyguRvQoXapg5gN+9RQxLAkakChZA7Y26j6yUCsFWN+hlKD6g==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -6735,14 +6683,14 @@ } }, "node_modules/jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.4.2.tgz", + "integrity": "sha512-x1FSd4Gvx2yIahdaIKoBjwji6XpboDunSJ95RpntGrYulI1ByuYQCKN/P7hvk09JB74IonU3IPLdkutEWYt++g==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/node": "*", - "jest-util": "^29.3.1" + "jest-util": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -6766,28 +6714,28 @@ } }, "node_modules/jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.2.tgz", + "integrity": "sha512-XYZXOqUl1y31H6VLMrrUL1ZhXuiymLKPz0BO1kEeR5xER9Tv86RZrjTm74g5l9bPJQXA/hyLdaVPN/sdqfteig==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.4.2.tgz", + "integrity": "sha512-RtKWW0mbR3I4UdkOrW7552IFGLYQ5AF9YrzD0FnIOkDu0rAMlA5/Y1+r7lhCAP4nXSBTaE7ueeqj6IOwZpgoqw==", "dev": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.4.2", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" }, "engines": { @@ -6795,13 +6743,13 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.4.2.tgz", + "integrity": "sha512-6pL4ptFw62rjdrPk7rRpzJYgcRqRZNsZTF1VxVTZMishbO6ObyWvX57yHOaNGgKoADtAHRFYdHQUEvYMJATbDg==", "dev": true, "dependencies": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" + "jest-regex-util": "^29.4.2", + "jest-snapshot": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -6878,30 +6826,30 @@ } }, "node_modules/jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.4.2.tgz", + "integrity": "sha512-wqwt0drm7JGjwdH+x1XgAl+TFPH7poowMguPQINYxaukCqlczAcNLJiK+OLxUxQAEWMdy+e6nHZlFHO5s7EuRg==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/environment": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-docblock": "^29.4.2", + "jest-environment-node": "^29.4.2", + "jest-haste-map": "^29.4.2", + "jest-leak-detector": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-runtime": "^29.4.2", + "jest-util": "^29.4.2", + "jest-watcher": "^29.4.2", + "jest-worker": "^29.4.2", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -6967,36 +6915,6 @@ "node": ">=8" } }, - "node_modules/jest-runner/node_modules/jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jest-runner/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7035,31 +6953,32 @@ } }, "node_modules/jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.4.2.tgz", + "integrity": "sha512-3fque9vtpLzGuxT9eZqhxi+9EylKK/ESfhClv4P7Y9sqJPs58LjVhTt8jaMp/pRO38agll1CkSu9z9ieTQeRrw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.4.2", + "@jest/fake-timers": "^29.4.2", + "@jest/globals": "^29.4.2", + "@jest/source-map": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-mock": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-snapshot": "^29.4.2", + "jest-util": "^29.4.2", + "semver": "^7.3.5", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -7125,6 +7044,21 @@ "node": ">=8" } }, + "node_modules/jest-runtime/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-runtime/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7138,9 +7072,9 @@ } }, "node_modules/jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.4.2.tgz", + "integrity": "sha512-PdfubrSNN5KwroyMH158R23tWcAXJyx4pvSvWls1dHoLCaUhGul9rsL3uVjtqzRpkxlkMavQjGuWG1newPgmkw==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", @@ -7149,23 +7083,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/expect-utils": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.3.1", + "expect": "^29.4.2", "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-diff": "^29.4.2", + "jest-get-type": "^29.4.2", + "jest-haste-map": "^29.4.2", + "jest-matcher-utils": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2", "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "semver": "^7.3.5" }, "engines": { @@ -7258,12 +7192,12 @@ } }, "node_modules/jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.4.2.tgz", + "integrity": "sha512-wKnm6XpJgzMUSRFB7YF48CuwdzuDIHenVuoIb1PLuJ6F+uErZsuDkU+EiExkChf6473XcawBrSfDSnXl+/YG4g==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -7345,17 +7279,17 @@ } }, "node_modules/jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.4.2.tgz", + "integrity": "sha512-tto7YKGPJyFbhcKhIDFq8B5od+eVWD/ySZ9Tvcp/NGCvYA4RQbuzhbwYWtIjMT5W5zA2W0eBJwu4HVw34d5G6Q==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", + "jest-get-type": "^29.4.2", "leven": "^3.1.0", - "pretty-format": "^29.3.1" + "pretty-format": "^29.4.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -7444,18 +7378,18 @@ } }, "node_modules/jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.4.2.tgz", + "integrity": "sha512-onddLujSoGiMJt+tKutehIidABa175i/Ays+QvKxCqBwp7fvxP3ZhKsrIdOodt71dKxqk4sc0LN41mWLGIK44w==", "dev": true, "dependencies": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/test-result": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.3.1", + "jest-util": "^29.4.2", "string-length": "^4.0.1" }, "engines": { @@ -7532,6 +7466,45 @@ "node": ">=8" } }, + "node_modules/jest-worker": { + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.4.2.tgz", + "integrity": "sha512-VIuZA2hZmFyRbchsUCHEehoSf2HEl0YVF8SDJqtPnKorAaBuh42V8QsLnde0XP5F6TyCynGPEGgBOn3Fc+wZGw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.4.2", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -7918,12 +7891,12 @@ "dev": true }, "node_modules/magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", "dev": true, "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.13" }, "engines": { "node": ">=12" @@ -8350,9 +8323,9 @@ } }, "node_modules/prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -8377,12 +8350,12 @@ } }, "node_modules/pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", + "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", "dev": true, "dependencies": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.2", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -8491,9 +8464,9 @@ "dev": true }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, "engines": { "node": ">=6" @@ -8703,9 +8676,9 @@ } }, "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.0.tgz", + "integrity": "sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==", "dev": true, "engines": { "node": ">=10" @@ -8747,15 +8720,16 @@ } }, "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.15.0.tgz", + "integrity": "sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=14.18.0", + "npm": ">=8.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" @@ -9012,13 +8986,6 @@ "source-map": "^0.6.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -9240,15 +9207,15 @@ } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -9390,9 +9357,9 @@ "dev": true }, "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -9723,35 +9690,35 @@ "dev": true }, "@babel/core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", - "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.0", - "@babel/helper-module-transforms": "^7.20.2", - "@babel/helpers": "^7.20.5", - "@babel/parser": "^7.20.5", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", + "json5": "^2.2.2", "semver": "^6.3.0" } }, "@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", "dev": true, "requires": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.20.7", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -9789,15 +9756,33 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.20.0", + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } } }, "@babel/helper-create-class-features-plugin": { @@ -9892,9 +9877,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.18.9", @@ -9902,9 +9887,9 @@ "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" } }, "@babel/helper-optimise-call-expression": { @@ -10005,14 +9990,14 @@ } }, "@babel/helpers": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", - "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", "dev": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" } }, "@babel/highlight": { @@ -10027,9 +10012,9 @@ } }, "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -10533,14 +10518,14 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", - "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.19.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-simple-access": "^7.19.4" + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" } }, "@babel/plugin-transform-modules-systemjs": { @@ -10802,38 +10787,38 @@ } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" } }, "@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", @@ -10904,15 +10889,15 @@ } }, "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -10921,9 +10906,9 @@ }, "dependencies": { "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -10938,9 +10923,9 @@ } }, "@grpc/grpc-js": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.4.tgz", - "integrity": "sha512-oaETBotls7FTBpySg5dhyUCyXSxSeCMmkBBXHXG1iw57MiNoB6D7VRhkrXYbwyHM3Q3Afjp4KlsBX0Zb+ELZXw==", + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.8.tgz", + "integrity": "sha512-4gfDqMLXTrorvYTKA1jL22zLvVwiHJ73t6Re1OHwdCFRjdGTDOVtSJuaWhtHaivyeDGg0LeCkmU77MTKoV3wPA==", "requires": { "@grpc/proto-loader": "^0.7.0", "@types/node": ">=12.12.47" @@ -10985,9 +10970,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -11054,16 +11039,16 @@ "dev": true }, "@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.4.2.tgz", + "integrity": "sha512-0I/rEJwMpV9iwi9cDEnT71a5nNGK9lj8Z4+1pRAU2x/thVXCDnaTGrvxyK+cAqZTFVFCiR+hfVrP4l2m+dCmQg==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2", "slash": "^3.0.0" }, "dependencies": { @@ -11119,37 +11104,37 @@ } }, "@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.4.2.tgz", + "integrity": "sha512-KGuoQah0P3vGNlaS/l9/wQENZGNKGoWb+OPxh3gz+YzG7/XExvYu34MzikRndQCdM2S0tzExN4+FL37i6gZmCQ==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/reporters": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", + "jest-changed-files": "^29.4.2", + "jest-config": "^29.4.2", + "jest-haste-map": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-resolve-dependencies": "^29.4.2", + "jest-runner": "^29.4.2", + "jest-runtime": "^29.4.2", + "jest-snapshot": "^29.4.2", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", + "jest-watcher": "^29.4.2", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -11206,73 +11191,73 @@ } }, "@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.4.2.tgz", + "integrity": "sha512-JKs3VUtse0vQfCaFGJRX1bir9yBdtasxziSyu+pIiEllAQOe4oQhdCYIf3+Lx+nGglFktSKToBnRJfD5QKp+NQ==", "dev": true, "requires": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/fake-timers": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", - "jest-mock": "^29.3.1" + "jest-mock": "^29.4.2" } }, "@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.4.2.tgz", + "integrity": "sha512-NUAeZVApzyaeLjfWIV/64zXjA2SS+NuUPHpAlO7IwVMGd5Vf9szTl9KEDlxY3B4liwLO31os88tYNHl6cpjtKQ==", "dev": true, "requires": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" + "expect": "^29.4.2", + "jest-snapshot": "^29.4.2" } }, "@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.4.2.tgz", + "integrity": "sha512-Dd3ilDJpBnqa0GiPN7QrudVs0cczMMHtehSo2CSTjm3zdHx0RcpmhFNVEltuEFeqfLIyWKFI224FsMSQ/nsJQA==", "dev": true, "requires": { - "jest-get-type": "^29.2.0" + "jest-get-type": "^29.4.2" } }, "@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.4.2.tgz", + "integrity": "sha512-Ny1u0Wg6kCsHFWq7A/rW/tMhIedq2siiyHyLpHCmIhP7WmcAmd2cx95P+0xtTZlj5ZbJxIRQi4OPydZZUoiSQQ==", "dev": true, "requires": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.4.2", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-message-util": "^29.4.2", + "jest-mock": "^29.4.2", + "jest-util": "^29.4.2" } }, "@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.4.2.tgz", + "integrity": "sha512-zCk70YGPzKnz/I9BNFDPlK+EuJLk21ur/NozVh6JVM86/YYZtZHqxFFQ62O9MWq7uf3vIZnvNA0BzzrtxD9iyg==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" + "@jest/environment": "^29.4.2", + "@jest/expect": "^29.4.2", + "@jest/types": "^29.4.2", + "jest-mock": "^29.4.2" } }, "@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.4.2.tgz", + "integrity": "sha512-10yw6YQe75zCgYcXgEND9kw3UZZH5tJeLzWv4vTk/2mrS1aY50A37F+XT2hPO5OqQFFnUWizXD8k1BMiATNfUw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -11285,9 +11270,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2", + "jest-worker": "^29.4.2", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -11334,29 +11319,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11369,18 +11331,18 @@ } }, "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.2.tgz", + "integrity": "sha512-ZrGzGfh31NtdVH8tn0mgJw4khQuNHiKqdzJAFbCaERbyCP9tHlxWuL/mnMu8P7e/+k4puWjI1NOzi/sFsjce/g==", "dev": true, "requires": { - "@sinclair/typebox": "^0.24.1" + "@sinclair/typebox": "^0.25.16" } }, "@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.2.tgz", + "integrity": "sha512-tIoqV5ZNgYI9XCKXMqbYe5JbumcvyTgNN+V5QW4My033lanijvCD0D4PI9tBw4pRTqWOc00/7X3KVvUh+qnF4Q==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.15", @@ -11389,50 +11351,50 @@ } }, "@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.4.2.tgz", + "integrity": "sha512-HZsC3shhiHVvMtP+i55MGR5bPcc3obCFbA5bzIOb8pCjwBZf11cZliJncCgaVUbC5yoQNuGqCkC0Q3t6EItxZA==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/types": "^29.4.2", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.4.2.tgz", + "integrity": "sha512-9Z2cVsD6CcObIVrWigHp2McRJhvCxL27xHtrZFgNC1RwnoSpDx6fZo8QYjJmziFlW9/hr78/3sxF54S8B6v8rg==", "dev": true, "requires": { - "@jest/test-result": "^29.3.1", + "@jest/test-result": "^29.4.2", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.4.2", "slash": "^3.0.0" } }, "@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.4.2.tgz", + "integrity": "sha512-kf1v5iTJHn7p9RbOsBuc/lcwyPtJaZJt5885C98omWz79NIeD3PfoiiaPSu7JyCyFzNOIzKhmMhQLUhlTL9BvQ==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-util": "^29.4.2", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "dependencies": { "ansi-styles": { @@ -11493,12 +11455,12 @@ } }, "@jest/types": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.4.2.tgz", + "integrity": "sha512-CKlngyGP0fwlgC1BRUtPZSiWLBhyS9dKwKmyGxk8Z6M82LBEGB2aLQSg+U1MyLsU+M7UjnlLllBM2BLWKVm/Uw==", "dev": true, "requires": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.2", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -11699,9 +11661,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@rollup/plugin-alias": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-4.0.2.tgz", - "integrity": "sha512-1hv7dBOZZwo3SEupxn4UA2N0EDThqSSS+wI1St1TNTBtOZvUchyIClyHcnDcjjrReTPZ47Faedrhblv4n+T5UQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-4.0.3.tgz", + "integrity": "sha512-ZuDWE1q4PQDhvm/zc5Prun8sBpLJy41DMptYrS6MhAy9s9kL/doN1613BWfEchGVfKxzliJ3BjbOPizXX38DbQ==", "dev": true, "requires": { "slash": "^4.0.0" @@ -11716,9 +11678,9 @@ } }, "@rollup/plugin-commonjs": { - "version": "23.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.4.tgz", - "integrity": "sha512-bOPJeTZg56D2MCm+TT4psP8e8Jmf1Jsi7pFUMl8BN5kOADNzofNHe47+84WVCt7D095xPghC235/YKuNDEhczg==", + "version": "24.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz", + "integrity": "sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==", "dev": true, "requires": { "@rollup/pluginutils": "^5.0.1", @@ -11726,7 +11688,7 @@ "estree-walker": "^2.0.2", "glob": "^8.0.3", "is-reference": "1.2.1", - "magic-string": "^0.26.4" + "magic-string": "^0.27.0" }, "dependencies": { "brace-expansion": { @@ -11763,9 +11725,9 @@ } }, "@rollup/plugin-json": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-5.0.2.tgz", - "integrity": "sha512-D1CoOT2wPvadWLhVcmpkDnesTzjhNIQRWLsc3fA49IFOP2Y84cFOOJ+nKGYedvXHKUsPeq07HR4hXpBBr+CHlA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.0.tgz", + "integrity": "sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==", "dev": true, "requires": { "@rollup/pluginutils": "^5.0.1" @@ -11786,19 +11748,19 @@ } }, "@rollup/plugin-replace": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.1.tgz", - "integrity": "sha512-Z3MfsJ4CK17BfGrZgvrcp/l6WXoKb0kokULO+zt/7bmcyayokDaQ2K3eDJcRLCTAlp5FPI4/gz9MHAsosz4Rag==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", + "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", "dev": true, "requires": { "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.26.4" + "magic-string": "^0.27.0" } }, "@rollup/plugin-terser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.2.0.tgz", - "integrity": "sha512-UBr4WNXBFipKW2C2db9JIzIdq9bFZsaTZwKeAd9Y0N9Pv9G2XgRhaimGdotx1+Wf/2XTuTJ+FVS2SO+y2WyiUQ==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.0.tgz", + "integrity": "sha512-Ipcf3LPNerey1q9ZMjiaWHlNPEHNU/B5/uh9zXLltfEQ1lVSLLeZSgAtTPWGyw8Ip1guOeq+mDtdOlEj/wNxQw==", "dev": true, "requires": { "serialize-javascript": "^6.0.0", @@ -11818,9 +11780,9 @@ } }, "@rollup/plugin-typescript": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-10.0.1.tgz", - "integrity": "sha512-wBykxRLlX7EzL8BmUqMqk5zpx2onnmRMSw/l9M1sVfkJvdwfxogZQVNUM9gVMJbjRLDR5H6U0OMOrlDGmIV45A==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.0.0.tgz", + "integrity": "sha512-goPyCWBiimk1iJgSTgsehFD5OOFHiAknrRJjqFCudcW8JtWiBlK284Xnn4flqMqg6YAjVG/EE+3aVzrL5qNSzQ==", "dev": true, "requires": { "@rollup/pluginutils": "^5.0.1", @@ -11839,37 +11801,37 @@ } }, "@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "version": "0.25.21", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.21.tgz", + "integrity": "sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==", "dev": true }, "@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^2.0.0" } }, "@types/babel__core": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -11916,9 +11878,9 @@ "dev": true }, "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "requires": { "@types/node": "*" @@ -11949,9 +11911,9 @@ } }, "@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.4.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", + "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", "dev": true, "requires": { "expect": "^29.0.0", @@ -11970,14 +11932,14 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "@types/node": { - "version": "18.11.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz", - "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w==" + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==" }, "@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "@types/resolve": { @@ -12014,15 +11976,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz", - "integrity": "sha512-QrZqaIOzJAjv0sfjY4EjbXUi3ZOFpKfzntx22gPGr9pmFcTjcFw/1sS1LJhEubfAGwuLjNrPV0rH+D1/XZFy7Q==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", + "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/type-utils": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/type-utils": "5.52.0", + "@typescript-eslint/utils": "5.52.0", "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", @@ -12042,53 +12005,53 @@ } }, "@typescript-eslint/parser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz", - "integrity": "sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", + "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/typescript-estree": "5.46.0", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz", - "integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0" + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" } }, "@typescript-eslint/type-utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.0.tgz", - "integrity": "sha512-dwv4nimVIAsVS2dTA0MekkWaRnoYNXY26dKz8AN5W3cBFYwYGFQEqm/cG+TOoooKlncJS4RTbFKgcFY/pOiBCg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", + "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.46.0", - "@typescript-eslint/utils": "5.46.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/utils": "5.52.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz", - "integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz", - "integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/visitor-keys": "5.46.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -12108,16 +12071,16 @@ } }, "@typescript-eslint/utils": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.0.tgz", - "integrity": "sha512-4O+Ps1CRDw+D+R40JYh5GlKLQERXRKW5yIQoNDpmXPJ+C7kaPF9R7GWl+PxGgXjB3PQCqsaaZUpZ9dG4U6DO7g==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", + "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.46.0", - "@typescript-eslint/types": "5.46.0", - "@typescript-eslint/typescript-estree": "5.46.0", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -12135,12 +12098,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz", - "integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.46.0", + "@typescript-eslint/types": "5.52.0", "eslint-visitor-keys": "^3.3.0" }, "dependencies": { @@ -12260,15 +12223,15 @@ } }, "babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.4.2.tgz", + "integrity": "sha512-vcghSqhtowXPG84posYkkkzcZsdayFkubUgbE3/1tuGbX7AQtwCkkNA/wIbB0BMjuCPoqTkiDyKN7Ty7d3uwNQ==", "dev": true, "requires": { - "@jest/transform": "^29.3.1", + "@jest/transform": "^29.4.2", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", + "babel-preset-jest": "^29.4.2", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -12339,9 +12302,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.4.2.tgz", + "integrity": "sha512-5HZRCfMeWypFEonRbEkwWXtNS1sQK159LhRVyRuLzyfVBxDy/34Tr/rg4YVi0SScSJ4fqeaR/OIeceJ/LaQ0pQ==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -12401,12 +12364,12 @@ } }, "babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.4.2.tgz", + "integrity": "sha512-ecWdaLY/8JyfUDr0oELBMpj3R5I1L6ZqG+kRJmwqfHtLWuPrJStR0LUkvUhfykJWTsXXMnohsayN/twltBbDrQ==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^29.2.0", + "babel-plugin-jest-hoist": "^29.4.2", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -12945,9 +12908,9 @@ "dev": true }, "diff-sequences": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.2.tgz", + "integrity": "sha512-R6P0Y6PrsH3n4hUXxL3nns0rbRk6Q33js3ygJBeEpbzLzgcNuJ61+u0RXasFpTKISw99TxUzFnumSnRLsjhLaw==", "dev": true }, "diffie-hellman": { @@ -13057,13 +13020,13 @@ "dev": true }, "eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -13082,7 +13045,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -13176,9 +13139,9 @@ } }, "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -13235,25 +13198,25 @@ } }, "eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "requires": {} }, "eslint-plugin-jest": { - "version": "27.1.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.1.6.tgz", - "integrity": "sha512-XA7RFLSrlQF9IGtAmhddkUkBuICCTuryfOTfCSWcZHiHb69OilIH05oozH2XA6CEOtztnOd0vgXyvxZodkxGjg==", + "version": "27.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz", + "integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==", "dev": true, "requires": { "@typescript-eslint/utils": "^5.10.0" } }, "eslint-plugin-jsdoc": { - "version": "39.6.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.4.tgz", - "integrity": "sha512-fskvdLCfwmPjHb6e+xNGDtGgbF8X7cDwMtVLAP2WwSf9Htrx68OAx31BESBM1FAwsN2HTQyYQq7m4aW4Q4Nlag==", + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-40.0.0.tgz", + "integrity": "sha512-LOPyIu1vAVvGPkye3ci0moj0iNf3f8bmin6do2DYDj+77NRXWnkmhKRy8swWsatUs3mB5jYPWPUsFg9pyfEiyA==", "dev": true, "requires": { "@es-joy/jsdoccomment": "~0.36.1", @@ -13433,16 +13396,16 @@ "dev": true }, "expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.4.2.tgz", + "integrity": "sha512-+JHYg9O3hd3RlICG90OPVjRkPBoiUH7PxvDVMnRiaq1g6JUgZStX514erMl0v2Dc5SkfVbm7ztqbd6qHHPn+mQ==", "dev": true, "requires": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" + "@jest/expect-utils": "^29.4.2", + "jest-get-type": "^29.4.2", + "jest-matcher-utils": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2" } }, "fast-deep-equal": { @@ -14021,21 +13984,21 @@ } }, "jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.4.2.tgz", + "integrity": "sha512-+5hLd260vNIHu+7ZgMIooSpKl7Jp5pHKb51e73AJU3owd5dEo/RfVwHbA/na3C/eozrt3hJOLGf96c7EWwIAzg==", "dev": true, "requires": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.4.2", + "@jest/types": "^29.4.2", "import-local": "^3.0.2", - "jest-cli": "^29.3.1" + "jest-cli": "^29.4.2" } }, "jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.4.2.tgz", + "integrity": "sha512-Qdd+AXdqD16PQa+VsWJpxR3kN0JyOCX1iugQfx5nUgAsI4gwsKviXkpclxOK9ZnwaY2IQVHz+771eAvqeOlfuw==", "dev": true, "requires": { "execa": "^5.0.0", @@ -14054,28 +14017,28 @@ } }, "jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.4.2.tgz", + "integrity": "sha512-wW3ztp6a2P5c1yOc1Cfrt5ozJ7neWmqeXm/4SYiqcSriyisgq63bwFj1NuRdSR5iqS0CMEYwSZd89ZA47W9zUg==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.4.2", + "@jest/expect": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-each": "^29.4.2", + "jest-matcher-utils": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-runtime": "^29.4.2", + "jest-snapshot": "^29.4.2", + "jest-util": "^29.4.2", "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -14141,21 +14104,21 @@ } }, "jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.4.2.tgz", + "integrity": "sha512-b+eGUtXq/K2v7SH3QcJvFvaUaCDS1/YAZBYz0m28Q/Ppyr+1qNaHmVYikOrbHVbZqYQs2IeI3p76uy6BWbXq8Q==", "dev": true, "requires": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/types": "^29.4.2", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-config": "^29.4.2", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -14212,31 +14175,31 @@ } }, "jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.4.2.tgz", + "integrity": "sha512-919CtnXic52YM0zW4C1QxjG6aNueX1kBGthuMtvFtRTAxhKfJmiXC9qwHmi6o2josjbDz8QlWyY55F1SIVmCWA==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", + "@jest/test-sequencer": "^29.4.2", + "@jest/types": "^29.4.2", + "babel-jest": "^29.4.2", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-circus": "^29.4.2", + "jest-environment-node": "^29.4.2", + "jest-get-type": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-runner": "^29.4.2", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -14293,15 +14256,15 @@ } }, "jest-diff": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.4.2.tgz", + "integrity": "sha512-EK8DSajVtnjx9sa1BkjZq3mqChm2Cd8rIzdXkQMA8e0wuXq53ypz6s5o5V8HRZkoEt2ywJ3eeNWFKWeYr8HK4g==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "diff-sequences": "^29.4.2", + "jest-get-type": "^29.4.2", + "pretty-format": "^29.4.2" }, "dependencies": { "ansi-styles": { @@ -14356,25 +14319,25 @@ } }, "jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.2.tgz", + "integrity": "sha512-dV2JdahgClL34Y5vLrAHde3nF3yo2jKRH+GIYJuCpfqwEJZcikzeafVTGAjbOfKPG17ez9iWXwUYp7yefeCRag==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.4.2.tgz", + "integrity": "sha512-trvKZb0JYiCndc55V1Yh0Luqi7AsAdDWpV+mKT/5vkpnnFQfuQACV72IoRV161aAr6kAVIBpmYzwhBzm34vQkA==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.2", + "jest-util": "^29.4.2", + "pretty-format": "^29.4.2" }, "dependencies": { "ansi-styles": { @@ -14429,94 +14392,65 @@ } }, "jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.4.2.tgz", + "integrity": "sha512-MLPrqUcOnNBc8zTOfqBbxtoa8/Ee8tZ7UFW7hRDQSUT+NGsvS96wlbHGTf+EFAT9KC3VNb7fWEM6oyvmxtE/9w==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.4.2", + "@jest/fake-timers": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-mock": "^29.4.2", + "jest-util": "^29.4.2" } }, "jest-get-type": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.2.tgz", + "integrity": "sha512-vERN30V5i2N6lqlFu4ljdTqQAgrkTFMC9xaIIfOPYBw04pufjXRty5RuXBiB1d72tGbURa/UgoiHB90ruOSivg==", "dev": true }, "jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.4.2.tgz", + "integrity": "sha512-WkUgo26LN5UHPknkezrBzr7lUtV1OpGsp+NfXbBwHztsFruS3gz+AMTTBcEklvi8uPzpISzYjdKXYZQJXBnfvw==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-regex-util": "^29.4.2", + "jest-util": "^29.4.2", + "jest-worker": "^29.4.2", "micromatch": "^4.0.4", "walker": "^1.0.8" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.4.2.tgz", + "integrity": "sha512-Wa62HuRJmWXtX9F00nUpWlrbaH5axeYCdyRsOs/+Rb1Vb6+qWTlB5rKwCCRKtorM7owNwKsyJ8NRDUcZ8ghYUA==", "dev": true, "requires": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.2", + "pretty-format": "^29.4.2" } }, "jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.4.2.tgz", + "integrity": "sha512-EZaAQy2je6Uqkrm6frnxBIdaWtSYFoR8SVb2sNLAtldswlR/29JAgx+hy67llT3+hXBaLB0zAm5UfeqerioZyg==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-diff": "^29.4.2", + "jest-get-type": "^29.4.2", + "pretty-format": "^29.4.2" }, "dependencies": { "ansi-styles": { @@ -14571,18 +14505,18 @@ } }, "jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.4.2.tgz", + "integrity": "sha512-SElcuN4s6PNKpOEtTInjOAA8QvItu0iugkXqhYyguRvQoXapg5gN+9RQxLAkakChZA7Y26j6yUCsFWN+hlKD6g==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -14639,14 +14573,14 @@ } }, "jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.4.2.tgz", + "integrity": "sha512-x1FSd4Gvx2yIahdaIKoBjwji6XpboDunSJ95RpntGrYulI1ByuYQCKN/P7hvk09JB74IonU3IPLdkutEWYt++g==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/node": "*", - "jest-util": "^29.3.1" + "jest-util": "^29.4.2" } }, "jest-pnp-resolver": { @@ -14657,25 +14591,25 @@ "requires": {} }, "jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.2.tgz", + "integrity": "sha512-XYZXOqUl1y31H6VLMrrUL1ZhXuiymLKPz0BO1kEeR5xER9Tv86RZrjTm74g5l9bPJQXA/hyLdaVPN/sdqfteig==", "dev": true }, "jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.4.2.tgz", + "integrity": "sha512-RtKWW0mbR3I4UdkOrW7552IFGLYQ5AF9YrzD0FnIOkDu0rAMlA5/Y1+r7lhCAP4nXSBTaE7ueeqj6IOwZpgoqw==", "dev": true, "requires": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.4.2", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-util": "^29.4.2", + "jest-validate": "^29.4.2", "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" }, "dependencies": { @@ -14731,40 +14665,40 @@ } }, "jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.4.2.tgz", + "integrity": "sha512-6pL4ptFw62rjdrPk7rRpzJYgcRqRZNsZTF1VxVTZMishbO6ObyWvX57yHOaNGgKoADtAHRFYdHQUEvYMJATbDg==", "dev": true, "requires": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" + "jest-regex-util": "^29.4.2", + "jest-snapshot": "^29.4.2" } }, "jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.4.2.tgz", + "integrity": "sha512-wqwt0drm7JGjwdH+x1XgAl+TFPH7poowMguPQINYxaukCqlczAcNLJiK+OLxUxQAEWMdy+e6nHZlFHO5s7EuRg==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.4.2", + "@jest/environment": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-docblock": "^29.4.2", + "jest-environment-node": "^29.4.2", + "jest-haste-map": "^29.4.2", + "jest-leak-detector": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-runtime": "^29.4.2", + "jest-util": "^29.4.2", + "jest-watcher": "^29.4.2", + "jest-worker": "^29.4.2", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -14809,29 +14743,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-worker": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.3.1", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -14863,31 +14774,32 @@ } }, "jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", - "dev": true, - "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.4.2.tgz", + "integrity": "sha512-3fque9vtpLzGuxT9eZqhxi+9EylKK/ESfhClv4P7Y9sqJPs58LjVhTt8jaMp/pRO38agll1CkSu9z9ieTQeRrw==", + "dev": true, + "requires": { + "@jest/environment": "^29.4.2", + "@jest/fake-timers": "^29.4.2", + "@jest/globals": "^29.4.2", + "@jest/source-map": "^29.4.2", + "@jest/test-result": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-mock": "^29.4.2", + "jest-regex-util": "^29.4.2", + "jest-resolve": "^29.4.2", + "jest-snapshot": "^29.4.2", + "jest-util": "^29.4.2", + "semver": "^7.3.5", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -14932,6 +14844,15 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -14944,9 +14865,9 @@ } }, "jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.4.2.tgz", + "integrity": "sha512-PdfubrSNN5KwroyMH158R23tWcAXJyx4pvSvWls1dHoLCaUhGul9rsL3uVjtqzRpkxlkMavQjGuWG1newPgmkw==", "dev": true, "requires": { "@babel/core": "^7.11.6", @@ -14955,23 +14876,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/expect-utils": "^29.4.2", + "@jest/transform": "^29.4.2", + "@jest/types": "^29.4.2", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.3.1", + "expect": "^29.4.2", "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-diff": "^29.4.2", + "jest-get-type": "^29.4.2", + "jest-haste-map": "^29.4.2", + "jest-matcher-utils": "^29.4.2", + "jest-message-util": "^29.4.2", + "jest-util": "^29.4.2", "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.4.2", "semver": "^7.3.5" }, "dependencies": { @@ -15036,12 +14957,12 @@ } }, "jest-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.4.2.tgz", + "integrity": "sha512-wKnm6XpJgzMUSRFB7YF48CuwdzuDIHenVuoIb1PLuJ6F+uErZsuDkU+EiExkChf6473XcawBrSfDSnXl+/YG4g==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -15101,17 +15022,17 @@ } }, "jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.4.2.tgz", + "integrity": "sha512-tto7YKGPJyFbhcKhIDFq8B5od+eVWD/ySZ9Tvcp/NGCvYA4RQbuzhbwYWtIjMT5W5zA2W0eBJwu4HVw34d5G6Q==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.4.2", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", + "jest-get-type": "^29.4.2", "leven": "^3.1.0", - "pretty-format": "^29.3.1" + "pretty-format": "^29.4.2" }, "dependencies": { "ansi-styles": { @@ -15172,18 +15093,18 @@ } }, "jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.4.2.tgz", + "integrity": "sha512-onddLujSoGiMJt+tKutehIidABa175i/Ays+QvKxCqBwp7fvxP3ZhKsrIdOodt71dKxqk4sc0LN41mWLGIK44w==", "dev": true, "requires": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/test-result": "^29.4.2", + "@jest/types": "^29.4.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.3.1", + "jest-util": "^29.4.2", "string-length": "^4.0.1" }, "dependencies": { @@ -15238,6 +15159,35 @@ } } }, + "jest-worker": { + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.4.2.tgz", + "integrity": "sha512-VIuZA2hZmFyRbchsUCHEehoSf2HEl0YVF8SDJqtPnKorAaBuh42V8QsLnde0XP5F6TyCynGPEGgBOn3Fc+wZGw==", + "dev": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.4.2", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -15580,12 +15530,12 @@ "dev": true }, "magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", "dev": true, "requires": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.13" } }, "make-dir": { @@ -15924,9 +15874,9 @@ "dev": true }, "prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true }, "prettier-linter-helpers": { @@ -15939,12 +15889,12 @@ } }, "pretty-format": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "version": "29.4.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", + "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", "dev": true, "requires": { - "@jest/schemas": "^29.0.0", + "@jest/schemas": "^29.4.2", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -16040,9 +15990,9 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, "queue-microtask": { @@ -16200,9 +16150,9 @@ "dev": true }, "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.0.tgz", + "integrity": "sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==", "dev": true }, "reusify": { @@ -16231,9 +16181,9 @@ } }, "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.15.0.tgz", + "integrity": "sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -16431,12 +16381,6 @@ "source-map": "^0.6.0" } }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, "spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -16609,15 +16553,15 @@ } }, "ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "requires": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -16706,9 +16650,9 @@ "dev": true }, "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, "unicode-canonical-property-names-ecmascript": { diff --git a/package.json b/package.json index 2208ec4b..7b7127c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openmined/psi.js", - "version": "1.1.1", + "version": "2.0.0", "description": "Private Set Intersection for JavaScript", "repository": { "type": "git", @@ -42,42 +42,42 @@ "coverage": "jest private_set_intersection/javascript/src --coverage" }, "devDependencies": { - "@babel/core": "^7.20.5", - "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/core": "^7.20.12", + "@babel/plugin-transform-modules-commonjs": "^7.20.11", "@babel/preset-env": "^7.20.2", "@bazel/bazelisk": "^1.7.5", "@bazel/typescript": "^5.7.3", - "@rollup/plugin-alias": "^4.0.2", - "@rollup/plugin-commonjs": "^23.0.4", - "@rollup/plugin-json": "^5.0.2", + "@rollup/plugin-alias": "^4.0.3", + "@rollup/plugin-commonjs": "^24.0.1", + "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.1", - "@rollup/plugin-replace": "^5.0.1", - "@rollup/plugin-terser": "^0.2.0", - "@rollup/plugin-typescript": "^10.0.1", + "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-terser": "^0.4.0", + "@rollup/plugin-typescript": "^11.0.0", "@types/google-protobuf": "^3.15.6", - "@types/jest": "^29.2.4", - "@types/node": "^18.11.13", - "@typescript-eslint/eslint-plugin": "^5.46.0", - "@typescript-eslint/parser": "^5.46.0", + "@types/jest": "^29.4.0", + "@types/node": "^18.13.0", + "@typescript-eslint/eslint-plugin": "^5.52.0", + "@typescript-eslint/parser": "^5.52.0", "buffer": "^6.0.3", - "eslint": "^8.29.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-jest": "^27.1.6", - "eslint-plugin-jsdoc": "^39.6.4", + "eslint": "^8.34.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-jsdoc": "^40.0.0", "eslint-plugin-prettier": "^4.2.1", "esm": "^3.2.25", - "jest": "^29.3.1", + "jest": "^29.4.2", "path": "^0.12.7", - "prettier": "^2.8.1", - "rollup": "^2.32.1", + "prettier": "^2.8.4", + "rollup": "^3.15.0", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-typescript2": "^0.34.1", - "ts-jest": "^29.0.3", - "typescript": "^4.9.4" + "ts-jest": "^29.0.5", + "typescript": "^4.9.5" }, "dependencies": { - "@grpc/grpc-js": "^1.8.4", + "@grpc/grpc-js": "^1.8.8", "google-protobuf": "^3.21.2", "ts-protoc-gen": "^0.15.0" } diff --git a/private_set_intersection/c/BUILD b/private_set_intersection/c/BUILD index 6c5ee422..9f3bd007 100644 --- a/private_set_intersection/c/BUILD +++ b/private_set_intersection/c/BUILD @@ -25,17 +25,8 @@ cc_library( ], ) -cc_test( - name = "c_package_test", - srcs = ["package_test.cpp"], - deps = [ - ":c_package", - "@com_google_googletest//:gtest_main", - ], -) - cc_library( - name = "internal_utils", + name = "c_internal_utils", srcs = ["internal_utils.cpp"], hdrs = ["internal_utils.h"], visibility = ["//visibility:private"], @@ -49,22 +40,9 @@ cc_library( srcs = ["psi_client.cpp"], hdrs = ["psi_client.h"], deps = [ - "//private_set_intersection/c:internal_utils", + ":c_internal_utils", "//private_set_intersection/cpp:psi_client", - ], -) - -cc_test( - name = "c_psi_client_test", - srcs = ["psi_client_test.cpp"], - deps = [ - ":c_psi_client", - "//private_set_intersection/cpp/util:status_matchers", - "@com_google_absl//absl/container:flat_hash_set", - "@com_google_absl//absl/strings", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - "@private_join_and_compute//private_join_and_compute/crypto:ec_commutative_cipher", + "//private_set_intersection/cpp/datastructure", ], ) @@ -73,15 +51,17 @@ cc_library( srcs = ["psi_server.cpp"], hdrs = ["psi_server.h"], deps = [ - "//private_set_intersection/c:internal_utils", + ":c_internal_utils", "//private_set_intersection/cpp:psi_server", + "//private_set_intersection/cpp/datastructure", ], ) cc_test( - name = "c_psi_server_test", - srcs = ["psi_server_test.cpp"], + name = "c_integration_test", + srcs = ["integration_test.cpp"], deps = [ + ":c_package", ":c_psi_client", ":c_psi_server", "//private_set_intersection/cpp/util:status_matchers", diff --git a/private_set_intersection/c/integration_test.cpp b/private_set_intersection/c/integration_test.cpp new file mode 100644 index 00000000..cadfee11 --- /dev/null +++ b/private_set_intersection/c/integration_test.cpp @@ -0,0 +1,239 @@ +// +// Copyright 2020 the authors listed in CONTRIBUTORS.md +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "absl/container/flat_hash_set.h" +#include "absl/strings/str_cat.h" +#include "gtest/gtest.h" +#include "private_join_and_compute/crypto/ec_commutative_cipher.h" +#include "private_set_intersection/c/package.h" +#include "private_set_intersection/c/psi_client.h" +#include "private_set_intersection/c/psi_server.h" +#include "private_set_intersection/cpp/datastructure/datastructure.h" +#include "util/status_matchers.h" + +namespace private_set_intersection { + +namespace { + +static const char client_key_buff[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; +psi_client_buffer_t client_key{*(&client_key_buff), sizeof(client_key_buff)}; + +static const char server_key_buff[32] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}; +psi_server_buffer_t server_key{*(&server_key_buff), sizeof(server_key_buff)}; + +const int num_client_inputs = 10, num_server_inputs = 100; +const double fpr = 0.01; +std::vector client_orig_elements(num_client_inputs); +std::vector client_inputs(num_client_inputs); +std::vector server_orig_elements(num_server_inputs); +std::vector server_inputs(num_server_inputs); + +TEST(PackageTest, testVersionFormat) { + // The regex represents Semantic Versioning syntax (www.semver.org), + // i.e. three dot-separated numbers, with an optional suffix + // that starts with a hyphen, to cover alpha/beta releases and + // release candiates, for example: + // 1.2.3 + // 1.2.3-beta + // 1.2.3-RC1 + std::string version_regex = "[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9]+)?"; +#ifdef GTEST_USES_POSIX_RE + EXPECT_THAT(psi_version(), testing::MatchesRegex(version_regex)); +#else + EXPECT_TRUE(std::regex_match(psi_version(), std::regex(version_regex))); +#endif +} + +class Correctness + : public ::testing::TestWithParam> { + protected: + void SetUp() { + // Create elements, such that 50% of the client's elements overlap with the + // server. + for (int i = 0; i < num_client_inputs; i++) { + client_orig_elements[i] = absl::StrCat("Element ", i); + client_inputs[i] = {client_orig_elements[i].c_str(), + client_orig_elements[i].size()}; + } + for (int i = 0; i < num_server_inputs; i++) { + server_orig_elements[i] = absl::StrCat("Element ", i * 2); + server_inputs[i] = {server_orig_elements[i].c_str(), + server_orig_elements[i].size()}; + } + } + void TearDown() {} +}; + +TEST_F(Correctness, TestCreatingFromKey) { + psi_client_ctx client2; + psi_server_ctx server2; + char *err; + int ok = 99; + ok = psi_client_create_from_key(client_key, false, &client2, &err); + ASSERT_TRUE(client2 != nullptr); + ASSERT_TRUE(ok == 0); + + ok = psi_server_create_from_key(server_key, false, &server2, &err); + ASSERT_TRUE(server2 != nullptr); + ASSERT_TRUE(ok == 0); + + char *client_key_buff2 = {0}; + size_t key_len = 0; + + ok = psi_client_get_private_key_bytes(client2, &client_key_buff2, &key_len, + &err); + ASSERT_TRUE(client_key_buff2 != nullptr); + ASSERT_TRUE(ok == 0); + ASSERT_TRUE(strncmp(client_key.buff, client_key_buff2, client_key.buff_len) == + 0); + EXPECT_EQ(key_len, 32); + free(client_key_buff2); + + char *server_key_buff2 = {0}; + key_len = 0; + + ok = psi_server_get_private_key_bytes(server2, &server_key_buff2, &key_len, + &err); + ASSERT_TRUE(server_key_buff != nullptr); + ASSERT_TRUE(ok == 0); + ASSERT_TRUE(strncmp(server_key.buff, server_key_buff2, server_key.buff_len) == + 0); + EXPECT_EQ(key_len, 32); + free(server_key_buff2); +} + +INSTANTIATE_TEST_CASE_P( + Integration, Correctness, + testing::Combine(testing::Values(true, false), + testing::Values(DataStructure::Raw, DataStructure::Gcs, + DataStructure::BloomFilter)), + [](const testing::TestParamInfo &info) { + bool reveal_intersection = std::get<0>(info.param); + DataStructure ds = std::get<1>(info.param); + std::string ds_name; + switch (ds) { + case DataStructure::Raw: + ds_name = "raw"; + break; + case DataStructure::Gcs: + ds_name = "gcs"; + break; + case DataStructure::BloomFilter: + ds_name = "bloomfilter"; + break; + default: { + throw std::logic_error("Bad enum variant"); + } + } + + return absl::StrCat(reveal_intersection ? "true_" : "false_", ds_name); + }); + +TEST_P(Correctness, intersection) { + bool reveal_intersection = std::get<0>(GetParam()); + DataStructure ds = std::get<1>(GetParam()); + + psi_client_ctx client; + psi_server_ctx server; + char *err; + + int ok = psi_client_create_from_key(client_key, reveal_intersection, &client, + &err); + ASSERT_TRUE(client != nullptr); + ASSERT_TRUE(ok == 0); + + ok = psi_server_create_from_key(server_key, reveal_intersection, &server, + &err); + ASSERT_TRUE(server != nullptr); + ASSERT_TRUE(ok == 0); + + // Run Server setup. + char *server_setup = nullptr; + size_t server_setup_buff_len = 0; + psi_server_create_setup_message( + server, fpr, num_client_inputs, server_inputs.data(), + server_inputs.size(), &server_setup, &server_setup_buff_len, &err, ds); + + ASSERT_TRUE(server_setup != nullptr); + ASSERT_TRUE(server_setup_buff_len != 0); + + // Create Client request. + char *client_request = {0}; + size_t req_len = 0; + ok = psi_client_create_request(client, client_inputs.data(), + client_inputs.size(), &client_request, + &req_len, &err); + + ASSERT_TRUE(ok == 0); + ASSERT_TRUE(req_len > 0); + ASSERT_TRUE(client_request != nullptr); + + // Create Server response. + char *server_response = nullptr; + size_t response_len = 0; + ok = psi_server_process_request(server, {client_request, req_len}, + &server_response, &response_len, &err); + ASSERT_TRUE(server_response != nullptr); + ASSERT_TRUE(response_len >= 0); + ASSERT_TRUE(ok == 0); + + if (reveal_intersection) { + // Compute intersection. + int64_t *intersection; + size_t intersect_len; + psi_client_get_intersection(client, {server_setup, server_setup_buff_len}, + {server_response, response_len}, &intersection, + &intersect_len, &err); + + absl::flat_hash_set intersection_set(intersection, + intersection + intersect_len); + + // Test if all even elements are present. + for (int i = 0; i < num_client_inputs; i++) { + if (i % 2) { + EXPECT_FALSE(intersection_set.contains(i)); + } else { + EXPECT_TRUE(intersection_set.contains(i)); + } + } + + } else { + // Compute intersection size. + int64_t intersection_size = 0; + psi_client_get_intersection_size( + client, {server_setup, server_setup_buff_len}, + {server_response, response_len}, &intersection_size, &err); + + // Test if size is approximately as expected (up to 10%). + EXPECT_GE(intersection_size, num_client_inputs / 2); + EXPECT_LT(intersection_size, (num_client_inputs / 2) * 1.1); + } + free(server_setup); + free(client_request); + free(server_response); + + psi_server_delete(&server); + ASSERT_TRUE(server == nullptr); + psi_client_delete(&client); + ASSERT_TRUE(client == nullptr); +} + +} // namespace +} // namespace private_set_intersection diff --git a/private_set_intersection/c/package_test.cpp b/private_set_intersection/c/package_test.cpp deleted file mode 100644 index d4dc6943..00000000 --- a/private_set_intersection/c/package_test.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright 2020 the authors listed in CONTRIBUTORS.md -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "private_set_intersection/c/package.h" - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace private_set_intersection { -namespace { - -TEST(PackageTest, testVersionFormat) { - // The regex represents Semantic Versioning syntax (www.semver.org), - // i.e. three dot-separated numbers, with an optional suffix - // that starts with a hyphen, to cover alpha/beta releases and - // release candiates, for example: - // 1.2.3 - // 1.2.3-beta - // 1.2.3-RC1 - std::string version_regex = "[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9]+)?"; -#ifdef GTEST_USES_POSIX_RE - EXPECT_THAT(psi_version(), testing::MatchesRegex(version_regex)); -#else - EXPECT_TRUE(std::regex_match(psi_version(), std::regex(version_regex))); -#endif -} - -} // namespace -} // namespace private_set_intersection diff --git a/private_set_intersection/c/psi_benchmark.cpp b/private_set_intersection/c/psi_benchmark.cpp index 5c9cbd44..a7acc771 100644 --- a/private_set_intersection/c/psi_benchmark.cpp +++ b/private_set_intersection/c/psi_benchmark.cpp @@ -2,6 +2,7 @@ #include "benchmark/benchmark.h" #include "private_set_intersection/c/psi_client.h" #include "private_set_intersection/c/psi_server.h" +#include "private_set_intersection/cpp/datastructure/datastructure.h" namespace private_set_intersection { namespace { @@ -26,9 +27,9 @@ void BM_ServerSetup(benchmark::State &state, double fpr, for (auto _ : state) { char *server_setup = nullptr; size_t server_setup_buff_len = 0; - psi_server_create_setup_message(server_, fpr, num_client_inputs, - inputs.data(), inputs.size(), &server_setup, - &server_setup_buff_len, &err); + psi_server_create_setup_message( + server_, fpr, num_client_inputs, inputs.data(), inputs.size(), + &server_setup, &server_setup_buff_len, &err, DataStructure::Gcs); ::benchmark::DoNotOptimize(server_setup); ::benchmark::ClobberMemory(); @@ -176,9 +177,9 @@ void BM_ClientProcessResponse(benchmark::State &state, char *server_setup = nullptr; size_t server_setup_buff_len = 0; - psi_server_create_setup_message(server_, fpr, num_inputs, srv_inputs.data(), - srv_inputs.size(), &server_setup, - &server_setup_buff_len, &err); + psi_server_create_setup_message( + server_, fpr, num_inputs, srv_inputs.data(), srv_inputs.size(), + &server_setup, &server_setup_buff_len, &err, DataStructure::Gcs); char *client_request = nullptr; size_t req_len = 0; diff --git a/private_set_intersection/c/psi_client_test.cpp b/private_set_intersection/c/psi_client_test.cpp deleted file mode 100644 index 10502433..00000000 --- a/private_set_intersection/c/psi_client_test.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// -// Copyright 2020 the authors listed in CONTRIBUTORS.md -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "private_set_intersection/c/psi_client.h" - -#include "absl/container/flat_hash_set.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "gtest/gtest.h" -#include "private_join_and_compute/crypto/ec_commutative_cipher.h" -#include "private_set_intersection/c/internal_utils.h" -#include "private_set_intersection/cpp/bloom_filter.h" -#include "util/status_matchers.h" - -namespace private_set_intersection { -namespace { - -class PsiClientTest : public ::testing::Test { - protected: - void SetUp() {} - void TearDown() {} -}; - -void test_corectness(bool reveal_intersection) { - psi_client_ctx client; - - char *err; - int ret = psi_client_create_with_new_key(reveal_intersection, &client, &err); - ASSERT_TRUE(client != nullptr); - ASSERT_TRUE(ret == 0); - constexpr int num_client_elements = 1000, num_server_elements = 10000; - double fpr = 0.01; - std::vector client_elements(num_client_elements); - std::vector client_orig_elements(num_client_elements); - std::vector server_elements(num_server_elements); - - // Create elements, such that 50% of the client's elements overlap with the - // server. - for (int i = 0; i < num_client_elements; i++) { - client_orig_elements[i] = absl::StrCat("Element ", i); - client_elements[i] = {client_orig_elements[i].c_str(), - client_orig_elements[i].size()}; - } - for (int i = 0; i < num_server_elements; i++) { - server_elements[i] = absl::StrCat("Element ", 2 * i); - } - - // Insert server elements into Bloom filter. - PSI_ASSERT_OK_AND_ASSIGN( - auto bloom_filter, - BloomFilter::CreateEmpty(fpr / num_client_elements, num_server_elements)); - - PSI_ASSERT_OK_AND_ASSIGN( - auto server_ec_cipher, - ::private_join_and_compute::ECCommutativeCipher::CreateWithNewKey( - NID_X9_62_prime256v1, - ::private_join_and_compute::ECCommutativeCipher::HashType::SHA256)); - for (int i = 0; i < num_server_elements; i++) { - PSI_ASSERT_OK_AND_ASSIGN(std::string encrypted_element, - server_ec_cipher->Encrypt(server_elements[i])); - - bloom_filter->Add(encrypted_element); - } - - auto server_setup = bloom_filter->ToProtobuf(); - - // Compute client request. - char *client_request = {0}; - size_t req_len = 0; - ret = psi_client_create_request(client, client_elements.data(), - client_elements.size(), &client_request, - &req_len, &err); - - ASSERT_TRUE(ret == 0) << err; - ASSERT_TRUE(req_len > 0); - ASSERT_TRUE(client_request != nullptr); - - psi_proto::Request request_proto; - ASSERT_TRUE(request_proto.ParseFromArray(client_request, req_len)); - - // Re-encrypt elements. - const auto &encrypted_elements = request_proto.encrypted_elements(); - - // Create the response - psi_proto::Response response; - - // Re-encrypt the request's elements and add to the response - for (int i = 0; i < num_client_elements; i++) { - PSI_ASSERT_OK_AND_ASSIGN(std::string encrypted, server_ec_cipher->ReEncrypt( - encrypted_elements[i])); - response.add_encrypted_elements(encrypted); - } - - std::string server_response_str, server_setup_str; - ASSERT_TRUE(response.SerializeToString(&server_response_str)); - ASSERT_TRUE(server_setup.SerializeToString(&server_setup_str)); - - // Compute intersection. - if (reveal_intersection) { - int64_t *intersection; - size_t intersectlen; - psi_client_get_intersection( - client, {server_setup_str.c_str(), server_setup_str.size()}, - {server_response_str.c_str(), server_response_str.size()}, - &intersection, &intersectlen, &err); - - absl::flat_hash_set intersection_set(intersection, - intersection + intersectlen); - - // Test if all even elements are present. - for (int i = 0; i < num_client_elements; i++) { - if (i % 2) { - EXPECT_FALSE(intersection_set.contains(i)); - } else { - EXPECT_TRUE(intersection_set.contains(i)); - } - } - } else { - int64_t intersection_size = 0; - ret = psi_client_get_intersection_size( - client, {server_setup_str.c_str(), server_setup_str.size()}, - {server_response_str.c_str(), server_response_str.size()}, - &intersection_size, &err); - ASSERT_TRUE(ret == 0) << err; - ASSERT_TRUE(intersection_size > 0); - // Test if size is approximately as expected (up to 10%). - - EXPECT_GE(intersection_size, num_client_elements / 2); - EXPECT_LT(intersection_size, (num_client_elements / 2) * 1.1); - } - free(client_request); - - psi_client_delete(&client); - - ASSERT_TRUE(client == nullptr); -} -TEST_F(PsiClientTest, TestCorrectnessSize) { test_corectness(false); } -TEST_F(PsiClientTest, TestCorrectness) { test_corectness(true); } - -} // namespace -} // namespace private_set_intersection diff --git a/private_set_intersection/c/psi_server.cpp b/private_set_intersection/c/psi_server.cpp index 73101ced..432ba1df 100644 --- a/private_set_intersection/c/psi_server.cpp +++ b/private_set_intersection/c/psi_server.cpp @@ -3,9 +3,11 @@ #include #include "private_set_intersection/c/internal_utils.h" +#include "private_set_intersection/cpp/datastructure/datastructure.h" #include "private_set_intersection/cpp/psi_server.h" namespace { +using private_set_intersection::DataStructure; using private_set_intersection::PsiServer; using private_set_intersection::c_bindings_internal::generate_error; } // namespace @@ -42,11 +44,11 @@ void psi_server_delete(psi_server_ctx *ctx) { *ctx = nullptr; } -int psi_server_create_setup_message(psi_server_ctx ctx, double fpr, - int64_t num_client_inputs, - psi_server_buffer_t *input, - size_t input_len, char **output, - size_t *output_len, char **error_out) { +int psi_server_create_setup_message( + psi_server_ctx ctx, double fpr, int64_t num_client_inputs, + psi_server_buffer_t *input, size_t input_len, char **output, + size_t *output_len, char **error_out, + private_set_intersection::datastructure_t datastructure) { auto server = static_cast(ctx); if (server == nullptr) { return generate_error(absl::InvalidArgumentError("invalid server context"), @@ -58,7 +60,8 @@ int psi_server_create_setup_message(psi_server_ctx ctx, double fpr, in.push_back(std::string(input[idx].buff, input[idx].buff_len)); } - auto result = server->CreateSetupMessage(fpr, num_client_inputs, in); + auto result = + server->CreateSetupMessage(fpr, num_client_inputs, in, datastructure); if (!result.ok()) { return generate_error(result.status(), error_out); } diff --git a/private_set_intersection/c/psi_server.h b/private_set_intersection/c/psi_server.h index f52fb2b8..5bbf6951 100644 --- a/private_set_intersection/c/psi_server.h +++ b/private_set_intersection/c/psi_server.h @@ -21,8 +21,13 @@ #include #include +#include "private_set_intersection/cpp/datastructure/datastructure.h" + #ifdef __cplusplus extern "C" { +namespace { +using private_set_intersection::datastructure_t; +} // namespace #endif typedef void *psi_server_ctx; @@ -43,7 +48,8 @@ int psi_server_create_setup_message(psi_server_ctx ctx, double fpr, int64_t num_client_inputs, struct psi_server_buffer_t *input, size_t input_len, char **output, - size_t *output_len, char **error_out); + size_t *output_len, char **error_out, + datastructure_t ds); int psi_server_process_request(psi_server_ctx ctx, struct psi_server_buffer_t client_request, diff --git a/private_set_intersection/c/psi_server_test.cpp b/private_set_intersection/c/psi_server_test.cpp deleted file mode 100644 index 1acb0c0d..00000000 --- a/private_set_intersection/c/psi_server_test.cpp +++ /dev/null @@ -1,139 +0,0 @@ -// -// Copyright 2020 the authors listed in CONTRIBUTORS.md -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include "private_set_intersection/c/psi_server.h" - -#include "absl/container/flat_hash_set.h" -#include "absl/strings/str_cat.h" -#include "gtest/gtest.h" -#include "private_join_and_compute/crypto/ec_commutative_cipher.h" -#include "private_set_intersection/c/psi_client.h" -#include "util/status_matchers.h" - -namespace private_set_intersection { -namespace { - -class PsiServerTest : public ::testing::Test { - protected: - void SetUp() {} - void TearDown() {} -}; - -void test_correctness(bool reveal_intersection) { - psi_server_ctx server; - char *err; - int ret = psi_server_create_with_new_key(reveal_intersection, &server, &err); - ASSERT_TRUE(server != nullptr); - ASSERT_TRUE(ret == 0); - psi_client_ctx client; - psi_client_create_with_new_key(reveal_intersection, &client, &err); - - ASSERT_TRUE(client != nullptr); - - int num_client_elements = 1000, num_server_elements = 10000; - double fpr = 0.01; - std::vector client_orig_elements(num_client_elements); - std::vector client_elements(num_client_elements); - std::vector server_orig_elements(num_server_elements); - std::vector server_elements(num_server_elements); - - // Create elements, such that 50% of the client's elements overlap with the - // server. - for (int i = 0; i < num_client_elements; i++) { - client_orig_elements[i] = absl::StrCat("Element ", i); - client_elements[i] = {client_orig_elements[i].c_str(), - client_orig_elements[i].size()}; - } - for (int i = 0; i < num_server_elements; i++) { - server_orig_elements[i] = absl::StrCat("Element ", 2 * i); - server_elements[i] = {server_orig_elements[i].c_str(), - server_orig_elements[i].size()}; - } - - // Run Server setup. - char *server_setup = nullptr; - size_t server_setup_buff_len = 0; - psi_server_create_setup_message( - server, fpr, num_client_elements, server_elements.data(), - server_elements.size(), &server_setup, &server_setup_buff_len, &err); - - ASSERT_TRUE(server_setup != nullptr); - ASSERT_TRUE(server_setup_buff_len != 0); - - // Create Client request. - char *client_request = {0}; - size_t req_len = 0; - ret = psi_client_create_request(client, client_elements.data(), - client_elements.size(), &client_request, - &req_len, &err); - - ASSERT_TRUE(ret == 0); - ASSERT_TRUE(req_len > 0); - ASSERT_TRUE(client_request != nullptr); - - // Create Server response. - char *server_response = nullptr; - size_t response_len = 0; - ret = psi_server_process_request(server, {client_request, req_len}, - &server_response, &response_len, &err); - ASSERT_TRUE(server_response != nullptr); - ASSERT_TRUE(response_len >= 0); - ASSERT_TRUE(ret == 0); - - if (reveal_intersection) { - // Compute intersection. - int64_t *intersection; - size_t intersectlen; - psi_client_get_intersection(client, {server_setup, server_setup_buff_len}, - {server_response, response_len}, &intersection, - &intersectlen, &err); - - absl::flat_hash_set intersection_set(intersection, - intersection + intersectlen); - - // Test if all even elements are present. - for (int i = 0; i < num_client_elements; i++) { - if (i % 2) { - EXPECT_FALSE(intersection_set.contains(i)); - } else { - EXPECT_TRUE(intersection_set.contains(i)); - } - } - - } else { - // Compute intersection size. - int64_t intersection_size = 0; - psi_client_get_intersection_size( - client, {server_setup, server_setup_buff_len}, - {server_response, response_len}, &intersection_size, &err); - - // Test if size is approximately as expected (up to 10%). - EXPECT_GE(intersection_size, num_client_elements / 2); - EXPECT_LT(intersection_size, (num_client_elements / 2) * 1.1); - } - free(server_setup); - free(server_response); - free(client_request); - - psi_server_delete(&server); - ASSERT_TRUE(server == nullptr); -} - -TEST_F(PsiServerTest, TestCorrectnessSize) { test_correctness(false); } - -TEST_F(PsiServerTest, TestCorrectnessIntersection) { test_correctness(true); } -} // namespace -} // namespace private_set_intersection diff --git a/private_set_intersection/cpp/BUILD b/private_set_intersection/cpp/BUILD index 71279447..8080b1f7 100644 --- a/private_set_intersection/cpp/BUILD +++ b/private_set_intersection/cpp/BUILD @@ -52,92 +52,16 @@ cc_test( ], ) -cc_library( - name = "golomb", - srcs = ["golomb.cpp"], - hdrs = ["golomb.h"], - visibility = ["//visibility:private"], -) - -cc_test( - name = "golomb_test", - srcs = ["golomb_test.cpp"], - linkopts = PSI_LINKOPTS, - deps = [ - ":golomb", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "gcs", - srcs = ["gcs.cpp"], - hdrs = ["gcs.h"], - visibility = ["//visibility:private"], - deps = [ - ":golomb", - "//private_set_intersection/proto:psi_cc_proto", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - "@private_join_and_compute//private_join_and_compute/crypto:bn_util", - ], -) - -cc_test( - name = "gcs_test", - srcs = ["gcs_test.cpp"], - linkopts = PSI_LINKOPTS, - deps = [ - ":gcs", - "//private_set_intersection/cpp/util:status_matchers", - "//private_set_intersection/proto:psi_cc_proto", - "@com_google_absl//absl/container:flat_hash_set", - "@com_google_absl//absl/strings", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - -cc_library( - name = "bloom_filter", - srcs = ["bloom_filter.cpp"], - hdrs = ["bloom_filter.h"], - visibility = ["//visibility:private"], - deps = [ - "//private_set_intersection/proto:psi_cc_proto", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:span", - "@private_join_and_compute//private_join_and_compute/crypto:bn_util", - ], -) - -cc_test( - name = "bloom_filter_test", - srcs = ["bloom_filter_test.cpp"], - linkopts = PSI_LINKOPTS, - deps = [ - ":bloom_filter", - "//private_set_intersection/cpp/util:status_matchers", - "//private_set_intersection/proto:psi_cc_proto", - "@com_google_absl//absl/strings", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - cc_library( name = "psi_client", srcs = ["psi_client.cpp"], hdrs = ["psi_client.h"], includes = ["."], deps = [ - ":bloom_filter", - ":gcs", + "//private_set_intersection/cpp/datastructure", + "//private_set_intersection/cpp/datastructure:bloom_filter", + "//private_set_intersection/cpp/datastructure:gcs", + "//private_set_intersection/cpp/datastructure:raw", "//private_set_intersection/proto:psi_cc_proto", "@boringssl//:crypto", "@com_google_absl//absl/memory", @@ -166,11 +90,15 @@ cc_test( cc_library( name = "psi_server", srcs = ["psi_server.cpp"], - hdrs = ["psi_server.h"], + hdrs = [ + "psi_server.h", + ], includes = ["."], deps = [ - ":bloom_filter", - ":gcs", + "//private_set_intersection/cpp/datastructure", + "//private_set_intersection/cpp/datastructure:bloom_filter", + "//private_set_intersection/cpp/datastructure:gcs", + "//private_set_intersection/cpp/datastructure:raw", "//private_set_intersection/proto:psi_cc_proto", "@boringssl//:crypto", "@com_google_absl//absl/memory", diff --git a/private_set_intersection/cpp/datastructure/BUILD b/private_set_intersection/cpp/datastructure/BUILD new file mode 100644 index 00000000..fc8cbda5 --- /dev/null +++ b/private_set_intersection/cpp/datastructure/BUILD @@ -0,0 +1,136 @@ +# +# Copyright 2020 the authors listed in CONTRIBUTORS.md +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package(default_visibility = ["//visibility:public"]) + +PSI_LINKOPTS = select({ + "@platforms//os:osx": [], + "//conditions:default": [ + # Needed on some Linux systems. See also + # https://github.com/google/cctz/issues/47 + # https://github.com/tensorflow/tensorflow/issues/15129 + "-lrt", + ], +}) + +cc_library( + name = "datastructure", + hdrs = ["datastructure.h"], +) + +cc_library( + name = "golomb", + srcs = ["golomb.cpp"], + hdrs = ["golomb.h"], + visibility = ["//visibility:private"], +) + +cc_test( + name = "golomb_test", + srcs = ["golomb_test.cpp"], + linkopts = PSI_LINKOPTS, + deps = [ + ":golomb", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "gcs", + srcs = ["gcs.cpp"], + hdrs = ["gcs.h"], + deps = [ + ":golomb", + "//private_set_intersection/proto:psi_cc_proto", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:span", + "@private_join_and_compute//private_join_and_compute/crypto:bn_util", + ], +) + +cc_test( + name = "gcs_test", + srcs = ["gcs_test.cpp"], + linkopts = PSI_LINKOPTS, + deps = [ + ":gcs", + "//private_set_intersection/cpp/util:status_matchers", + "//private_set_intersection/proto:psi_cc_proto", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "bloom_filter", + srcs = ["bloom_filter.cpp"], + hdrs = ["bloom_filter.h"], + deps = [ + "//private_set_intersection/proto:psi_cc_proto", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:span", + "@private_join_and_compute//private_join_and_compute/crypto:bn_util", + ], +) + +cc_test( + name = "bloom_filter_test", + srcs = ["bloom_filter_test.cpp"], + linkopts = PSI_LINKOPTS, + deps = [ + ":bloom_filter", + "//private_set_intersection/cpp/util:status_matchers", + "//private_set_intersection/proto:psi_cc_proto", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "raw", + srcs = ["raw.cpp"], + hdrs = ["raw.h"], + deps = [ + "//private_set_intersection/proto:psi_cc_proto", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:span", + "@private_join_and_compute//private_join_and_compute/crypto:bn_util", + ], +) + +cc_test( + name = "raw_test", + srcs = ["raw_test.cpp"], + linkopts = PSI_LINKOPTS, + deps = [ + ":raw", + "//private_set_intersection/cpp/util:status_matchers", + "//private_set_intersection/proto:psi_cc_proto", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/private_set_intersection/cpp/bloom_filter.cpp b/private_set_intersection/cpp/datastructure/bloom_filter.cpp similarity index 94% rename from private_set_intersection/cpp/bloom_filter.cpp rename to private_set_intersection/cpp/datastructure/bloom_filter.cpp index 6cfc6e51..bfe6930f 100644 --- a/private_set_intersection/cpp/bloom_filter.cpp +++ b/private_set_intersection/cpp/datastructure/bloom_filter.cpp @@ -14,7 +14,7 @@ // limitations under the License. // -#include "private_set_intersection/cpp/bloom_filter.h" +#include "private_set_intersection/cpp/datastructure/bloom_filter.h" #include @@ -71,9 +71,9 @@ StatusOr> BloomFilter::CreateFromProtobuf( } auto context = absl::make_unique<::private_join_and_compute::Context>(); - return absl::WrapUnique( - new BloomFilter(encoded_filter.bloom_filter().num_hash_functions(), - std::move(encoded_filter.bits()), std::move(context))); + return absl::WrapUnique(new BloomFilter( + encoded_filter.bloom_filter().num_hash_functions(), + std::move(encoded_filter.bloom_filter().bits()), std::move(context))); } void BloomFilter::Add(const std::string& input) { @@ -113,7 +113,7 @@ psi_proto::ServerSetup BloomFilter::ToProtobuf() const { psi_proto::ServerSetup server_setup; server_setup.mutable_bloom_filter()->set_num_hash_functions( NumHashFunctions()); - server_setup.set_bits(bits_); + server_setup.mutable_bloom_filter()->set_bits(bits_); return server_setup; } diff --git a/private_set_intersection/cpp/bloom_filter.h b/private_set_intersection/cpp/datastructure/bloom_filter.h similarity index 100% rename from private_set_intersection/cpp/bloom_filter.h rename to private_set_intersection/cpp/datastructure/bloom_filter.h diff --git a/private_set_intersection/cpp/bloom_filter_test.cpp b/private_set_intersection/cpp/datastructure/bloom_filter_test.cpp similarity index 93% rename from private_set_intersection/cpp/bloom_filter_test.cpp rename to private_set_intersection/cpp/datastructure/bloom_filter_test.cpp index 22aa44d7..58d7bbc1 100644 --- a/private_set_intersection/cpp/bloom_filter_test.cpp +++ b/private_set_intersection/cpp/datastructure/bloom_filter_test.cpp @@ -14,13 +14,13 @@ // limitations under the License. // -#include "private_set_intersection/cpp/bloom_filter.h" +#include "private_set_intersection/cpp/datastructure/bloom_filter.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "gtest/gtest.h" +#include "private_set_intersection/cpp/util/status_matchers.h" #include "private_set_intersection/proto/psi.pb.h" -#include "util/status_matchers.h" namespace private_set_intersection { namespace { @@ -87,9 +87,9 @@ TEST_F(BloomFilterTest, TestToProtobuf) { EXPECT_EQ(encoded_filter.bloom_filter().num_hash_functions(), filter_->NumHashFunctions()); EXPECT_EQ(encoded_filter.bloom_filter().num_hash_functions(), 7); - EXPECT_EQ(encoded_filter.bits(), filter_->Bits()); + EXPECT_EQ(encoded_filter.bloom_filter().bits(), filter_->Bits()); EXPECT_EQ( - absl::Base64Escape(encoded_filter.bits()), + absl::Base64Escape(encoded_filter.bloom_filter().bits()), "VN3/" "BXfUjEDvJLcxCTepUCTXGQwlTax0xHiMohCNb45uShFsznK099RH0CFVIMn91Bdc7jLkXHXr" "Xp1NimmZSDrYSj5sd/" diff --git a/private_set_intersection/cpp/datastructure/datastructure.h b/private_set_intersection/cpp/datastructure/datastructure.h new file mode 100644 index 00000000..85c27803 --- /dev/null +++ b/private_set_intersection/cpp/datastructure/datastructure.h @@ -0,0 +1,35 @@ +// +// Copyright 2020 the authors listed in CONTRIBUTORS.md +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef PRIVATE_SET_INTERSECTION_CPP_DATASTRUCTURE_H_ +#define PRIVATE_SET_INTERSECTION_CPP_DATASTRUCTURE_H_ + +#ifdef __cplusplus +namespace private_set_intersection { +extern "C" { +#endif + +typedef enum DataStructure { + Raw = 0, + Gcs = 1, + BloomFilter = 2, +} datastructure_t; + +#ifdef __cplusplus +} +} +#endif + +#endif // PRIVATE_SET_INTERSECTION_CPP_DATASTRUCTURE_H_ diff --git a/private_set_intersection/cpp/gcs.cpp b/private_set_intersection/cpp/datastructure/gcs.cpp similarity index 94% rename from private_set_intersection/cpp/gcs.cpp rename to private_set_intersection/cpp/datastructure/gcs.cpp index c4baedd9..fb853486 100644 --- a/private_set_intersection/cpp/gcs.cpp +++ b/private_set_intersection/cpp/datastructure/gcs.cpp @@ -14,7 +14,7 @@ // limitations under the License. // -#include "private_set_intersection/cpp/gcs.h" +#include "private_set_intersection/cpp/datastructure/gcs.h" #include #include @@ -22,7 +22,7 @@ #include "absl/memory/memory.h" #include "absl/strings/escaping.h" -#include "private_set_intersection/cpp/golomb.h" +#include "private_set_intersection/cpp/datastructure/golomb.h" #include "private_set_intersection/proto/psi.pb.h" namespace private_set_intersection { @@ -65,7 +65,7 @@ StatusOr> GCS::CreateFromProtobuf( } auto context = absl::make_unique<::private_join_and_compute::Context>(); - return absl::WrapUnique(new GCS(std::move(encoded_set.bits()), + return absl::WrapUnique(new GCS(std::move(encoded_set.gcs().bits()), static_cast(encoded_set.gcs().div()), encoded_set.gcs().hash_range(), std::move(context))); @@ -91,7 +91,7 @@ std::vector GCS::Intersect( psi_proto::ServerSetup GCS::ToProtobuf() const { psi_proto::ServerSetup server_setup; - server_setup.set_bits(golomb_); + server_setup.mutable_gcs()->set_bits(golomb_); server_setup.mutable_gcs()->set_div(static_cast(div_)); server_setup.mutable_gcs()->set_hash_range(hash_range_); return server_setup; diff --git a/private_set_intersection/cpp/gcs.h b/private_set_intersection/cpp/datastructure/gcs.h similarity index 100% rename from private_set_intersection/cpp/gcs.h rename to private_set_intersection/cpp/datastructure/gcs.h diff --git a/private_set_intersection/cpp/gcs_test.cpp b/private_set_intersection/cpp/datastructure/gcs_test.cpp similarity index 97% rename from private_set_intersection/cpp/gcs_test.cpp rename to private_set_intersection/cpp/datastructure/gcs_test.cpp index 7f2bac4d..c5516175 100644 --- a/private_set_intersection/cpp/gcs_test.cpp +++ b/private_set_intersection/cpp/datastructure/gcs_test.cpp @@ -14,7 +14,7 @@ // limitations under the License. // -#include "private_set_intersection/cpp/gcs.h" +#include "private_set_intersection/cpp/datastructure/gcs.h" #include @@ -22,8 +22,8 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "gtest/gtest.h" +#include "private_set_intersection/cpp/util/status_matchers.h" #include "private_set_intersection/proto/psi.pb.h" -#include "util/status_matchers.h" namespace private_set_intersection { namespace { @@ -107,7 +107,7 @@ TEST(GCSTest, TestToProtobuf) { psi_proto::ServerSetup encoded_gcs = gcs->ToProtobuf(); EXPECT_EQ(encoded_gcs.gcs().div(), gcs->Div()); EXPECT_EQ(encoded_gcs.gcs().hash_range(), gcs->HashRange()); - EXPECT_EQ(encoded_gcs.bits(), gcs->Golomb()); + EXPECT_EQ(encoded_gcs.gcs().bits(), gcs->Golomb()); } TEST(GCSTest, TestCreateFromProtobuf) { diff --git a/private_set_intersection/cpp/golomb.cpp b/private_set_intersection/cpp/datastructure/golomb.cpp similarity index 98% rename from private_set_intersection/cpp/golomb.cpp rename to private_set_intersection/cpp/datastructure/golomb.cpp index 1215a501..9ba3e006 100644 --- a/private_set_intersection/cpp/golomb.cpp +++ b/private_set_intersection/cpp/datastructure/golomb.cpp @@ -14,7 +14,7 @@ // limitations under the License. // -#include "private_set_intersection/cpp/golomb.h" +#include "private_set_intersection/cpp/datastructure/golomb.h" #include #include diff --git a/private_set_intersection/cpp/golomb.h b/private_set_intersection/cpp/datastructure/golomb.h similarity index 100% rename from private_set_intersection/cpp/golomb.h rename to private_set_intersection/cpp/datastructure/golomb.h diff --git a/private_set_intersection/cpp/golomb_test.cpp b/private_set_intersection/cpp/datastructure/golomb_test.cpp similarity index 97% rename from private_set_intersection/cpp/golomb_test.cpp rename to private_set_intersection/cpp/datastructure/golomb_test.cpp index 05c3670c..a725ac07 100644 --- a/private_set_intersection/cpp/golomb_test.cpp +++ b/private_set_intersection/cpp/datastructure/golomb_test.cpp @@ -14,7 +14,7 @@ // limitations under the License. // -#include "private_set_intersection/cpp/golomb.h" +#include "private_set_intersection/cpp/datastructure/golomb.h" #include #include diff --git a/private_set_intersection/cpp/datastructure/raw.cpp b/private_set_intersection/cpp/datastructure/raw.cpp new file mode 100644 index 00000000..2f172c45 --- /dev/null +++ b/private_set_intersection/cpp/datastructure/raw.cpp @@ -0,0 +1,79 @@ +// +// Copyright 2020 the authors listed in CONTRIBUTORS.md +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "private_set_intersection/cpp/datastructure/raw.h" + +#include + +#include "absl/memory/memory.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "private_set_intersection/proto/psi.pb.h" + +namespace private_set_intersection { + +Raw::Raw(std::vector elements) : encrypted_(std::move(elements)) {} + +StatusOr> Raw::Create(int64_t num_client_inputs, + std::vector elements) { + auto num_server_inputs = static_cast(elements.size()); + + // If server inputs < client inputs, add random encrypted values + // ... + + // Then we perform a sort to make intersections easier to find + std::sort(elements.begin(), elements.end()); + + return absl::WrapUnique(new Raw(elements)); +} + +StatusOr> Raw::CreateFromProtobuf( + const psi_proto::ServerSetup& encoded_filter) { + if (!encoded_filter.IsInitialized()) { + return absl::InvalidArgumentError("`ServerSetup` is corrupt!"); + } + + std::vector encrypted_elements( + encoded_filter.raw().encrypted_elements().begin(), + encoded_filter.raw().encrypted_elements().end()); + + return absl::WrapUnique(new Raw(encrypted_elements)); +} + +std::vector Raw::Intersect( + absl::Span elements) const { + std::vector res; + + for (size_t i = 0; i < elements.size(); i++) { + if (std::binary_search(encrypted_.begin(), encrypted_.end(), elements[i])) { + res.push_back(i); + } + } + + return res; +} + +size_t Raw::size() const { return encrypted_.size(); } + +psi_proto::ServerSetup Raw::ToProtobuf() const { + psi_proto::ServerSetup server_setup; + *server_setup.mutable_raw()->mutable_encrypted_elements() = { + encrypted_.begin(), encrypted_.end()}; + + return server_setup; +} + +} // namespace private_set_intersection diff --git a/private_set_intersection/cpp/datastructure/raw.h b/private_set_intersection/cpp/datastructure/raw.h new file mode 100644 index 00000000..0df362ad --- /dev/null +++ b/private_set_intersection/cpp/datastructure/raw.h @@ -0,0 +1,59 @@ +// +// Copyright 2020 the authors listed in CONTRIBUTORS.md +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef PRIVATE_SET_INTERSECTION_CPP_RAW_H_ +#define PRIVATE_SET_INTERSECTION_CPP_RAW_H_ + +#include + +#include "absl/status/statusor.h" +#include "absl/types/span.h" +#include "private_join_and_compute/crypto/context.h" +#include "private_set_intersection/proto/psi.pb.h" + +namespace private_set_intersection { + +using absl::StatusOr; + +// A Raw datastructure is a simple container for holding raw encrypted values. +class Raw { + public: + Raw() = delete; + + static StatusOr> Create( + int64_t num_client_inputs, std::vector elements); + + // Creates a container containing holding encrypted values from a protocol + // buffer + static StatusOr> CreateFromProtobuf( + const psi_proto::ServerSetup& encoded_filter); + + std::vector Intersect(absl::Span elements) const; + + // Returns the size of the encrypted elements + size_t size() const; + + // Returns a protobuf representation of the container + psi_proto::ServerSetup ToProtobuf() const; + + private: + Raw(std::vector encrypted); + const std::vector encrypted_; +}; + +} // namespace private_set_intersection + +#endif // PRIVATE_SET_INTERSECTION_CPP_RAW_H_ diff --git a/private_set_intersection/cpp/datastructure/raw_test.cpp b/private_set_intersection/cpp/datastructure/raw_test.cpp new file mode 100644 index 00000000..4334292f --- /dev/null +++ b/private_set_intersection/cpp/datastructure/raw_test.cpp @@ -0,0 +1,82 @@ +// +// Copyright 2020 the authors listed in CONTRIBUTORS.md +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "private_set_intersection/cpp/datastructure/raw.h" + +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "gtest/gtest.h" +#include "private_set_intersection/cpp/util/status_matchers.h" +#include "private_set_intersection/proto/psi.pb.h" + +namespace private_set_intersection { +namespace { + +class RawTest : public ::testing::Test { + protected: + void SetUp(int64_t num_client_inputs, + std::vector encrypted_elements) { + PSI_ASSERT_OK_AND_ASSIGN( + container_, Raw::Create(num_client_inputs, encrypted_elements)); + } + + std::unique_ptr container_; +}; + +TEST_F(RawTest, TestAdd) { + std::vector server = {"a", "b", "c", "d", "e"}; + std::vector client = {"z", "b", "c", "d"}; + + SetUp(static_cast(client.size()), server); + std::vector results = container_->Intersect(client); + std::vector expected{1, 2, 3}; + EXPECT_EQ(results.size(), 3); + EXPECT_EQ(results, expected); +} + +TEST_F(RawTest, TestToProtobuf) { + std::vector server = {"b", "a", "c", "d", "e"}; + std::vector client = {"z", "b", "c", "d"}; + + SetUp(static_cast(client.size()), server); + + // Create the protobuf from the Raw container and check if it matches. + psi_proto::ServerSetup encoded_filter = container_->ToProtobuf(); + EXPECT_EQ(encoded_filter.raw().encrypted_elements().size(), + container_->size()); + + // In Raw mode, the encrypted results are sorted so this check + // is to verify we're performing a sort correctly. + EXPECT_EQ(encoded_filter.raw().encrypted_elements()[0], "a"); +} + +TEST_F(RawTest, TestCreateFromProtobuf) { + std::vector server = {"a", "b", "c", "d", "e"}; + std::vector client = {"z", "b", "c", "d"}; + + SetUp(static_cast(client.size()), server); + + // Create the protobuf from the Raw container and check if it matches. + PSI_ASSERT_OK_AND_ASSIGN(auto container2, + Raw::CreateFromProtobuf(container_->ToProtobuf())); + std::vector results = container2->Intersect(client); + std::vector expected{1, 2, 3}; + EXPECT_EQ(results.size(), 3); + EXPECT_EQ(results, expected); +} + +} // namespace +} // namespace private_set_intersection diff --git a/private_set_intersection/cpp/psi_benchmark.cpp b/private_set_intersection/cpp/psi_benchmark.cpp index 440d8f73..df9259aa 100644 --- a/private_set_intersection/cpp/psi_benchmark.cpp +++ b/private_set_intersection/cpp/psi_benchmark.cpp @@ -32,19 +32,19 @@ void BM_ServerSetup(benchmark::State& state, double fpr, // Range is for the number of inputs, and the captured argument is the false // positive rate for 10k client queries. BENCHMARK_CAPTURE(BM_ServerSetup, 0.001 size gcs, 0.001, false, - DataStructure::GCS) + DataStructure::Gcs) ->RangeMultiplier(10) ->Range(1, 100000); BENCHMARK_CAPTURE(BM_ServerSetup, 0.000001 size gcs, 0.000001, false, - DataStructure::GCS) + DataStructure::Gcs) ->RangeMultiplier(10) ->Range(1, 100000); BENCHMARK_CAPTURE(BM_ServerSetup, 0.001 intersection gcs, 0.001, true, - DataStructure::GCS) + DataStructure::Gcs) ->RangeMultiplier(10) ->Range(1, 100000); BENCHMARK_CAPTURE(BM_ServerSetup, 0.000001 intersection gcs, 0.000001, true, - DataStructure::GCS) + DataStructure::Gcs) ->RangeMultiplier(10) ->Range(1, 100000); BENCHMARK_CAPTURE(BM_ServerSetup, 0.001 size bloom, 0.001, false, @@ -159,12 +159,12 @@ void BM_ClientProcessResponse(benchmark::State& state, bool reveal_intersection, static_cast(elements_processed), benchmark::Counter::kIsRate); } // Range is for the number of inputs. -BENCHMARK_CAPTURE(BM_ClientProcessResponse, size gcs, false, DataStructure::GCS, +BENCHMARK_CAPTURE(BM_ClientProcessResponse, size gcs, false, DataStructure::Gcs, 1.0) ->RangeMultiplier(10) ->Range(1, 10000); BENCHMARK_CAPTURE(BM_ClientProcessResponse, intersection gcs, true, - DataStructure::GCS, 1.0) + DataStructure::Gcs, 1.0) ->RangeMultiplier(10) ->Range(1, 10000); BENCHMARK_CAPTURE(BM_ClientProcessResponse, size bloom, false, @@ -176,11 +176,11 @@ BENCHMARK_CAPTURE(BM_ClientProcessResponse, intersection bloom, true, ->RangeMultiplier(10) ->Range(1, 10000); BENCHMARK_CAPTURE(BM_ClientProcessResponse, size gcs asymmetric, false, - DataStructure::GCS, 0.001) + DataStructure::Gcs, 0.001) ->RangeMultiplier(10) ->Range(10000, 100000); BENCHMARK_CAPTURE(BM_ClientProcessResponse, intersection gcs asymmetric, true, - DataStructure::GCS, 0.001) + DataStructure::Gcs, 0.001) ->RangeMultiplier(10) ->Range(10000, 100000); BENCHMARK_CAPTURE(BM_ClientProcessResponse, size bloom asymmetric, false, diff --git a/private_set_intersection/cpp/psi_client.cpp b/private_set_intersection/cpp/psi_client.cpp index e185000f..08387f4a 100644 --- a/private_set_intersection/cpp/psi_client.cpp +++ b/private_set_intersection/cpp/psi_client.cpp @@ -22,8 +22,9 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "openssl/obj_mac.h" -#include "private_set_intersection/cpp/bloom_filter.h" -#include "private_set_intersection/cpp/gcs.h" +#include "private_set_intersection/cpp/datastructure/bloom_filter.h" +#include "private_set_intersection/cpp/datastructure/gcs.h" +#include "private_set_intersection/cpp/datastructure/raw.h" #include "private_set_intersection/proto/psi.pb.h" namespace private_set_intersection { @@ -127,20 +128,29 @@ StatusOr> PsiClient::ProcessResponse( decrypted.push_back(element); } - if (server_setup.data_structure_case() == - psi_proto::ServerSetup::DataStructureCase::kGcs) { - // Decode GCS from the server setup. - ASSIGN_OR_RETURN(auto gcs, GCS::CreateFromProtobuf(server_setup)); - return gcs->Intersect(absl::MakeConstSpan(&decrypted[0], decrypted.size())); - } else if (server_setup.data_structure_case() == - psi_proto::ServerSetup::DataStructureCase::kBloomFilter) { - // Decode Bloom Filter from the server setup. - ASSIGN_OR_RETURN(auto filter, - BloomFilter::CreateFromProtobuf(server_setup)); - return filter->Intersect( - absl::MakeConstSpan(&decrypted[0], decrypted.size())); - } else { - return absl::InvalidArgumentError("Impossible"); + switch (server_setup.data_structure_case()) { + case psi_proto::ServerSetup::DataStructureCase::kRaw: { + // Decode Bloom Filter from the server setup. + ASSIGN_OR_RETURN(auto container, Raw::CreateFromProtobuf(server_setup)); + return container->Intersect( + absl::MakeConstSpan(&decrypted[0], decrypted.size())); + } + case psi_proto::ServerSetup::DataStructureCase::kGcs: { + // Decode GCS from the server setup. + ASSIGN_OR_RETURN(auto container, GCS::CreateFromProtobuf(server_setup)); + return container->Intersect( + absl::MakeConstSpan(&decrypted[0], decrypted.size())); + } + case psi_proto::ServerSetup::DataStructureCase::kBloomFilter: { + // Decode Bloom Filter from the server setup. + ASSIGN_OR_RETURN(auto container, + BloomFilter::CreateFromProtobuf(server_setup)); + return container->Intersect( + absl::MakeConstSpan(&decrypted[0], decrypted.size())); + } + default: { + return absl::InvalidArgumentError("Impossible"); + } } } diff --git a/private_set_intersection/cpp/psi_client_test.cpp b/private_set_intersection/cpp/psi_client_test.cpp index 33b0a208..7bb22170 100644 --- a/private_set_intersection/cpp/psi_client_test.cpp +++ b/private_set_intersection/cpp/psi_client_test.cpp @@ -21,7 +21,7 @@ #include "absl/strings/str_cat.h" #include "gtest/gtest.h" #include "private_join_and_compute/crypto/ec_commutative_cipher.h" -#include "private_set_intersection/cpp/gcs.h" +#include "private_set_intersection/cpp/datastructure/gcs.h" #include "util/status_matchers.h" namespace private_set_intersection { diff --git a/private_set_intersection/cpp/psi_server.cpp b/private_set_intersection/cpp/psi_server.cpp index 17512c94..799157ae 100644 --- a/private_set_intersection/cpp/psi_server.cpp +++ b/private_set_intersection/cpp/psi_server.cpp @@ -22,8 +22,9 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "openssl/obj_mac.h" -#include "private_set_intersection/cpp/bloom_filter.h" -#include "private_set_intersection/cpp/gcs.h" +#include "private_set_intersection/cpp/datastructure/bloom_filter.h" +#include "private_set_intersection/cpp/datastructure/gcs.h" +#include "private_set_intersection/cpp/datastructure/raw.h" #include "private_set_intersection/proto/psi.pb.h" namespace private_set_intersection { @@ -73,26 +74,38 @@ StatusOr PsiServer::CreateSetupMessage( encrypted.push_back(encrypted_element); } - if (ds == DataStructure::GCS) { - // Create a GCS and insert elements into it. - ASSIGN_OR_RETURN( - auto gcs, - GCS::Create(corrected_fpr, num_client_inputs, - absl::MakeConstSpan(&encrypted[0], encrypted.size()))); - - // Return the GCS as a Protobuf - return gcs->ToProtobuf(); - } else if (ds == DataStructure::BloomFilter) { - // Create a Bloom Filter and insert elements into it. - ASSIGN_OR_RETURN(auto filter, - BloomFilter::Create( - corrected_fpr, num_client_inputs, - absl::MakeConstSpan(&encrypted[0], encrypted.size()))); - - // Return the Bloom Filter as a Protobuf - return filter->ToProtobuf(); - } else { - return absl::InvalidArgumentError("Impossible"); + switch (ds) { + case DataStructure::Gcs: { + // Create a GCS and insert elements into it. + ASSIGN_OR_RETURN( + auto container, + GCS::Create(corrected_fpr, num_client_inputs, + absl::MakeConstSpan(&encrypted[0], encrypted.size()))); + + // Return the GCS as a Protobuf + return container->ToProtobuf(); + } + case DataStructure::BloomFilter: { + // Create a Bloom Filter and insert elements into it. + ASSIGN_OR_RETURN( + auto container, + BloomFilter::Create( + corrected_fpr, num_client_inputs, + absl::MakeConstSpan(&encrypted[0], encrypted.size()))); + + // Return the Bloom Filter as a Protobuf + return container->ToProtobuf(); + } + case DataStructure::Raw: { + // Create a Raw container and insert elements into it. + ASSIGN_OR_RETURN(auto container, + Raw::Create(num_client_inputs, std::move(encrypted))); + + // Return the Raw container as a Protobuf + return container->ToProtobuf(); + } + default: + return absl::InvalidArgumentError("Impossible"); } } diff --git a/private_set_intersection/cpp/psi_server.h b/private_set_intersection/cpp/psi_server.h index 0323cfa2..bc06ae6e 100644 --- a/private_set_intersection/cpp/psi_server.h +++ b/private_set_intersection/cpp/psi_server.h @@ -20,14 +20,13 @@ #include "absl/status/statusor.h" #include "absl/types/span.h" #include "private_join_and_compute/crypto/ec_commutative_cipher.h" +#include "private_set_intersection/cpp/datastructure/datastructure.h" #include "private_set_intersection/proto/psi.pb.h" namespace private_set_intersection { using absl::StatusOr; -enum class DataStructure { GCS, BloomFilter }; - // The server side of a Private Set Intersection protocol. // See the documentation in PsiClient for a full description of the // protocol. @@ -51,32 +50,36 @@ class PsiServer { static StatusOr> CreateFromKey( const std::string& key_bytes, bool reveal_intersection); - // Creates a setup message from the server's dataset to be sent to the - // client. The setup message is a set containing - // H(x)^s for each element x in `inputs`, where s is the server's secret - // key. The setup is sent to the client as a serialized protobuf with - // the following form: + // Creates a setup message from the server's dataset to be sent to the client. + // The setup message is a set containing H(x)^s for each element x in + // `inputs`, where s is the server's secret key. The setup is sent to the + // client as a serialized protobuf with the following form: // // { // "num_hash_functions": , // "bits": // } // - // `bits` is a binary string. - // The false-positive rate `fpr` is the probability that any query of size - // `num_client_inputs` will result in a false positive. + // `bits` is a binary string. The false-positive rate `fpr` is the probability + // that any query of size `num_client_inputs` will result in a false positive. // // By default, Golomb Compressed Sets are used as the underlying set data - // structure. If the number of client elements is expected to be orders - // of magnitude lower than the number of server elements, then Bloom - // Filters may be faster. Otherwise, Golomb Compressed Sets can achieve - // better compression, so it is better for network transfer. + // structure. If the number of client elements is expected to be orders of + // magnitude lower than the number of server elements, then Bloom Filters may + // be faster. Otherwise, Golomb Compressed Sets can achieve better + // compression, so it is better for network transfer. + // + // NOTE: If DataStructure::Raw is specified, the protocol will use raw + // encrypted values and intersection calculations will not have false + // positive. This means the `fpr` parameter is ignored, but comes at the cost + // of larger communication costs. Specifying DataStructure::Raw is useful if + // you must have correctness. // // Returns INTERNAL if encryption fails. StatusOr CreateSetupMessage( double fpr, int64_t num_client_inputs, absl::Span inputs, - DataStructure ds = DataStructure::GCS) const; + DataStructure ds = DataStructure::Gcs) const; // Processes a client query and returns the corresponding server response to // be sent to the client. For each encrytped element H(x)^c in the decoded diff --git a/private_set_intersection/cpp/psi_server_test.cpp b/private_set_intersection/cpp/psi_server_test.cpp index e0aadf7d..6b40fd37 100644 --- a/private_set_intersection/cpp/psi_server_test.cpp +++ b/private_set_intersection/cpp/psi_server_test.cpp @@ -201,7 +201,7 @@ TEST_F(PsiServerTest, TestCreatingFromKey) { // Both setup messages should be the same EXPECT_EQ(server_setup.gcs().div(), server_setup1.gcs().div()); EXPECT_EQ(server_setup.gcs().hash_range(), server_setup1.gcs().hash_range()); - EXPECT_EQ(server_setup.bits(), server_setup1.bits()); + EXPECT_EQ(server_setup.gcs().bits(), server_setup1.gcs().bits()); // Create a 31-byte key that should be equivalent to a 32-byte null-inserted // key. @@ -222,7 +222,7 @@ TEST_F(PsiServerTest, TestCreatingFromKey) { server3->CreateSetupMessage(fpr, num_client_elements, server_elements)); EXPECT_EQ(server_setup2.gcs().div(), server_setup3.gcs().div()); EXPECT_EQ(server_setup2.gcs().hash_range(), server_setup3.gcs().hash_range()); - EXPECT_EQ(server_setup2.bits(), server_setup3.bits()); + EXPECT_EQ(server_setup2.gcs().bits(), server_setup3.gcs().bits()); } TEST_F(PsiServerTest, FailIfRevealIntersectionDoesntMatch) { diff --git a/private_set_intersection/go/BUILD b/private_set_intersection/go/BUILD index 6827eaf0..f8a350dd 100644 --- a/private_set_intersection/go/BUILD +++ b/private_set_intersection/go/BUILD @@ -1,4 +1,31 @@ load("@bazel_gazelle//:def.bzl", "gazelle") +load("@io_bazel_rules_go//go:def.bzl", "go_test") # gazelle:prefix github.com/openmined/psi gazelle(name = "gazelle") + +go_test( + name = "integration_test", + srcs = ["integration_test.go"], + importpath = "github.com/openmined/psi", + deps = [ + "//private_set_intersection/go/client", + "//private_set_intersection/go/datastructure", + "//private_set_intersection/go/server", + "//private_set_intersection/go/version", + "//private_set_intersection/proto:psi_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", + ], +) + +go_test( + name = "benchmark_test", + srcs = ["benchmark_test.go"], + deps = [ + "//private_set_intersection/go/client", + "//private_set_intersection/go/datastructure", + "//private_set_intersection/go/server", + "//private_set_intersection/proto:psi_go_proto", + "@org_golang_google_protobuf//proto:go_default_library", + ], +) diff --git a/private_set_intersection/go/benchmark_test.go b/private_set_intersection/go/benchmark_test.go new file mode 100644 index 00000000..932d1f6d --- /dev/null +++ b/private_set_intersection/go/benchmark_test.go @@ -0,0 +1,182 @@ +package benchmark + +import ( + "fmt" + "testing" + + psi_client "github.com/openmined/psi/client" + psi_ds "github.com/openmined/psi/datastructure" + psi_server "github.com/openmined/psi/server" + "google.golang.org/protobuf/proto" +) + +var paramsTable = []struct { + revealIntersection bool + ds psi_ds.DataStructure +}{ + {revealIntersection: true, ds: psi_ds.Raw}, + {revealIntersection: true, ds: psi_ds.Gcs}, + {revealIntersection: true, ds: psi_ds.BloomFilter}, +} + +var inputsTable = []struct { + fpr float64 + numClientInputs int +}{ + {fpr: 0.001, numClientInputs: 10}, + {fpr: 0.001, numClientInputs: 100}, +} + +const numServerInputs = 1000 + +func BenchmarkServerSetup(b *testing.B) { + for _, pt := range paramsTable { + server, err := psi_server.CreateWithNewKey(pt.revealIntersection) + if err != nil || server == nil { + b.Errorf("failed to get server") + } + for _, it := range inputsTable { + b.Run(fmt.Sprintf("ds_%s_fpr_%f_inputs_%d", pt.ds, it.fpr, it.numClientInputs), func(b *testing.B) { + b.ReportAllocs() + total := 0 + serverInputs := []string{} + for i := 0; i < numServerInputs; i++ { + serverInputs = append(serverInputs, "Element "+string(i)) + } + + for i := 0; i < b.N; i++ { + _, err := server.CreateSetupMessage(it.fpr, int64(10000), serverInputs, pt.ds) + if err != nil { + b.Errorf("failed to create setup msg %v", err) + } + total += numServerInputs + } + + b.ReportMetric(float64(total), "ElementsProcessed") + }) + } + } +} + +func BenchmarkClientRequest(b *testing.B) { + for _, pt := range paramsTable { + client, err := psi_client.CreateWithNewKey(pt.revealIntersection) + if err != nil { + b.Errorf("failed to get client") + } + + for _, it := range inputsTable { + b.Run(fmt.Sprintf("ds_%s_fpr_%f_inputs_%d", pt.ds, it.fpr, it.numClientInputs), func(b *testing.B) { + b.ReportAllocs() + total := 0 + + clientInputs := []string{} + for i := 0; i < it.numClientInputs; i++ { + clientInputs = append(clientInputs, "Element "+string(i)) + } + + for n := 0; n < b.N; n++ { + request, err := client.CreateRequest(clientInputs) + if err != nil { + b.Errorf("failed to create request %v", err) + } + total += it.numClientInputs + b.ReportMetric(float64(proto.Size(request)), "RequestSize") + } + b.ReportMetric(float64(total), "ElementsProcessed") + }) + } + } +} + +func BenchmarkProcessRequest(b *testing.B) { + for _, pt := range paramsTable { + client, err := psi_client.CreateWithNewKey(pt.revealIntersection) + if err != nil { + b.Errorf("failed to get client") + } + server, err := psi_server.CreateWithNewKey(pt.revealIntersection) + if err != nil { + b.Errorf("failed to get server") + } + + for _, it := range inputsTable { + b.Run(fmt.Sprintf("ds_%s_fpr_%f_inputs_%d", pt.ds, it.fpr, it.numClientInputs), func(b *testing.B) { + b.ReportAllocs() + total := 0 + + clientInputs := []string{} + for i := 0; i < it.numClientInputs; i++ { + clientInputs = append(clientInputs, "Element "+string(i)) + } + + request, err := client.CreateRequest(clientInputs) + if err != nil { + b.Errorf("failed to create request %v", err) + } + + for n := 0; n < b.N; n++ { + serverResp, err := server.ProcessRequest(request) + if err != nil { + b.Errorf("failed to process request %v", err) + } + total += it.numClientInputs + b.ReportMetric(float64(proto.Size(serverResp)), "ResponseSize") + } + b.ReportMetric(float64(total), "ElementsProcessed") + }) + } + } +} + +func BenchmarkIntersection(b *testing.B) { + for _, pt := range paramsTable { + client, err := psi_client.CreateWithNewKey(pt.revealIntersection) + if err != nil { + b.Errorf("failed to get client") + } + server, err := psi_server.CreateWithNewKey(pt.revealIntersection) + if err != nil { + b.Errorf("failed to get server") + } + + for _, it := range inputsTable { + b.Run(fmt.Sprintf("ds_%s_fpr_%f_inputs_%d", pt.ds, it.fpr, it.numClientInputs), func(b *testing.B) { + b.ReportAllocs() + total := 0 + + clientInputs := []string{} + for i := 0; i < it.numClientInputs; i++ { + clientInputs = append(clientInputs, "Element "+string(i)) + } + serverInputs := []string{} + for i := 0; i < numServerInputs; i++ { + serverInputs = append(serverInputs, "Element "+string(i*2)) + } + + setup, err := server.CreateSetupMessage(it.fpr, int64(10000), serverInputs, pt.ds) + if err != nil { + b.Errorf("failed to create setup msg %v", err) + } + + request, err := client.CreateRequest(clientInputs) + if err != nil { + b.Errorf("failed to create request %v", err) + } + serverResp, err := server.ProcessRequest(request) + if err != nil { + b.Errorf("failed to process request %v", err) + } + + for n := 0; n < b.N; n++ { + intersection, err := client.GetIntersection(setup, serverResp) + if err != nil { + b.Errorf("failed to compute intersection %v", err) + } + total += len(intersection) + } + b.ReportMetric(float64(total), "ElementsProcessed") + }) + } + } +} diff --git a/private_set_intersection/go/client/BUILD b/private_set_intersection/go/client/BUILD index 9f96f676..9869990d 100644 --- a/private_set_intersection/go/client/BUILD +++ b/private_set_intersection/go/client/BUILD @@ -8,9 +8,10 @@ go_library( importpath = "github.com/openmined/psi/client", visibility = ["//visibility:public"], deps = [ + "//private_set_intersection/go/datastructure", "//private_set_intersection/go/version", "//private_set_intersection/proto:psi_go_proto", - "@com_github_golang_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/private_set_intersection/go/client/client.go b/private_set_intersection/go/client/client.go index 80bb9530..d18a1adb 100644 --- a/private_set_intersection/go/client/client.go +++ b/private_set_intersection/go/client/client.go @@ -71,9 +71,9 @@ import ( "runtime" "unsafe" - "github.com/golang/protobuf/proto" psi_proto "github.com/openmined/psi/pb" "github.com/openmined/psi/version" + "google.golang.org/protobuf/proto" ) // PsiClient context for the client side of a Private Set Intersection protocol. diff --git a/private_set_intersection/go/client/client_test.go b/private_set_intersection/go/client/client_test.go index a7ca08f3..48482565 100644 --- a/private_set_intersection/go/client/client_test.go +++ b/private_set_intersection/go/client/client_test.go @@ -1,61 +1,10 @@ package client import ( - "bytes" - "github.com/golang/protobuf/proto" psi_proto "github.com/openmined/psi/pb" - "github.com/openmined/psi/server" - "regexp" "testing" ) -func generateSet(in []int64) map[int]struct{} { - out := map[int]struct{}{} - for _, item := range in { - out[int(item)] = struct{}{} - } - - return out -} -func testClientSanity(t *testing.T, revealIntersection bool) { - client, err := CreateWithNewKey(revealIntersection) - if err != nil || client == nil { - t.Errorf("Failed to create a PSI client %v", err) - } - - key, err := client.GetPrivateKeyBytes() - if err != nil { - t.Errorf("Failed to create a PSI client key %v", err) - } - - newClient, err := CreateFromKey(key, revealIntersection) - if err != nil || newClient == nil { - t.Errorf("Failed to create a PSI client from key %v", err) - } - - newKey, err := newClient.GetPrivateKeyBytes() - if err != nil { - t.Errorf("Failed to create a new PSI client key %v", err) - } - if !bytes.Equal(key, newKey) { - t.Errorf("new client invalid") - } - client.Destroy() - for i := 0; i < 5; i++ { - client.Destroy() - } - - matched, _ := regexp.MatchString(`[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9]+)?`, client.Version()) - if !matched { - t.Errorf("Got invalid version %v", client.Version()) - } -} - -func TestClientSanity(t *testing.T) { - testClientSanity(t, true) - testClientSanity(t, false) -} - func testClientFailure(t *testing.T, revealIntersection bool) { c := &PsiClient{} _, err := c.CreateRequest([]string{"dummy"}) @@ -81,203 +30,3 @@ func TestClientFailure(t *testing.T) { testClientFailure(t, false) testClientFailure(t, true) } - -func testClientServer(t *testing.T, revealIntersection bool) { - client, err := CreateWithNewKey(revealIntersection) - if err != nil || client == nil { - t.Errorf("Failed to create a PSI client %v", err) - } - - server, err := server.CreateWithNewKey(revealIntersection) - if err != nil || server == nil { - t.Errorf("Failed to create a PSI server %v", err) - } - - generateItems := func(cnt int, m int) (int, []string) { - items := []string{} - for i := 0; i < cnt; i++ { - items = append(items, "Element "+string(m*i)) - } - return cnt, items - } - cntClientItems, clientItems := generateItems(1000, 1) - _, serverItems := generateItems(10000, 2) - - fpr := 1. / (1000000000) - setup, err := server.CreateSetupMessage(fpr, int64(cntClientItems), serverItems) - if err != nil { - t.Errorf("failed to create setup msg %v", err) - } - request, err := client.CreateRequest(clientItems) - if err != nil { - t.Errorf("failed to create request %v", err) - } - serverResp, err := server.ProcessRequest(request) - if err != nil { - t.Errorf("failed to process request %v", err) - } - if revealIntersection { - intersection, err := client.GetIntersection(setup, serverResp) - if err != nil { - t.Errorf("failed to compute intersection %v", err) - } - intersectionSet := generateSet(intersection) - for idx := 0; idx < cntClientItems; idx++ { - _, ok := intersectionSet[idx] - if ok != (idx%2 == 0) { - t.Errorf("Invalid intersection for item %v %v", idx, ok) - } - } - } else { - intersectionCnt, err := client.GetIntersectionSize(setup, serverResp) - if err != nil { - t.Errorf("failed to compute intersection size %v", err) - } - - if int(intersectionCnt) < (cntClientItems / 2) { - t.Errorf("Invalid intersection. expected lower bound %v. got %v", (cntClientItems / 2), intersectionCnt) - } - - if float64(intersectionCnt) > float64(cntClientItems/2)*float64(1.1) { - t.Errorf("Invalid intersection. expected upper bound %v. got %v", float64(cntClientItems/2)*float64(1.1), intersectionCnt) - } - - } -} - -func TestClientServer(t *testing.T) { - - testClientServer(t, false) - testClientServer(t, true) -} - -var result *psi_proto.Request - -func benchmarkClientCreateRequest(cnt int, revealIntersection bool, b *testing.B) { - b.ReportAllocs() - total := 0 - - client, err := CreateWithNewKey(revealIntersection) - if err != nil || client == nil { - b.Errorf("failed to get client") - } - inputs := []string{} - for i := 0; i < cnt; i++ { - inputs = append(inputs, "Element "+string(i)) - } - - for n := 0; n < b.N; n++ { - request, err := client.CreateRequest(inputs) - if err != nil { - b.Errorf("failed to generate request") - } - - //ugly hack for preventing compiler optimizations - result = request - - total += cnt - b.ReportMetric(float64(proto.Size(request)), "RequestSize") - - } - b.ReportMetric(float64(total), "ElementsProcessed") -} - -func BenchmarkClientCreateRequest1(b *testing.B) { benchmarkClientCreateRequest(1, false, b) } -func BenchmarkClientCreateRequest10(b *testing.B) { benchmarkClientCreateRequest(10, false, b) } -func BenchmarkClientCreateRequest100(b *testing.B) { benchmarkClientCreateRequest(100, false, b) } -func BenchmarkClientCreateRequest1000(b *testing.B) { benchmarkClientCreateRequest(1000, false, b) } -func BenchmarkClientCreateRequest10000(b *testing.B) { benchmarkClientCreateRequest(10000, false, b) } - -func BenchmarkClientCreateRequestIntersection1(b *testing.B) { - benchmarkClientCreateRequest(1, true, b) -} -func BenchmarkClientCreateRequestIntersection10(b *testing.B) { - benchmarkClientCreateRequest(10, true, b) -} -func BenchmarkClientCreateRequestIntersection100(b *testing.B) { - benchmarkClientCreateRequest(100, true, b) -} -func BenchmarkClientCreateRequestIntersection1000(b *testing.B) { - benchmarkClientCreateRequest(1000, true, b) -} -func BenchmarkClientCreateRequestIntersection10000(b *testing.B) { - benchmarkClientCreateRequest(10000, true, b) -} - -var dummyInt64 int64 - -func benchmarkClientProcessResponse(cnt int, revealIntersection bool, b *testing.B) { - b.ReportAllocs() - total := 0 - - client, err := CreateWithNewKey(revealIntersection) - if err != nil || client == nil { - b.Errorf("failed to get client") - } - server, err := server.CreateWithNewKey(revealIntersection) - if err != nil || server == nil { - b.Errorf("failed to get server") - } - - fpr := 1. / (1000000) - - inputs := []string{} - for i := 0; i < cnt; i++ { - inputs = append(inputs, "Element "+string(i)) - } - - setup, err := server.CreateSetupMessage(fpr, int64(cnt), inputs) - if err != nil { - b.Errorf("failed to create setup msg %v", err) - } - request, err := client.CreateRequest(inputs) - if err != nil { - b.Errorf("failed to create request %v", err) - } - serverResp, err := server.ProcessRequest(request) - if err != nil { - b.Errorf("failed to process request %v", err) - } - - for n := 0; n < b.N; n++ { - if revealIntersection { - intersection, err := client.GetIntersection(setup, serverResp) - if err != nil { - b.Errorf("failed to compute intersection %v", err) - } - dummyInt64 = int64(len(intersection)) - } else { - intersectionCnt, err := client.GetIntersectionSize(setup, serverResp) - if err != nil { - b.Errorf("failed to process response %v", err) - } - total += cnt - //ugly hack for preventing compiler optimizations - dummyInt64 = intersectionCnt - } - } - b.ReportMetric(float64(total), "ElementsProcessed") -} - -func BenchmarkClientProcessResponse1(b *testing.B) { benchmarkClientProcessResponse(1, false, b) } -func BenchmarkClientProcessResponse10(b *testing.B) { benchmarkClientProcessResponse(10, false, b) } -func BenchmarkClientProcessResponse100(b *testing.B) { benchmarkClientProcessResponse(100, false, b) } -func BenchmarkClientProcessResponse1000(b *testing.B) { benchmarkClientProcessResponse(1000, false, b) } -func BenchmarkClientProcessResponse10000(b *testing.B) { - benchmarkClientProcessResponse(10000, false, b) -} -func BenchmarkClientProcessResponseIntersection1(b *testing.B) { - benchmarkClientProcessResponse(1, true, b) -} -func BenchmarkClientProcessResponseIntersection10(b *testing.B) { - benchmarkClientProcessResponse(10, true, b) -} -func BenchmarkClientProcessResponseIntersection100(b *testing.B) { - benchmarkClientProcessResponse(100, true, b) -} -func BenchmarkClientProcessResponseIntersection1000(b *testing.B) { - benchmarkClientProcessResponse(1000, true, b) -} -func BenchmarkClientProcessResponseIntersection10000(b *testing.B) { - benchmarkClientProcessResponse(10000, true, b) -} diff --git a/private_set_intersection/go/datastructure/BUILD b/private_set_intersection/go/datastructure/BUILD new file mode 100644 index 00000000..92ed9a75 --- /dev/null +++ b/private_set_intersection/go/datastructure/BUILD @@ -0,0 +1,10 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "datastructure", + srcs = ["datastructure.go"], + cdeps = ["//private_set_intersection/cpp/datastructure"], + cgo = True, + importpath = "github.com/openmined/psi/datastructure", + visibility = ["//visibility:public"], +) diff --git a/private_set_intersection/go/datastructure/datastructure.go b/private_set_intersection/go/datastructure/datastructure.go new file mode 100644 index 00000000..df3ab3e9 --- /dev/null +++ b/private_set_intersection/go/datastructure/datastructure.go @@ -0,0 +1,30 @@ +package datastructure + +/* +#include "private_set_intersection/cpp/datastructure/datastructure.h" +#include +*/ +import "C" + +// DataStructure enum type used to specify which backing datastructure to use +type DataStructure int + +// Golang's way to define enums that are compatible with our C bindings +const ( + Raw DataStructure = C.Raw + Gcs = C.Gcs + BloomFilter = C.BloomFilter +) + +func (ds DataStructure) String() string { + switch ds { + case Raw: + return "raw" + case Gcs: + return "gcs" + case BloomFilter: + return "bloomfilter" + default: + panic("impossible") + } +} diff --git a/private_set_intersection/go/integration_test.go b/private_set_intersection/go/integration_test.go new file mode 100644 index 00000000..beb9056d --- /dev/null +++ b/private_set_intersection/go/integration_test.go @@ -0,0 +1,205 @@ +package integration_test + +import ( + "bytes" + psi_client "github.com/openmined/psi/client" + psi_ds "github.com/openmined/psi/datastructure" + psi_proto "github.com/openmined/psi/pb" + psi_server "github.com/openmined/psi/server" + psi_version "github.com/openmined/psi/version" + "google.golang.org/protobuf/proto" + "regexp" + "testing" +) + +var clientKey = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31} +var serverKey = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} + +const fpr = 0.01 +const numClientInputs = 10 +const numServerInputs = 100 + +func generateSet(in []int64) map[int]struct{} { + out := map[int]struct{}{} + for _, item := range in { + out[int(item)] = struct{}{} + } + + return out +} + +func TestVersion(t *testing.T) { + version := psi_version.Version() + r, _ := regexp.Compile(`[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9]+)?`) + + matched := r.MatchString(version) + if !matched { + t.Errorf("Invalid version: %v", version) + } + + client, err := psi_client.CreateWithNewKey(false) + if err != nil { + t.Errorf("Failed to create a PSI client %v", err) + } + server, err := psi_server.CreateWithNewKey(false) + if err != nil { + t.Errorf("Failed to create a PSI server %v", err) + } + + clientVersion := client.Version() + serverVersion := server.Version() + matched = r.MatchString(clientVersion) + if !matched { + t.Errorf("Invalid client version: %v", version) + } + matched = r.MatchString(serverVersion) + if !matched { + t.Errorf("Invalid server version: %v", version) + } + + if version != clientVersion || version != serverVersion || clientVersion != serverVersion { + t.Errorf("Missmatched versions pkg (%s), client (%s), server (%s)", version, clientVersion, serverVersion) + } +} + +func TestStaticKey(t *testing.T) { + client, err := psi_client.CreateFromKey(clientKey, false) + if err != nil || client == nil { + t.Errorf("Failed to create a PSI client from key %v", err) + } + + newKey, err := client.GetPrivateKeyBytes() + if err != nil { + t.Errorf("Failed to create a new PSI client key %v", err) + } + if !bytes.Equal(clientKey, newKey) { + t.Errorf("new client invalid") + } + client.Destroy() + + server, err := psi_server.CreateFromKey(serverKey, false) + if err != nil || server == nil { + t.Errorf("Failed to create a PSI server from key %v", err) + } + + newKey, err = server.GetPrivateKeyBytes() + if err != nil { + t.Errorf("Failed to create a new PSI server key %v", err) + } + if !bytes.Equal(serverKey, newKey) { + t.Errorf("new server invalid") + } + server.Destroy() + +} +func TestIntegrationIntersection(t *testing.T) { + testCases := []struct { + revealIntersection bool + ds psi_ds.DataStructure + }{ + {true, psi_ds.Raw}, + {true, psi_ds.Gcs}, + {true, psi_ds.BloomFilter}, + {false, psi_ds.Raw}, + {false, psi_ds.Gcs}, + {false, psi_ds.BloomFilter}, + } + for _, tc := range testCases { + client, err := psi_client.CreateWithNewKey(tc.revealIntersection) + if err != nil { + t.Errorf("Failed to create a PSI client %v", err) + } + server, err := psi_server.CreateWithNewKey(tc.revealIntersection) + if err != nil { + t.Errorf("Failed to create a PSI server %v", err) + } + + clientInputs := []string{} + for i := 0; i < numClientInputs; i++ { + clientInputs = append(clientInputs, "Element "+string(i)) + } + serverInputs := []string{} + for i := 0; i < numServerInputs; i++ { + serverInputs = append(serverInputs, "Element "+string(i*2)) + } + + // Create the setup + serverSetup, err := server.CreateSetupMessage(fpr, int64(len(clientInputs)), serverInputs, 0) + if err != nil { + t.Errorf("Failed to create serverSetup: %v", err) + } + serializedServerSetup, err := proto.Marshal(serverSetup) + if err != nil { + t.Errorf("Failed to serialize serverSetup: %v", err) + } + + serverSetup = &psi_proto.ServerSetup{} + err = proto.Unmarshal(serializedServerSetup, serverSetup) + if err != nil { + t.Errorf("Failed to deserialize serverSetup: %v", err) + } + + // Create client request + request, err := client.CreateRequest(clientInputs) + if err != nil { + t.Errorf("Failed to create request %v", err) + } + serializedRequest, err := proto.Marshal(request) + if err != nil { + t.Errorf("Failed to serialize request: %v", err) + } + request = &psi_proto.Request{} + err = proto.Unmarshal(serializedRequest, request) + if err != nil { + t.Errorf("Failed to deserialize request: %v", err) + } + + // Get the response + response, err := server.ProcessRequest(request) + if err != nil { + t.Errorf("Failed to process request: %v", err) + } + serializedResponse, err := proto.Marshal(response) + if err != nil { + t.Errorf("Failed to serialize response: %v", err) + } + response = &psi_proto.Response{} + err = proto.Unmarshal(serializedResponse, response) + if err != nil { + t.Errorf("Failed to deserialize response: %v", err) + } + + // Compute intersection + if tc.revealIntersection { + intersection, err := client.GetIntersection(serverSetup, response) + if err != nil { + t.Errorf("failed to compute intersection %v", err) + } + intersectionSet := generateSet(intersection) + for idx := 0; idx < numClientInputs; idx++ { + _, ok := intersectionSet[idx] + if ok != (idx%2 == 0) { + t.Errorf("Invalid intersection for item %v %v", idx, ok) + } + } + } else { + intersectionCnt, err := client.GetIntersectionSize(serverSetup, response) + if err != nil { + t.Errorf("failed to compute intersection size %v", err) + } + + if int(intersectionCnt) < (numClientInputs / 2) { + t.Errorf("Invalid intersection. expected lower bound %v. got %v", (numClientInputs / 2), intersectionCnt) + } + + if float64(intersectionCnt) > float64(numClientInputs/2)*float64(1.1) { + t.Errorf("Invalid intersection. expected upper bound %v. got %v", float64(numClientInputs/2)*float64(1.1), intersectionCnt) + } + + } + + // cleanup + server.Destroy() + client.Destroy() + } +} diff --git a/private_set_intersection/go/server/BUILD b/private_set_intersection/go/server/BUILD index 241217d7..42c43632 100644 --- a/private_set_intersection/go/server/BUILD +++ b/private_set_intersection/go/server/BUILD @@ -8,9 +8,10 @@ go_library( importpath = "github.com/openmined/psi/server", visibility = ["//visibility:public"], deps = [ + "//private_set_intersection/go/datastructure", "//private_set_intersection/go/version", "//private_set_intersection/proto:psi_go_proto", - "@com_github_golang_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", ], ) diff --git a/private_set_intersection/go/server/server.go b/private_set_intersection/go/server/server.go index fefd7a92..72c31a23 100644 --- a/private_set_intersection/go/server/server.go +++ b/private_set_intersection/go/server/server.go @@ -71,9 +71,10 @@ import ( "runtime" "unsafe" - "github.com/golang/protobuf/proto" + psi_ds "github.com/openmined/psi/datastructure" psi_proto "github.com/openmined/psi/pb" "github.com/openmined/psi/version" + "google.golang.org/protobuf/proto" ) // PsiServer context for the server side of a Private Set Intersection protocol. @@ -139,7 +140,7 @@ func CreateFromKey(key []byte, revealIntersection bool) (*PsiServer, error) { // `bits` is encoded as Base64. // The false-positive rate `fpr` is the probability that any query of size // `num_client_inputs` will result in a false positive. -func (s *PsiServer) CreateSetupMessage(fpr float64, inputCount int64, rawInput []string) (*psi_proto.ServerSetup, error) { +func (s *PsiServer) CreateSetupMessage(fpr float64, inputCount int64, rawInput []string, ds psi_ds.DataStructure) (*psi_proto.ServerSetup, error) { if s.context == nil { return nil, errors.New("invalid context") } @@ -160,7 +161,7 @@ func (s *PsiServer) CreateSetupMessage(fpr float64, inputCount int64, rawInput [ if len(input) > 0 { inputPtr = &input[0] } - rcode := C.psi_server_create_setup_message(s.context, C.double(fpr), C.int64_t(inputCount), inputPtr, C.size_t(len(input)), &out, &outlen, &err) + rcode := C.psi_server_create_setup_message(s.context, C.double(fpr), C.int64_t(inputCount), inputPtr, C.size_t(len(input)), &out, &outlen, &err, C.datastructure_t(ds)) for idx := range input { C.free(unsafe.Pointer(input[idx].buff)) diff --git a/private_set_intersection/go/server/server_test.go b/private_set_intersection/go/server/server_test.go index 6559dfe1..c7bea7b7 100644 --- a/private_set_intersection/go/server/server_test.go +++ b/private_set_intersection/go/server/server_test.go @@ -1,11 +1,9 @@ package server import ( - "bytes" - "github.com/golang/protobuf/proto" "github.com/openmined/psi/client" + psi_ds "github.com/openmined/psi/datastructure" psi_proto "github.com/openmined/psi/pb" - "regexp" "testing" ) @@ -17,62 +15,13 @@ func generateItems(cnt int, m int) (int, []string) { return cnt, items } -func generateSet(in []int64) map[int]struct{} { - out := map[int]struct{}{} - for _, item := range in { - out[int(item)] = struct{}{} - } - - return out -} -func testServerSanity(t *testing.T, revealIntersection bool) { - server, err := CreateWithNewKey(revealIntersection) - if err != nil || server == nil { - t.Errorf("Failed to create a PSI server %v", err) - } - _, err = server.CreateSetupMessage(0.001, 1000, []string{}) - if err != nil { - t.Errorf("Should not fail on empty input %v", err) - } - key, err := server.GetPrivateKeyBytes() - if err != nil { - t.Errorf("Failed to create a PSI server key %v", err) - } - - newServer, err := CreateFromKey(key, revealIntersection) - if err != nil || newServer == nil { - t.Errorf("Failed to create a PSI server from key %v", err) - } - - newKey, err := newServer.GetPrivateKeyBytes() - if err != nil { - t.Errorf("Failed to create a new PSI server key %v", err) - } - if !bytes.Equal(key, newKey) { - t.Errorf("new server invalid") - } - server.Destroy() - for i := 0; i < 5; i++ { - server.Destroy() - } - - matched, _ := regexp.MatchString(`[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9]+)?`, server.Version()) - if !matched { - t.Errorf("Got invalid version %v", server.Version()) - } -} -func TestServerSanity(t *testing.T) { - testServerSanity(t, false) - testServerSanity(t, true) -} - func testServerFailure(t *testing.T, revealIntersection bool) { server := &PsiServer{} _, err := server.GetPrivateKeyBytes() if err == nil { t.Errorf("GetPrivateKeyBytes should fail with an invalid context %v", err) } - _, err = server.CreateSetupMessage(0.1, 100, []string{"dummy"}) + _, err = server.CreateSetupMessage(0.1, 100, []string{"dummy"}, psi_ds.Gcs) if err == nil { t.Errorf("CreateSetupMessage should fail with an invalid context %v", err) } @@ -102,186 +51,3 @@ func TestServerFailure(t *testing.T) { testServerFailure(t, false) testServerFailure(t, true) } - -func testServerClient(t *testing.T, revealIntersection bool) { - client, err := client.CreateWithNewKey(revealIntersection) - if err != nil || client == nil { - t.Errorf("Failed to create a PSI client %v", err) - } - - server, err := CreateWithNewKey(revealIntersection) - if err != nil || server == nil { - t.Errorf("Failed to create a PSI server %v", err) - } - - cntClientItems, clientItems := generateItems(1000, 1) - _, serverItems := generateItems(10000, 2) - - fpr := 1. / (1000000000) - setup, err := server.CreateSetupMessage(fpr, int64(cntClientItems), serverItems) - if err != nil { - t.Errorf("failed to create setup msg %v", err) - } - request, err := client.CreateRequest(clientItems) - if err != nil { - t.Errorf("failed to create request %v", err) - } - serverResp, err := server.ProcessRequest(request) - if err != nil { - t.Errorf("failed to process request %v", err) - } - - if revealIntersection { - intersection, err := client.GetIntersection(setup, serverResp) - if err != nil { - t.Errorf("failed to compute intersection %v", err) - } - intersectionSet := generateSet(intersection) - for idx := 0; idx < cntClientItems; idx++ { - _, ok := intersectionSet[idx] - if ok != (idx%2 == 0) { - t.Errorf("Invalid intersection for item %v", idx) - } - } - } else { - intersectionCnt, err := client.GetIntersectionSize(setup, serverResp) - if err != nil { - t.Errorf("failed to compute intersection %v", err) - } - - if int(intersectionCnt) < (cntClientItems / 2) { - t.Errorf("Invalid intersection. expected lower bound %v. got %v", (cntClientItems / 2), intersectionCnt) - } - - if float64(intersectionCnt) > float64(cntClientItems/2)*float64(1.1) { - t.Errorf("Invalid intersection. expected upper bound %v. got %v", float64(cntClientItems/2)*float64(1.1), intersectionCnt) - } - } -} - -func TestServerClient(t *testing.T) { - testServerClient(t, false) - testServerClient(t, true) -} - -var dummyString *psi_proto.ServerSetup - -func benchmarkServerSetup(cnt int, fpr float64, revealIntersection bool, b *testing.B) { - b.ReportAllocs() - total := 0 - - server, err := CreateWithNewKey(revealIntersection) - if err != nil || server == nil { - b.Errorf("failed to get server") - } - - inputs := []string{} - for i := 0; i < cnt; i++ { - inputs = append(inputs, "Element "+string(i)) - } - - numClientInputs := 10000 - - for n := 0; n < b.N; n++ { - setup, err := server.CreateSetupMessage(fpr, int64(numClientInputs), inputs) - if err != nil { - b.Errorf("failed to create setup msg %v", err) - } - total += cnt - //ugly hack for preventing compiler optimizations - dummyString = setup - } - b.ReportMetric(float64(total), "ElementsProcessed") -} - -const fpr3 = 0.001 -const fpr6 = 0.000001 - -func BenchmarkServerSetup1fpr3(b *testing.B) { benchmarkServerSetup(1, fpr3, false, b) } -func BenchmarkServerSetup10fpr3(b *testing.B) { benchmarkServerSetup(10, fpr3, false, b) } -func BenchmarkServerSetup100fpr3(b *testing.B) { benchmarkServerSetup(100, fpr3, false, b) } -func BenchmarkServerSetup1000fpr3(b *testing.B) { benchmarkServerSetup(1000, fpr3, false, b) } -func BenchmarkServerSetup10000fpr3(b *testing.B) { benchmarkServerSetup(10000, fpr3, false, b) } -func BenchmarkServerSetupIntersection1fpr3(b *testing.B) { benchmarkServerSetup(1, fpr3, true, b) } -func BenchmarkServerSetupIntersection10fpr3(b *testing.B) { benchmarkServerSetup(10, fpr3, true, b) } -func BenchmarkServerSetupIntersection100fpr3(b *testing.B) { benchmarkServerSetup(100, fpr3, true, b) } -func BenchmarkServerSetupIntersection1000fpr3(b *testing.B) { - benchmarkServerSetup(1000, fpr3, true, b) -} -func BenchmarkServerSetupIntersection10000fpr3(b *testing.B) { - benchmarkServerSetup(10000, fpr3, true, b) -} - -func BenchmarkServerSetup1fpr6(b *testing.B) { benchmarkServerSetup(1, fpr6, false, b) } -func BenchmarkServerSetup10fpr6(b *testing.B) { benchmarkServerSetup(10, fpr6, false, b) } -func BenchmarkServerSetup100fpr6(b *testing.B) { benchmarkServerSetup(100, fpr6, false, b) } -func BenchmarkServerSetup1000fpr6(b *testing.B) { benchmarkServerSetup(1000, fpr6, false, b) } -func BenchmarkServerSetup10000fpr6(b *testing.B) { benchmarkServerSetup(10000, fpr6, false, b) } -func BenchmarkServerSetupIntersection1fpr6(b *testing.B) { benchmarkServerSetup(1, fpr6, true, b) } -func BenchmarkServerSetupIntersection10fpr6(b *testing.B) { benchmarkServerSetup(10, fpr6, true, b) } -func BenchmarkServerSetupIntersection100fpr6(b *testing.B) { benchmarkServerSetup(100, fpr6, true, b) } -func BenchmarkServerSetupIntersection1000fpr6(b *testing.B) { - benchmarkServerSetup(1000, fpr6, true, b) -} -func BenchmarkServerSetupIntersection10000fpr6(b *testing.B) { - benchmarkServerSetup(10000, fpr6, true, b) -} - -var dummyResponse *psi_proto.Response - -func benchmarkServerProcessRequest(cnt int, revealIntersection bool, b *testing.B) { - b.ReportAllocs() - total := 0 - - client, err := client.CreateWithNewKey(revealIntersection) - if err != nil || client == nil { - b.Errorf("failed to get client") - } - server, err := CreateWithNewKey(revealIntersection) - if err != nil || server == nil { - b.Errorf("failed to get server") - } - - inputs := []string{} - for i := 0; i < cnt; i++ { - inputs = append(inputs, "Element "+string(i)) - } - - request, err := client.CreateRequest(inputs) - if err != nil { - b.Errorf("failed to create request %v", err) - } - - for n := 0; n < b.N; n++ { - serverResp, err := server.ProcessRequest(request) - if err != nil { - b.Errorf("failed to process request %v", err) - } - total += cnt - b.ReportMetric(float64(proto.Size(serverResp)), "ResponseSize") - //ugly hack for preventing compiler optimizations - dummyResponse = serverResp - } - b.ReportMetric(float64(total), "ElementsProcessed") -} - -func BenchmarkServerProcessRequest1(b *testing.B) { benchmarkServerProcessRequest(1, false, b) } -func BenchmarkServerProcessRequest10(b *testing.B) { benchmarkServerProcessRequest(10, false, b) } -func BenchmarkServerProcessRequest100(b *testing.B) { benchmarkServerProcessRequest(100, false, b) } -func BenchmarkServerProcessRequest1000(b *testing.B) { benchmarkServerProcessRequest(1000, false, b) } -func BenchmarkServerProcessRequest10000(b *testing.B) { benchmarkServerProcessRequest(10000, false, b) } -func BenchmarkServerProcessRequestIntersection1(b *testing.B) { - benchmarkServerProcessRequest(1, true, b) -} -func BenchmarkServerProcessRequestIntersection10(b *testing.B) { - benchmarkServerProcessRequest(10, true, b) -} -func BenchmarkServerProcessRequestIntersection100(b *testing.B) { - benchmarkServerProcessRequest(100, true, b) -} -func BenchmarkServerProcessRequestIntersection1000(b *testing.B) { - benchmarkServerProcessRequest(1000, true, b) -} -func BenchmarkServerProcessRequestIntersection10000(b *testing.B) { - benchmarkServerProcessRequest(10000, true, b) -} diff --git a/private_set_intersection/javascript/cpp/data_structure.cpp b/private_set_intersection/javascript/cpp/data_structure.cpp index 59e66dbc..c6f2a008 100644 --- a/private_set_intersection/javascript/cpp/data_structure.cpp +++ b/private_set_intersection/javascript/cpp/data_structure.cpp @@ -4,6 +4,7 @@ EMSCRIPTEN_BINDINGS(PSI_DataStructure) { using private_set_intersection::DataStructure; emscripten::enum_("DataStructure") - .value("BloomFilter", DataStructure::BloomFilter) - .value("GCS", DataStructure::GCS); + .value("Raw", DataStructure::Raw) + .value("GCS", DataStructure::Gcs) + .value("BloomFilter", DataStructure::BloomFilter); } diff --git a/private_set_intersection/javascript/custom_types/psi/index.d.ts b/private_set_intersection/javascript/custom_types/psi/index.d.ts index df4de9fa..b7db4cee 100644 --- a/private_set_intersection/javascript/custom_types/psi/index.d.ts +++ b/private_set_intersection/javascript/custom_types/psi/index.d.ts @@ -64,8 +64,9 @@ declare module 'psi_*' { } export type DataStructure = { - readonly BloomFilter: any + readonly Raw: any readonly GCS: any + readonly BloomFilter: any } export type Library = { diff --git a/private_set_intersection/javascript/src/__tests__/client.test.ts b/private_set_intersection/javascript/src/__tests__/client.test.ts index 4045f91c..784c385b 100644 --- a/private_set_intersection/javascript/src/__tests__/client.test.ts +++ b/private_set_intersection/javascript/src/__tests__/client.test.ts @@ -9,42 +9,6 @@ beforeAll(async () => { }) describe('PSI Client', () => { - test('It should create from an existing key', async () => { - const client1 = psi.client!.createWithNewKey() - const key = client1.getPrivateKeyBytes() - - const client2 = psi.client!.createFromKey(key) - - expect(client2.getPrivateKeyBytes()).toEqual(key) - }) - - test('It should fail to create from an invalid key', async () => { - const key = Uint8Array.from({ length: 32 }) - expect(() => psi.client!.createFromKey(key)).toThrow() - }) - test('It should throw if deleted twice', async () => { - const client = psi.client!.createWithNewKey() - - client.delete() - - expect(client.delete).toThrow(ERROR_INSTANCE_DELETED) - }) - - test('It should return the private key as a binary array', async () => { - const client = psi.client!.createWithNewKey() - const keyLength = 32 - const key = client.getPrivateKeyBytes() - expect(key.length).toBe(keyLength) - }) - - test('It should fail return the private key as a binary array if deleted', async () => { - const client = psi.client!.createWithNewKey() - client.delete() - expect(client.getPrivateKeyBytes.bind(client)).toThrow( - ERROR_INSTANCE_DELETED - ) - }) - test('It should create a request', async () => { const client = psi.client!.createWithNewKey() const numClientElements = 10 @@ -74,256 +38,6 @@ describe('PSI Client', () => { ) }) - test('It should process a response (cardinality) [GCS]', async () => { - // prettier-ignore - const key = Uint8Array.from([ - 160, 193, 102, 5, 219, 141, 42, 183, - 157, 180, 97, 194, 33, 176, 95, 191, - 77, 185, 205, 139, 61, 124, 1, 178, - 198, 110, 236, 127, 64, 242, 152, 15 - ]) - const client = psi.client!.createFromKey(key) - - // prettier-ignore - const serverSetup = ServerSetup.deserializeBinary(Uint8Array.from([ - 10, 6, 8, 9, 16, 160, 141, 6, 26, 145, 1, 156, - 124, 83, 130, 180, 41, 13, 249, 1, 160, 66, 225, 180, - 102, 13, 186, 232, 132, 241, 96, 160, 28, 76, 132, 180, - 174, 0, 237, 108, 36, 157, 81, 137, 81, 127, 152, 70, - 60, 101, 15, 115, 201, 88, 204, 220, 14, 190, 136, 164, - 2, 51, 141, 245, 160, 62, 55, 221, 23, 64, 22, 143, - 242, 126, 57, 222, 180, 110, 125, 196, 1, 162, 228, 13, - 133, 2, 63, 225, 105, 72, 148, 234, 184, 79, 143, 204, - 148, 80, 122, 239, 70, 226, 93, 105, 118, 117, 46, 120, - 4, 12, 47, 87, 126, 245, 6, 135, 24, 21, 228, 145, - 49, 194, 180, 50, 255, 21, 233, 166, 226, 140, 5, 77, - 7, 131, 118, 88, 132, 233, 2, 147, 128, 83, 16, 242, - 171, 197, 88, 9, 148, 22, 129, 12, 112, 149, 170, 1 - ])) - - // prettier-ignore - const response = Response.deserializeBinary(Uint8Array.from([ - 10, 33, 3, 76, 217, 211, 215, 254, 176, 87, 33, 177, - 111, 184, 131, 7, 251, 172, 119, 48, 58, 156, 152, 18, - 186, 184, 140, 122, 119, 253, 134, 206, 216, 193, 5, 10, - 33, 3, 153, 37, 67, 82, 212, 45, 237, 208, 191, 226, - 31, 75, 233, 165, 62, 126, 69, 93, 227, 207, 61, 22, - 84, 196, 196, 73, 96, 234, 110, 75, 170, 229, 10, 33, - 3, 141, 219, 163, 220, 158, 79, 10, 77, 55, 211, 205, - 67, 160, 141, 61, 149, 156, 88, 126, 72, 94, 213, 42, - 126, 245, 177, 50, 34, 90, 129, 193, 165, 10, 33, 2, - 78, 83, 208, 113, 10, 63, 19, 208, 30, 134, 222, 189, - 84, 35, 204, 184, 42, 23, 60, 138, 236, 88, 161, 35, - 156, 54, 227, 58, 86, 22, 232, 116, 10, 33, 3, 159, - 214, 143, 126, 207, 205, 25, 47, 174, 247, 87, 223, 117, - 48, 106, 60, 203, 131, 125, 78, 8, 249, 141, 91, 214, - 249, 239, 171, 120, 178, 50, 59, 10, 33, 3, 52, 239, - 62, 190, 198, 211, 210, 185, 126, 26, 167, 170, 51, 218, - 14, 121, 114, 68, 0, 99, 25, 198, 74, 169, 235, 245, - 13, 234, 188, 200, 24, 150, 10, 33, 2, 36, 121, 159, - 69, 8, 220, 251, 171, 213, 97, 193, 228, 171, 161, 171, - 186, 96, 145, 190, 8, 174, 33, 160, 163, 214, 69, 0, - 165, 161, 92, 94, 165, 10, 33, 2, 196, 108, 146, 176, - 132, 215, 102, 87, 221, 29, 248, 65, 53, 145, 120, 220, - 34, 136, 76, 91, 188, 35, 117, 239, 171, 174, 132, 154, - 125, 50, 254, 158, 10, 33, 2, 34, 245, 53, 64, 84, - 70, 211, 155, 133, 221, 136, 142, 173, 212, 234, 129, 0, - 88, 99, 234, 212, 131, 188, 129, 174, 168, 95, 42, 131, - 108, 120, 197, 10, 33, 3, 231, 207, 242, 34, 77, 41, - 49, 61, 155, 163, 188, 51, 90, 70, 1, 15, 189, 140, - 231, 10, 53, 120, 90, 155, 163, 88, 209, 165, 234, 47, - 4, 126 - ])) - - const intersection = client.getIntersectionSize(serverSetup, response) - expect(intersection).toStrictEqual(0) - }) - - test('It should process a response (intersection)', async () => { - // prettier-ignore - const key = Uint8Array.from([ - 160, 193, 102, 5, 219, 141, 42, 183, - 157, 180, 97, 194, 33, 176, 95, 191, - 77, 185, 205, 139, 61, 124, 1, 178, - 198, 110, 236, 127, 64, 242, 152, 15 - ]) - const client = psi.client!.createFromKey(key, true) - - // prettier-ignore - const serverSetup = ServerSetup.deserializeBinary(Uint8Array.from([ - 10, 6, 8, 9, 16, 160, 141, 6, 26, 145, 1, 156, - 124, 83, 130, 180, 41, 13, 249, 1, 160, 66, 225, 180, - 102, 13, 186, 232, 132, 241, 96, 160, 28, 76, 132, 180, - 174, 0, 237, 108, 36, 157, 81, 137, 81, 127, 152, 70, - 60, 101, 15, 115, 201, 88, 204, 220, 14, 190, 136, 164, - 2, 51, 141, 245, 160, 62, 55, 221, 23, 64, 22, 143, - 242, 126, 57, 222, 180, 110, 125, 196, 1, 162, 228, 13, - 133, 2, 63, 225, 105, 72, 148, 234, 184, 79, 143, 204, - 148, 80, 122, 239, 70, 226, 93, 105, 118, 117, 46, 120, - 4, 12, 47, 87, 126, 245, 6, 135, 24, 21, 228, 145, - 49, 194, 180, 50, 255, 21, 233, 166, 226, 140, 5, 77, - 7, 131, 118, 88, 132, 233, 2, 147, 128, 83, 16, 242, - 171, 197, 88, 9, 148, 22, 129, 12, 112, 149, 170, 1 - ])) - - // prettier-ignore - const response = Response.deserializeBinary(Uint8Array.from([ - 10, 33, 3, 76, 217, 211, 215, 254, 176, 87, 33, 177, - 111, 184, 131, 7, 251, 172, 119, 48, 58, 156, 152, 18, - 186, 184, 140, 122, 119, 253, 134, 206, 216, 193, 5, 10, - 33, 3, 153, 37, 67, 82, 212, 45, 237, 208, 191, 226, - 31, 75, 233, 165, 62, 126, 69, 93, 227, 207, 61, 22, - 84, 196, 196, 73, 96, 234, 110, 75, 170, 229, 10, 33, - 3, 141, 219, 163, 220, 158, 79, 10, 77, 55, 211, 205, - 67, 160, 141, 61, 149, 156, 88, 126, 72, 94, 213, 42, - 126, 245, 177, 50, 34, 90, 129, 193, 165, 10, 33, 2, - 78, 83, 208, 113, 10, 63, 19, 208, 30, 134, 222, 189, - 84, 35, 204, 184, 42, 23, 60, 138, 236, 88, 161, 35, - 156, 54, 227, 58, 86, 22, 232, 116, 10, 33, 3, 159, - 214, 143, 126, 207, 205, 25, 47, 174, 247, 87, 223, 117, - 48, 106, 60, 203, 131, 125, 78, 8, 249, 141, 91, 214, - 249, 239, 171, 120, 178, 50, 59, 10, 33, 3, 52, 239, - 62, 190, 198, 211, 210, 185, 126, 26, 167, 170, 51, 218, - 14, 121, 114, 68, 0, 99, 25, 198, 74, 169, 235, 245, - 13, 234, 188, 200, 24, 150, 10, 33, 2, 36, 121, 159, - 69, 8, 220, 251, 171, 213, 97, 193, 228, 171, 161, 171, - 186, 96, 145, 190, 8, 174, 33, 160, 163, 214, 69, 0, - 165, 161, 92, 94, 165, 10, 33, 2, 196, 108, 146, 176, - 132, 215, 102, 87, 221, 29, 248, 65, 53, 145, 120, 220, - 34, 136, 76, 91, 188, 35, 117, 239, 171, 174, 132, 154, - 125, 50, 254, 158, 10, 33, 2, 34, 245, 53, 64, 84, - 70, 211, 155, 133, 221, 136, 142, 173, 212, 234, 129, 0, - 88, 99, 234, 212, 131, 188, 129, 174, 168, 95, 42, 131, - 108, 120, 197, 10, 33, 3, 231, 207, 242, 34, 77, 41, - 49, 61, 155, 163, 188, 51, 90, 70, 1, 15, 189, 140, - 231, 10, 53, 120, 90, 155, 163, 88, 209, 165, 234, 47, - 4, 126 - ])) - - const intersection = client.getIntersection(serverSetup, response) - expect(intersection).toStrictEqual([]) - }) - - test('It should throw if attempting to process a response after deletion (cardinality)', async () => { - const client = psi.client!.createWithNewKey() - // prettier-ignore - const serverSetup = ServerSetup.deserializeBinary(Uint8Array.from([ - 10, 6, 8, 9, 16, 160, 141, 6, 26, 145, 1, 156, - 124, 83, 130, 180, 41, 13, 249, 1, 160, 66, 225, 180, - 102, 13, 186, 232, 132, 241, 96, 160, 28, 76, 132, 180, - 174, 0, 237, 108, 36, 157, 81, 137, 81, 127, 152, 70, - 60, 101, 15, 115, 201, 88, 204, 220, 14, 190, 136, 164, - 2, 51, 141, 245, 160, 62, 55, 221, 23, 64, 22, 143, - 242, 126, 57, 222, 180, 110, 125, 196, 1, 162, 228, 13, - 133, 2, 63, 225, 105, 72, 148, 234, 184, 79, 143, 204, - 148, 80, 122, 239, 70, 226, 93, 105, 118, 117, 46, 120, - 4, 12, 47, 87, 126, 245, 6, 135, 24, 21, 228, 145, - 49, 194, 180, 50, 255, 21, 233, 166, 226, 140, 5, 77, - 7, 131, 118, 88, 132, 233, 2, 147, 128, 83, 16, 242, - 171, 197, 88, 9, 148, 22, 129, 12, 112, 149, 170, 1 - ])) - - // prettier-ignore - const response = Response.deserializeBinary(Uint8Array.from([ - 10, 33, 3, 76, 217, 211, 215, 254, 176, 87, 33, 177, - 111, 184, 131, 7, 251, 172, 119, 48, 58, 156, 152, 18, - 186, 184, 140, 122, 119, 253, 134, 206, 216, 193, 5, 10, - 33, 3, 153, 37, 67, 82, 212, 45, 237, 208, 191, 226, - 31, 75, 233, 165, 62, 126, 69, 93, 227, 207, 61, 22, - 84, 196, 196, 73, 96, 234, 110, 75, 170, 229, 10, 33, - 3, 141, 219, 163, 220, 158, 79, 10, 77, 55, 211, 205, - 67, 160, 141, 61, 149, 156, 88, 126, 72, 94, 213, 42, - 126, 245, 177, 50, 34, 90, 129, 193, 165, 10, 33, 2, - 78, 83, 208, 113, 10, 63, 19, 208, 30, 134, 222, 189, - 84, 35, 204, 184, 42, 23, 60, 138, 236, 88, 161, 35, - 156, 54, 227, 58, 86, 22, 232, 116, 10, 33, 3, 159, - 214, 143, 126, 207, 205, 25, 47, 174, 247, 87, 223, 117, - 48, 106, 60, 203, 131, 125, 78, 8, 249, 141, 91, 214, - 249, 239, 171, 120, 178, 50, 59, 10, 33, 3, 52, 239, - 62, 190, 198, 211, 210, 185, 126, 26, 167, 170, 51, 218, - 14, 121, 114, 68, 0, 99, 25, 198, 74, 169, 235, 245, - 13, 234, 188, 200, 24, 150, 10, 33, 2, 36, 121, 159, - 69, 8, 220, 251, 171, 213, 97, 193, 228, 171, 161, 171, - 186, 96, 145, 190, 8, 174, 33, 160, 163, 214, 69, 0, - 165, 161, 92, 94, 165, 10, 33, 2, 196, 108, 146, 176, - 132, 215, 102, 87, 221, 29, 248, 65, 53, 145, 120, 220, - 34, 136, 76, 91, 188, 35, 117, 239, 171, 174, 132, 154, - 125, 50, 254, 158, 10, 33, 2, 34, 245, 53, 64, 84, - 70, 211, 155, 133, 221, 136, 142, 173, 212, 234, 129, 0, - 88, 99, 234, 212, 131, 188, 129, 174, 168, 95, 42, 131, - 108, 120, 197, 10, 33, 3, 231, 207, 242, 34, 77, 41, - 49, 61, 155, 163, 188, 51, 90, 70, 1, 15, 189, 140, - 231, 10, 53, 120, 90, 155, 163, 88, 209, 165, 234, 47, - 4, 126 - ])) - - client.delete() - - expect( - client.getIntersectionSize.bind(client, serverSetup, response) - ).toThrow(ERROR_INSTANCE_DELETED) - }) - - test('It should throw if attempting to process a response after deletion (intersection)', async () => { - const client = psi.client!.createWithNewKey(true) - // prettier-ignore - const serverSetup = ServerSetup.deserializeBinary(Uint8Array.from([ - 10, 6, 8, 9, 16, 160, 141, 6, 26, 145, 1, 156, - 124, 83, 130, 180, 41, 13, 249, 1, 160, 66, 225, 180, - 102, 13, 186, 232, 132, 241, 96, 160, 28, 76, 132, 180, - 174, 0, 237, 108, 36, 157, 81, 137, 81, 127, 152, 70, - 60, 101, 15, 115, 201, 88, 204, 220, 14, 190, 136, 164, - 2, 51, 141, 245, 160, 62, 55, 221, 23, 64, 22, 143, - 242, 126, 57, 222, 180, 110, 125, 196, 1, 162, 228, 13, - 133, 2, 63, 225, 105, 72, 148, 234, 184, 79, 143, 204, - 148, 80, 122, 239, 70, 226, 93, 105, 118, 117, 46, 120, - 4, 12, 47, 87, 126, 245, 6, 135, 24, 21, 228, 145, - 49, 194, 180, 50, 255, 21, 233, 166, 226, 140, 5, 77, - 7, 131, 118, 88, 132, 233, 2, 147, 128, 83, 16, 242, - 171, 197, 88, 9, 148, 22, 129, 12, 112, 149, 170, 1 - ])) - - // prettier-ignore - const response = Response.deserializeBinary(Uint8Array.from([ - 10, 33, 3, 76, 217, 211, 215, 254, 176, 87, 33, 177, - 111, 184, 131, 7, 251, 172, 119, 48, 58, 156, 152, 18, - 186, 184, 140, 122, 119, 253, 134, 206, 216, 193, 5, 10, - 33, 3, 153, 37, 67, 82, 212, 45, 237, 208, 191, 226, - 31, 75, 233, 165, 62, 126, 69, 93, 227, 207, 61, 22, - 84, 196, 196, 73, 96, 234, 110, 75, 170, 229, 10, 33, - 3, 141, 219, 163, 220, 158, 79, 10, 77, 55, 211, 205, - 67, 160, 141, 61, 149, 156, 88, 126, 72, 94, 213, 42, - 126, 245, 177, 50, 34, 90, 129, 193, 165, 10, 33, 2, - 78, 83, 208, 113, 10, 63, 19, 208, 30, 134, 222, 189, - 84, 35, 204, 184, 42, 23, 60, 138, 236, 88, 161, 35, - 156, 54, 227, 58, 86, 22, 232, 116, 10, 33, 3, 159, - 214, 143, 126, 207, 205, 25, 47, 174, 247, 87, 223, 117, - 48, 106, 60, 203, 131, 125, 78, 8, 249, 141, 91, 214, - 249, 239, 171, 120, 178, 50, 59, 10, 33, 3, 52, 239, - 62, 190, 198, 211, 210, 185, 126, 26, 167, 170, 51, 218, - 14, 121, 114, 68, 0, 99, 25, 198, 74, 169, 235, 245, - 13, 234, 188, 200, 24, 150, 10, 33, 2, 36, 121, 159, - 69, 8, 220, 251, 171, 213, 97, 193, 228, 171, 161, 171, - 186, 96, 145, 190, 8, 174, 33, 160, 163, 214, 69, 0, - 165, 161, 92, 94, 165, 10, 33, 2, 196, 108, 146, 176, - 132, 215, 102, 87, 221, 29, 248, 65, 53, 145, 120, 220, - 34, 136, 76, 91, 188, 35, 117, 239, 171, 174, 132, 154, - 125, 50, 254, 158, 10, 33, 2, 34, 245, 53, 64, 84, - 70, 211, 155, 133, 221, 136, 142, 173, 212, 234, 129, 0, - 88, 99, 234, 212, 131, 188, 129, 174, 168, 95, 42, 131, - 108, 120, 197, 10, 33, 3, 231, 207, 242, 34, 77, 41, - 49, 61, 155, 163, 188, 51, 90, 70, 1, 15, 189, 140, - 231, 10, 53, 120, 90, 155, 163, 88, 209, 165, 234, 47, - 4, 126 - ])) - - client.delete() - - expect(client.getIntersection.bind(client, serverSetup, response)).toThrow( - ERROR_INSTANCE_DELETED - ) - }) - test('It should fail to process a response (cardinality)', async () => { const client = psi.client!.createWithNewKey() const serverSetup = new ServerSetup() diff --git a/private_set_intersection/javascript/src/__tests__/integration.test.ts b/private_set_intersection/javascript/src/__tests__/integration.test.ts index d61b3549..2b79ddb6 100644 --- a/private_set_intersection/javascript/src/__tests__/integration.test.ts +++ b/private_set_intersection/javascript/src/__tests__/integration.test.ts @@ -1,135 +1,105 @@ import PSI from '../wasm_node' import { PSILibrary } from '../implementation/psi' +const clientKey = Uint8Array.from([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +]) +const serverKey = Uint8Array.from([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +]) +const fpr = 0.01 +const numClientElements = 10 +const numServerElements = 100 +const clientInputs = Array.from( + { length: numClientElements }, + (_, i) => `Element ${i}` +) +const serverInputs = Array.from( + { length: numServerElements }, + (_, i) => `Element ${i * 2}` +) let psi: PSILibrary + beforeAll(async () => { psi = await PSI() }) describe('PSI Integration', () => { - test('It should return the intersection (GCS)', async () => { - const client = psi.client!.createWithNewKey(true) - const key = Uint8Array.from( - // eslint-disable-next-line no-undef - Buffer.from('djY2Bgt4JwfbjvJn6dDzpwrTvKWVE1Ks458mlrd1/tY=', 'base64') - ) - const server = psi.server!.createFromKey(key, true) - const fpr = 0.01 - const numClientElements = 10 - const numServerElements = 100 - const clientInputs = Array.from( - { length: numClientElements }, - (_, i) => `Element ${i}` - ) - const serverInputs = Array.from( - { length: numServerElements }, - (_, i) => `Element ${i * 2}` - ) - const serverSetup = server.createSetupMessage( - fpr, - numClientElements, - serverInputs, - psi.dataStructure.GCS - ) - - const clientRequest = client.createRequest(clientInputs) - const serverResponse = server.processRequest(clientRequest) - const intersection = client.getIntersection(serverSetup, serverResponse) - // Test that the intersection is within 10% error margin to match `fpr` - expect(intersection.length).toBeGreaterThanOrEqual(numClientElements / 2) - expect(intersection.length).toBeLessThan((numClientElements / 2) * 1.1) + test('should return a version string', async () => { + expect(typeof psi.package.version).toBe('string') }) - test('It should return the intersection size (GCS)', async () => { - const client = psi.client!.createWithNewKey() - const key = Uint8Array.from( - // eslint-disable-next-line no-undef - Buffer.from('djY2Bgt4JwfbjvJn6dDzpwrTvKWVE1Ks458mlrd1/tY=', 'base64') - ) - const server = psi.server!.createFromKey(key) - const fpr = 0.01 - const numClientElements = 10 - const numServerElements = 100 - const clientInputs = Array.from( - { length: numClientElements }, - (_, i) => `Element ${i}` - ) - const serverInputs = Array.from( - { length: numServerElements }, - (_, i) => `Element ${i * 2}` - ) - const serverSetup = server.createSetupMessage( - fpr, - numClientElements, - serverInputs, - psi.dataStructure.GCS - ) - const clientRequest = client.createRequest(clientInputs) - const serverResponse = server.processRequest(clientRequest) - const intersection = client.getIntersectionSize(serverSetup, serverResponse) - // Test that the intersection is within 10% error margin to match `fpr` - expect(intersection).toBeGreaterThanOrEqual(numClientElements / 2) - expect(intersection).toBeLessThan((numClientElements / 2) * 1.1) - }) - test('It should return the intersection (BloomFilter)', async () => { - const client = psi.client!.createWithNewKey(true) - const key = Uint8Array.from( - // eslint-disable-next-line no-undef - Buffer.from('djY2Bgt4JwfbjvJn6dDzpwrTvKWVE1Ks458mlrd1/tY=', 'base64') - ) - const server = psi.server!.createFromKey(key, true) - const fpr = 0.01 - const numClientElements = 10 - const numServerElements = 100 - const clientInputs = Array.from( - { length: numClientElements }, - (_, i) => `Element ${i}` - ) - const serverInputs = Array.from( - { length: numServerElements }, - (_, i) => `Element ${i * 2}` - ) - const serverSetup = server.createSetupMessage( - fpr, - numClientElements, - serverInputs, - psi.dataStructure.BloomFilter - ) - const clientRequest = client.createRequest(clientInputs) - const serverResponse = server.processRequest(clientRequest) - const intersection = client.getIntersection(serverSetup, serverResponse) - // Test that the intersection is within 10% error margin to match `fpr` - expect(intersection.length).toBeGreaterThanOrEqual(numClientElements / 2) - expect(intersection.length).toBeLessThan((numClientElements / 2) * 1.1) + + test('It should create from a static key', async () => { + const server = psi.server!.createFromKey(serverKey, false) + expect(server.getPrivateKeyBytes()).toEqual(serverKey) + const client = psi.client!.createFromKey(clientKey, false) + expect(client.getPrivateKeyBytes()).toEqual(clientKey) }) - test('It should return the intersection size (BloomFilter)', async () => { - const client = psi.client!.createWithNewKey() - const key = Uint8Array.from( - // eslint-disable-next-line no-undef - Buffer.from('djY2Bgt4JwfbjvJn6dDzpwrTvKWVE1Ks458mlrd1/tY=', 'base64') - ) - const server = psi.server!.createFromKey(key) - const fpr = 0.01 - const numClientElements = 10 - const numServerElements = 100 - const clientInputs = Array.from( - { length: numClientElements }, - (_, i) => `Element ${i}` - ) - const serverInputs = Array.from( - { length: numServerElements }, - (_, i) => `Element ${i * 2}` - ) - const serverSetup = server.createSetupMessage( - fpr, - numClientElements, - serverInputs, - psi.dataStructure.BloomFilter - ) - const clientRequest = client.createRequest(clientInputs) - const serverResponse = server.processRequest(clientRequest) - const intersection = client.getIntersectionSize(serverSetup, serverResponse) - // Test that the intersection is within 10% error margin to match `fpr` - expect(intersection).toBeGreaterThanOrEqual(numClientElements / 2) - expect(intersection).toBeLessThan((numClientElements / 2) * 1.1) + + test('should compute the intersection', async () => { + ;[ + { revealIntersection: true, dataStructure: psi.dataStructure.Raw }, + { revealIntersection: true, dataStructure: psi.dataStructure.GCS }, + { + revealIntersection: true, + dataStructure: psi.dataStructure.BloomFilter + }, + { revealIntersection: false, dataStructure: psi.dataStructure.Raw }, + { revealIntersection: false, dataStructure: psi.dataStructure.GCS }, + { + revealIntersection: false, + dataStructure: psi.dataStructure.BloomFilter + } + ].forEach(({ revealIntersection, dataStructure }) => { + const client = psi.client!.createWithNewKey(revealIntersection) + const server = psi.server!.createWithNewKey(revealIntersection) + + const serverSetup = server + .createSetupMessage(fpr, numClientElements, serverInputs, dataStructure) + .serializeBinary() + + const clientRequest = client.createRequest(clientInputs).serializeBinary() + const serverResponse = server + .processRequest(psi.request.deserializeBinary(clientRequest)) + .serializeBinary() + + if (revealIntersection === true) { + const intersection = client.getIntersection( + psi.serverSetup.deserializeBinary(serverSetup), + psi.response.deserializeBinary(serverResponse) + ) + const iset = new Set(intersection) + for (let idx = 0; idx < numClientElements; idx++) { + if (idx % 2 === 0) { + // eslint-disable-next-line jest/no-conditional-expect + expect(iset.has(idx)).toBeTruthy() + } else { + // eslint-disable-next-line jest/no-conditional-expect + expect(iset.has(idx)).toBeFalsy() + } + // Test that the intersection is within 10% error margin to match `fpr` + // eslint-disable-next-line jest/no-conditional-expect + expect(intersection.length).toBeGreaterThanOrEqual( + numClientElements / 2 + ) + // eslint-disable-next-line jest/no-conditional-expect + expect(intersection.length).toBeLessThan( + (numClientElements / 2) * 1.1 + ) + } + } else { + const intersection = client.getIntersectionSize( + psi.serverSetup.deserializeBinary(serverSetup), + psi.response.deserializeBinary(serverResponse) + ) + // Test that the intersection is within 10% error margin to match `fpr` + // eslint-disable-next-line jest/no-conditional-expect + expect(intersection).toBeGreaterThanOrEqual(numClientElements / 2) + // eslint-disable-next-line jest/no-conditional-expect + expect(intersection).toBeLessThan((numClientElements / 2) * 1.1) + } + }) }) }) diff --git a/private_set_intersection/javascript/src/__tests__/package.test.ts b/private_set_intersection/javascript/src/__tests__/package.test.ts deleted file mode 100644 index 35727cdd..00000000 --- a/private_set_intersection/javascript/src/__tests__/package.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import PSI from '../wasm_node' -import { PSILibrary } from '../implementation/psi' - -let psi: PSILibrary -beforeAll(async () => { - psi = await PSI() -}) - -describe('PSI Package', () => { - test('It should return the version string', async () => { - const { version } = psi.package - expect(typeof version).toBe('string') - }) -}) diff --git a/private_set_intersection/javascript/src/__tests__/server.test.ts b/private_set_intersection/javascript/src/__tests__/server.test.ts index a7c97353..9fafa442 100644 --- a/private_set_intersection/javascript/src/__tests__/server.test.ts +++ b/private_set_intersection/javascript/src/__tests__/server.test.ts @@ -1,7 +1,6 @@ import PSI from '../wasm_node' import { ERROR_INSTANCE_DELETED } from '../implementation/constants' import { PSILibrary } from '../implementation/psi' -import { Request, Response } from '../implementation/proto/psi_pb' let psi: PSILibrary beforeAll(async () => { @@ -9,42 +8,9 @@ beforeAll(async () => { }) describe('PSI Server', () => { - test('It should create from an existing key', async () => { - const server1 = psi.server!.createWithNewKey() - const key = server1.getPrivateKeyBytes() - - const server2 = psi.server!.createFromKey(key) - - expect(server2.getPrivateKeyBytes()).toEqual(key) - }) - - test('It should fail to create from an invalid key', async () => { - const key = Uint8Array.from({ length: 32 }) - expect(() => psi.server!.createFromKey(key)).toThrow() - }) - - test('It should throw if deleted twice', async () => { - const server = psi.server!.createWithNewKey() - server.delete() - expect(server.delete).toThrow(ERROR_INSTANCE_DELETED) - }) - - test('It should return the private key as a binary array', async () => { - const server = psi.server!.createWithNewKey() - const keyLength = 32 - const key = server.getPrivateKeyBytes() - expect(key.length).toBe(keyLength) - }) - - test('It should fail return the private key as a binary array if deleted', async () => { - const server = psi.server!.createWithNewKey() - server.delete() - expect(() => server.getPrivateKeyBytes()).toThrow(ERROR_INSTANCE_DELETED) - }) - test('It should create a setup message (BloomFilter)', async () => { const server = psi.server!.createWithNewKey() - const fpr = 0.001 + const fpr = 0.01 const numClientElements = 10 const serverInputs = Array.from({ length: 100 }, (_, i) => `Element ${i}`) @@ -56,14 +22,14 @@ describe('PSI Server', () => { ) const numHashFunctions = setup.getBloomFilter()!.getNumHashFunctions() - expect(numHashFunctions).toStrictEqual(14) - const bits = setup.getBits() + expect(numHashFunctions).toStrictEqual(10) + const bits = setup.getBloomFilter()!.getBits() expect(bits.constructor).toStrictEqual(Uint8Array) }) test('It should create a setup message (GCS)', async () => { const server = psi.server!.createWithNewKey() - const fpr = 0.001 + const fpr = 0.01 const numClientElements = 10 const serverInputs = Array.from({ length: 100 }, (_, i) => `Element ${i}`) @@ -75,14 +41,32 @@ describe('PSI Server', () => { ) const hashRange = setup.getGcs()!.getHashRange() - expect(hashRange).toStrictEqual(1000000) - const bits = setup.getBits() + expect(hashRange).toStrictEqual(100000) + const bits = setup.getGcs()!.getBits() expect(bits.constructor).toStrictEqual(Uint8Array) }) + test('It should create a setup message (Raw)', async () => { + const server = psi.server!.createWithNewKey() + const fpr = 0.01 + const numClientElements = 10 + const serverInputs = Array.from({ length: 100 }, (_, i) => `Element ${i}`) + + const setup = server.createSetupMessage( + fpr, + numClientElements, + serverInputs, + psi.dataStructure.Raw + ) + + const bits = setup.getRaw()!.getEncryptedElementsList() + expect(bits.constructor).toStrictEqual(Array) + expect(bits.length).toStrictEqual(100) + }) + test('It should throw if attempting to create a setup message after deletion', async () => { const server = psi.server!.createWithNewKey() - const fpr = 0.001 + const fpr = 0.01 const numClientElements = 10 const serverInputs = Array.from({ length: 100 }, (_, i) => `Element ${i}`) @@ -100,7 +84,7 @@ describe('PSI Server', () => { test('It should fail to create a setup message', async () => { const server = psi.server!.createWithNewKey() - const fpr = 0.001 + const fpr = 0.01 const numClientElements = Infinity const serverInputs = Array.from({ length: 100 }, (_, i) => `Element ${i}`) @@ -113,130 +97,4 @@ describe('PSI Server', () => { ) ).toThrow() }) - - test('It should create a response to a client request', async () => { - const server = psi.server!.createWithNewKey() - - // prettier-ignore - const request = Request.deserializeBinary(Uint8Array.from([ - 18, 33, 2, 3, 219, 96, 37, 182, 133, 228, 25, 79, - 234, 44, 142, 91, 90, 22, 254, 26, 85, 201, 1, 156, - 53, 47, 231, 118, 42, 240, 188, 89, 160, 180, 240, 18, - 33, 3, 38, 205, 60, 197, 53, 232, 56, 179, 140, 157, - 110, 175, 219, 95, 190, 185, 219, 33, 40, 221, 106, 42, - 159, 57, 21, 166, 225, 111, 183, 142, 25, 217, 18, 33, - 2, 137, 13, 129, 117, 62, 62, 141, 34, 1, 108, 181, - 149, 219, 90, 51, 13, 24, 5, 198, 81, 75, 114, 57, - 50, 14, 83, 176, 247, 251, 230, 174, 151, 18, 33, 3, - 174, 135, 0, 184, 126, 207, 121, 90, 221, 248, 120, 116, - 212, 125, 74, 199, 188, 206, 64, 171, 44, 140, 29, 33, - 204, 37, 51, 60, 187, 171, 190, 140, 18, 33, 3, 107, - 179, 129, 236, 175, 208, 179, 90, 102, 86, 209, 237, 32, - 176, 187, 99, 156, 237, 50, 193, 107, 226, 98, 175, 90, - 1, 179, 52, 192, 248, 92, 244, 18, 33, 3, 96, 57, - 220, 207, 167, 203, 19, 11, 120, 189, 33, 69, 249, 66, - 156, 188, 251, 5, 133, 148, 32, 230, 76, 66, 199, 151, - 178, 152, 50, 176, 121, 253, 18, 33, 2, 108, 40, 24, - 235, 61, 178, 53, 93, 59, 221, 145, 50, 205, 218, 118, - 244, 167, 118, 204, 238, 51, 93, 46, 189, 168, 41, 50, - 144, 106, 226, 185, 77, 18, 33, 2, 137, 185, 176, 205, - 77, 212, 199, 54, 193, 72, 141, 23, 252, 194, 187, 27, - 150, 197, 124, 201, 183, 7, 100, 43, 197, 142, 6, 138, - 96, 73, 11, 38, 18, 33, 2, 101, 115, 165, 127, 201, - 74, 239, 33, 103, 94, 18, 43, 62, 50, 17, 223, 83, - 177, 25, 23, 196, 200, 192, 198, 115, 40, 84, 90, 137, - 228, 118, 16, 18, 33, 2, 82, 37, 166, 155, 4, 244, - 228, 122, 150, 169, 225, 71, 110, 213, 42, 18, 105, 146, - 58, 180, 149, 197, 47, 214, 81, 126, 113, 248, 5, 16, - 19, 194 - ])) - - const response = server.processRequest(request) - expect(response.constructor).toBe(Response) - const numEncryptedElements = response.getEncryptedElementsList() - expect(numEncryptedElements.length).toBe(10) - }) - - test('It should throw if attempting to create a response to a client request after deletion', async () => { - const server = psi.server!.createWithNewKey() - - // prettier-ignore - const request = Request.deserializeBinary(Uint8Array.from([ - 18, 33, 2, 3, 219, 96, 37, 182, 133, 228, 25, 79, - 234, 44, 142, 91, 90, 22, 254, 26, 85, 201, 1, 156, - 53, 47, 231, 118, 42, 240, 188, 89, 160, 180, 240, 18, - 33, 3, 38, 205, 60, 197, 53, 232, 56, 179, 140, 157, - 110, 175, 219, 95, 190, 185, 219, 33, 40, 221, 106, 42, - 159, 57, 21, 166, 225, 111, 183, 142, 25, 217, 18, 33, - 2, 137, 13, 129, 117, 62, 62, 141, 34, 1, 108, 181, - 149, 219, 90, 51, 13, 24, 5, 198, 81, 75, 114, 57, - 50, 14, 83, 176, 247, 251, 230, 174, 151, 18, 33, 3, - 174, 135, 0, 184, 126, 207, 121, 90, 221, 248, 120, 116, - 212, 125, 74, 199, 188, 206, 64, 171, 44, 140, 29, 33, - 204, 37, 51, 60, 187, 171, 190, 140, 18, 33, 3, 107, - 179, 129, 236, 175, 208, 179, 90, 102, 86, 209, 237, 32, - 176, 187, 99, 156, 237, 50, 193, 107, 226, 98, 175, 90, - 1, 179, 52, 192, 248, 92, 244, 18, 33, 3, 96, 57, - 220, 207, 167, 203, 19, 11, 120, 189, 33, 69, 249, 66, - 156, 188, 251, 5, 133, 148, 32, 230, 76, 66, 199, 151, - 178, 152, 50, 176, 121, 253, 18, 33, 2, 108, 40, 24, - 235, 61, 178, 53, 93, 59, 221, 145, 50, 205, 218, 118, - 244, 167, 118, 204, 238, 51, 93, 46, 189, 168, 41, 50, - 144, 106, 226, 185, 77, 18, 33, 2, 137, 185, 176, 205, - 77, 212, 199, 54, 193, 72, 141, 23, 252, 194, 187, 27, - 150, 197, 124, 201, 183, 7, 100, 43, 197, 142, 6, 138, - 96, 73, 11, 38, 18, 33, 2, 101, 115, 165, 127, 201, - 74, 239, 33, 103, 94, 18, 43, 62, 50, 17, 223, 83, - 177, 25, 23, 196, 200, 192, 198, 115, 40, 84, 90, 137, - 228, 118, 16, 18, 33, 2, 82, 37, 166, 155, 4, 244, - 228, 122, 150, 169, 225, 71, 110, 213, 42, 18, 105, 146, - 58, 180, 149, 197, 47, 214, 81, 126, 113, 248, 5, 16, - 19, 194 - ])) - - server.delete() - - expect(server.processRequest.bind(server, request)).toThrow( - ERROR_INSTANCE_DELETED - ) - }) - - test('It should fail to create a response from an invalid client request', async () => { - const server = psi.server!.createWithNewKey() - - // prettier-ignore - const request = Request.deserializeBinary(Uint8Array.from([ - 8, 1, 18, 33, 3, 64, 96, 212, 146, 147, 255, 186, - 229, 165, 6, 66, 251, 234, 144, 164, 222, 156, 79, 150, - 116, 19, 191, 20, 22, 123, 236, 249, 152, 129, 29, 48, - 39, 18, 33, 2, 85, 204, 236, 125, 122, 245, 142, 39, - 102, 112, 47, 176, 44, 106, 183, 57, 183, 166, 174, 193, - 8, 246, 39, 87, 187, 244, 128, 253, 81, 114, 74, 131, - 18, 33, 3, 185, 14, 6, 28, 45, 130, 114, 213, 147, - 164, 227, 41, 250, 236, 65, 228, 228, 141, 26, 187, 176, - 103, 53, 245, 48, 250, 130, 184, 200, 181, 123, 181, 18, - 33, 3, 54, 190, 87, 246, 119, 32, 55, 243, 46, 48, - 84, 222, 164, 210, 17, 225, 185, 138, 154, 41, 224, 123, - 169, 152, 48, 237, 95, 134, 105, 172, 59, 111, 18, 33, - 2, 104, 36, 143, 103, 32, 239, 174, 80, 151, 97, 167, - 46, 156, 224, 196, 189, 119, 48, 44, 36, 69, 56, 26, - 232, 84, 71, 234, 237, 41, 184, 243, 85, 18, 33, 3, - 148, 214, 221, 236, 174, 68, 225, 28, 105, 32, 230, 224, - 111, 35, 25, 201, 189, 119, 26, 105, 31, 196, 140, 139, - 129, 193, 75, 117, 148, 148, 120, 100, 18, 33, 3, 173, - 254, 199, 3, 219, 173, 178, 187, 198, 22, 44, 30, 93, - 43, 160, 189, 134, 151, 197, 62, 165, 0, 197, 95, 5, - 48, 121, 151, 12, 106, 190, 240, 18, 33, 3, 86, 233, - 172, 104, 61, 190, 213, 154, 143, 19, 197, 68, 240, 236, - 77, 227, 217, 164, 86, 109, 233, 78, 0, 57, 119, 109, - 37, 183, 214, 4, 140, 12, 18, 33, 2, 6, 90, 46, - 46, 239, 113, 156, 252, 161, 131, 65, 193, 164, 167, 24, - 68, 42, 244, 53, 64, 181, 255, 165, 195, 110, 195, 115, - 77, 101, 118, 141, 22, 18, 33, 3, 25, 105, 238, 92, - 196, 202, 105, 252, 5, 193, 111, 98, 184, 166, 16, 12, - 129, 97, 240, 52, 11, 151, 40, 168, 218, 226, 13, 188, - 231, 92, 27, 247 - ])) - expect(server.processRequest.bind(server, request)).toThrow() - }) }) diff --git a/private_set_intersection/javascript/src/implementation/dataStructure.ts b/private_set_intersection/javascript/src/implementation/dataStructure.ts index 02fffe9f..776497da 100644 --- a/private_set_intersection/javascript/src/implementation/dataStructure.ts +++ b/private_set_intersection/javascript/src/implementation/dataStructure.ts @@ -1,12 +1,7 @@ import * as psi from 'psi_' import { Loader } from '../main/loader' -export type DataStructure = { - readonly BloomFilter: any - readonly GCS: any -} - -export type DataStructureWrapper = DataStructure +export type DataStructureWrapper = psi.DataStructure type DataStructureWrapperOptions = { readonly loader: Loader @@ -15,7 +10,7 @@ type DataStructureWrapperOptions = { /** * @implements DataStructure */ -const DataStructureConstructor = (library: psi.Library): DataStructure => { +const DataStructureConstructor = (library: psi.Library): psi.DataStructure => { const DataStructure: psi.DataStructure = library.DataStructure /** @@ -23,17 +18,17 @@ const DataStructureConstructor = (library: psi.Library): DataStructure => { */ return { /** - * Get the 'BloomFilter' enum + * Get the 'Raw' enum * * @function - * @name DataStructure.BloomFilter - * @type {DataStructure.BloomFilter} + * @name DataStructure.Raw + * @type {DataStructure.Raw} */ - get BloomFilter(): DataStructure { + get Raw(): psi.DataStructure { /** - * @typedef {DataStructure.BloomFilter} DataStructure.BloomFilter + * @typedef {DataStructure.Raw} DataStructure.Raw */ - return DataStructure.BloomFilter + return DataStructure.Raw }, /** * Get the 'GCS' enum @@ -42,11 +37,24 @@ const DataStructureConstructor = (library: psi.Library): DataStructure => { * @name DataStructure.GCS * @type {DataStructure.GCS} */ - get GCS(): DataStructure { + get GCS(): psi.DataStructure { /** * @typedef {DataStructure.GCS} DataStructure.GCS */ return DataStructure.GCS + }, + /** + * Get the 'BloomFilter' enum + * + * @function + * @name DataStructure.BloomFilter + * @type {DataStructure.BloomFilter} + */ + get BloomFilter(): psi.DataStructure { + /** + * @typedef {DataStructure.BloomFilter} DataStructure.BloomFilter + */ + return DataStructure.BloomFilter } } } diff --git a/private_set_intersection/javascript/src/implementation/server.ts b/private_set_intersection/javascript/src/implementation/server.ts index 38a5c0bb..952292e5 100644 --- a/private_set_intersection/javascript/src/implementation/server.ts +++ b/private_set_intersection/javascript/src/implementation/server.ts @@ -1,7 +1,6 @@ import * as psi from 'psi_' import { Loader } from '../main/loader' import { ERROR_INSTANCE_DELETED } from './constants' -import { DataStructure } from './dataStructure' import { Request, Response, ServerSetup } from './proto/psi_pb' export type Server = { @@ -10,7 +9,7 @@ export type Server = { fpr: number, numClientInputs: number, inputs: readonly string[], - dataStructure?: DataStructure + dataStructure?: psi.DataStructure ) => ServerSetup readonly processRequest: (clientRequest: Request) => Response readonly getPrivateKeyBytes: () => Uint8Array @@ -32,7 +31,7 @@ type ServerWrapperOptions = { * @implements Server */ const ServerConstructor = ( - { DataStructure }: { DataStructure: DataStructure }, + { DataStructure }: { DataStructure: psi.DataStructure }, instance: psi.Server ): Server => { let _instance: psi.Server | null = instance @@ -77,7 +76,7 @@ const ServerConstructor = ( fpr: number, numClientInputs: number, inputs: readonly string[], - dataStructure: DataStructure = DataStructure.GCS + dataStructure: psi.DataStructure = DataStructure.GCS ): ServerSetup { if (!_instance) { throw new Error(ERROR_INSTANCE_DELETED) @@ -140,7 +139,7 @@ const ServerConstructor = ( } export type ServerConstructorDependencies = { - ({ DataStructure }: { DataStructure: DataStructure }): ServerWrapper + ({ DataStructure }: { DataStructure: psi.DataStructure }): ServerWrapper } export const ServerWrapperConstructor = diff --git a/private_set_intersection/preload.bzl b/private_set_intersection/preload.bzl index bcd6475d..cce403a7 100644 --- a/private_set_intersection/preload.bzl +++ b/private_set_intersection/preload.bzl @@ -39,10 +39,10 @@ def psi_preload(): if "io_bazel_rules_go" not in native.existing_rules(): http_archive( name = "io_bazel_rules_go", - sha256 = "56d8c5a5c91e1af73eca71a6fab2ced959b67c86d12ba37feedb0a2dfea441a6", + sha256 = "dd926a88a564a9246713a9c00b35315f54cbd46b31a26d5d8fb264c07045f05d", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.37.0/rules_go-v0.37.0.zip", - "https://github.com/bazelbuild/rules_go/releases/download/v0.37.0/rules_go-v0.37.0.zip", + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.38.1/rules_go-v0.38.1.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.38.1/rules_go-v0.38.1.zip", ], ) diff --git a/private_set_intersection/proto/psi.proto b/private_set_intersection/proto/psi.proto index fcb3f648..00df5849 100644 --- a/private_set_intersection/proto/psi.proto +++ b/private_set_intersection/proto/psi.proto @@ -19,21 +19,27 @@ package psi_proto; // Setup phase message for server. message ServerSetup { + message RawInfo { + repeated bytes encrypted_elements = 1; + } + message GCSInfo { int32 div = 1; int64 hash_range = 2; + bytes bits = 3; } message BloomFilterInfo { int32 num_hash_functions = 1; + bytes bits = 2; } oneof data_structure { - GCSInfo gcs = 1; - BloomFilterInfo bloom_filter = 2; + RawInfo raw = 1; + GCSInfo gcs = 2; + BloomFilterInfo bloom_filter = 3; } - bytes bits = 3; } // Client request with encoded elements sent to the server as an array of diff --git a/private_set_intersection/python/__init__.py b/private_set_intersection/python/__init__.py index 97641637..c669614f 100644 --- a/private_set_intersection/python/__init__.py +++ b/private_set_intersection/python/__init__.py @@ -15,6 +15,7 @@ class DataStructure(Enum): + RAW = psi.data_structure.Raw GCS = psi.data_structure.GCS BLOOM_FILTER = psi.data_structure.BloomFilter diff --git a/private_set_intersection/python/psi_bindings.cpp b/private_set_intersection/python/psi_bindings.cpp index e11f5c27..3e9c5d02 100644 --- a/private_set_intersection/python/psi_bindings.cpp +++ b/private_set_intersection/python/psi_bindings.cpp @@ -41,7 +41,8 @@ void bind(pybind11::module& m) { m.attr("__version__") = ::private_set_intersection::Package::kVersion; py::enum_(m, "data_structure", py::arithmetic()) - .value("GCS", psi::DataStructure::GCS) + .value("Raw", psi::DataStructure::Raw) + .value("GCS", psi::DataStructure::Gcs) .value("BloomFilter", psi::DataStructure::BloomFilter); py::class_(m, "cpp_proto_server_setup") diff --git a/private_set_intersection/python/tests.py b/private_set_intersection/python/tests.py index 1711b0ac..95d55422 100644 --- a/private_set_intersection/python/tests.py +++ b/private_set_intersection/python/tests.py @@ -4,40 +4,49 @@ import private_set_intersection.python as psi +client_key = bytes(range(32)) +server_key = bytes(range(1, 33)) +fpr = 0.01 +num_client_inputs = 10 +num_server_inputs = 100 +client_items = ["Element " + str(i) for i in range(num_client_inputs)] +server_items = ["Element " + str(2 * i) for i in range(num_server_inputs)] -def dup(do, msg, dst): - if not do: - return msg - buff = msg.SerializeToString() - dst.ParseFromString(buff) - return dst +def test_version(): + version = psi.__version__ + assert re.match(r"[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9]+)?", version) -@pytest.mark.parametrize("reveal_intersection", [False, True]) -def test_sanity(reveal_intersection): - c = psi.client.CreateWithNewKey(reveal_intersection) - assert c != None + +def test_static_key(): + c = psi.client.CreateFromKey(client_key, False) + assert c.GetPrivateKeyBytes() == client_key + + s = psi.server.CreateFromKey(server_key, False) + assert s.GetPrivateKeyBytes() == server_key -@pytest.mark.parametrize("ds", [psi.DataStructure.GCS, psi.DataStructure.BLOOM_FILTER]) @pytest.mark.parametrize("reveal_intersection", [False, True]) -@pytest.mark.parametrize("duplicate", [False, True]) -def test_client_server(ds, reveal_intersection, duplicate): +@pytest.mark.parametrize( + "ds", [psi.DataStructure.RAW, psi.DataStructure.GCS, psi.DataStructure.BLOOM_FILTER] +) +def test_integration(ds, reveal_intersection): c = psi.client.CreateWithNewKey(reveal_intersection) s = psi.server.CreateWithNewKey(reveal_intersection) - client_items = ["Element " + str(i) for i in range(100)] - server_items = ["Element " + str(2 * i) for i in range(1000)] - - fpr = 1.0e-9 - setup = dup( - duplicate, s.CreateSetupMessage(fpr, len(client_items), server_items, ds), psi.ServerSetup() + setup = psi.ServerSetup() + setup.ParseFromString( + s.CreateSetupMessage(fpr, len(client_items), server_items, ds).SerializeToString() ) - request = dup(duplicate, c.CreateRequest(client_items), psi.Request()) - resp = dup(duplicate, s.ProcessRequest(request), psi.Response()) + + request = psi.Request() + request.ParseFromString(c.CreateRequest(client_items).SerializeToString()) + + response = psi.Response() + response.ParseFromString(s.ProcessRequest(request).SerializeToString()) if reveal_intersection: - intersection = c.GetIntersection(setup, resp) + intersection = c.GetIntersection(setup, response) iset = set(intersection) for idx in range(len(client_items)): if idx % 2 == 0: @@ -45,148 +54,10 @@ def test_client_server(ds, reveal_intersection, duplicate): else: assert idx not in iset else: - intersection = c.GetIntersectionSize(setup, resp) + intersection = c.GetIntersectionSize(setup, response) assert intersection >= (len(client_items) / 2.0) assert intersection <= (1.1 * len(client_items) / 2.0) -@pytest.mark.parametrize("ds", [psi.DataStructure.GCS, psi.DataStructure.BLOOM_FILTER]) -@pytest.mark.parametrize("reveal_intersection", [False, True]) -@pytest.mark.parametrize("duplicate", [False, True]) -def test_large_client_small_server(ds, reveal_intersection, duplicate): - c = psi.client.CreateWithNewKey(reveal_intersection) - s = psi.server.CreateWithNewKey(reveal_intersection) - - client_items = ["Element " + str(i) for i in range(1000)] - server_items = ["Element " + str(2 * i) for i in range(10)] - - fpr = 1.0e-9 - setup = dup( - duplicate, s.CreateSetupMessage(fpr, len(client_items), server_items, ds), psi.ServerSetup() - ) - request = dup(duplicate, c.CreateRequest(client_items), psi.Request()) - resp = dup(duplicate, s.ProcessRequest(request), psi.Response()) - - if reveal_intersection: - intersection = c.GetIntersection(setup, resp) - assert len(intersection) <= len(server_items) - # We should have an entry for every item in the server's set offset by - # two due to the input string names - for idx in intersection: - assert client_items[idx] == server_items[int(idx / 2)] - - else: - intersection = c.GetIntersectionSize(setup, resp) - assert intersection <= len(server_items) - - -def test_version(): - version = psi.__version__ - assert re.match(r"[0-9]+[.][0-9]+[.][0-9]+(-[A-Za-z0-9]+)?", version) - - -@pytest.mark.parametrize("reveal_intersection", [False, True]) -def test_server_sanity(reveal_intersection): - s = psi.server.CreateWithNewKey(reveal_intersection) - assert s != None - - key = s.GetPrivateKeyBytes() - assert key != None - - other = psi.server.CreateFromKey(key, reveal_intersection) - newkey = other.GetPrivateKeyBytes() - - assert key == newkey - - -@pytest.mark.parametrize("reveal_intersection", [False, True]) -def test_client_sanity(reveal_intersection): - c = psi.client.CreateWithNewKey(reveal_intersection) - assert c != None - - key = c.GetPrivateKeyBytes() - assert key != None - - other = psi.client.CreateFromKey(key, reveal_intersection) - newkey = other.GetPrivateKeyBytes() - - assert key == newkey - - -@pytest.mark.parametrize("ds", [psi.DataStructure.GCS, psi.DataStructure.BLOOM_FILTER]) -@pytest.mark.parametrize("reveal_intersection", [False, True]) -def test_serialization_setup_msg(ds, reveal_intersection): - s = psi.server.CreateWithNewKey(reveal_intersection) - - server_items = ["Element " + str(2 * i) for i in range(10000)] - - fpr = 1.0e-9 - setup = s.CreateSetupMessage(fpr, 1000, server_items, ds) - - buff = setup.SerializeToString() - recreated = psi.ServerSetup() - recreated.ParseFromString(buff) - assert isinstance(buff, bytes) - assert setup.bits == recreated.bits - - -@pytest.mark.parametrize("reveal_intersection", [False, True]) -def test_serialization_request(reveal_intersection): - c = psi.client.CreateWithNewKey(reveal_intersection) - client_items = ["Element " + str(i) for i in range(1000)] - request = c.CreateRequest(client_items) - - buff = request.SerializeToString() - recreated = psi.Request() - recreated.ParseFromString(buff) - assert isinstance(buff, bytes) - assert request.encrypted_elements == recreated.encrypted_elements - assert request.reveal_intersection == recreated.reveal_intersection - - -@pytest.mark.parametrize("ds", [psi.DataStructure.GCS, psi.DataStructure.BLOOM_FILTER]) -@pytest.mark.parametrize("reveal_intersection", [False, True]) -def test_serialization_response(ds, reveal_intersection): - c = psi.client.CreateWithNewKey(reveal_intersection) - s = psi.server.CreateWithNewKey(reveal_intersection) - - client_items = ["Element " + str(i) for i in range(100)] - server_items = ["Element " + str(2 * i) for i in range(1000)] - - fpr = 1.0e-9 - setup = s.CreateSetupMessage(fpr, len(client_items), server_items, ds) - req = c.CreateRequest(client_items) - resp = s.ProcessRequest(req) - - buff = resp.SerializeToString() - recreated = psi.Response() - recreated.ParseFromString(buff) - - assert isinstance(buff, bytes) - assert resp.encrypted_elements == recreated.encrypted_elements - - -@pytest.mark.parametrize("ds", [psi.DataStructure.GCS, psi.DataStructure.BLOOM_FILTER]) -@pytest.mark.parametrize("reveal_intersection", [False, True]) -def test_empty_intersection(ds, reveal_intersection): - c = psi.client.CreateWithNewKey(reveal_intersection) - s = psi.server.CreateWithNewKey(reveal_intersection) - - client_items = ["Element " + str(i) for i in range(100)] - server_items = ["Other " + str(2 * i) for i in range(1000)] - - fpr = 1.0e-9 - setup = s.CreateSetupMessage(fpr, len(client_items), server_items, ds) - request = c.CreateRequest(client_items) - resp = s.ProcessRequest(request) - - if reveal_intersection: - intersection = c.GetIntersection(setup, resp) - assert len(intersection) == 0 - else: - intersection = c.GetIntersectionSize(setup, resp) - assert intersection == 0 - - if __name__ == "__main__": sys.exit(pytest.main(["-s", "-v", "-x", __file__])) diff --git a/private_set_intersection/rust/BUILD b/private_set_intersection/rust/BUILD index a560687d..186c09ee 100644 --- a/private_set_intersection/rust/BUILD +++ b/private_set_intersection/rust/BUILD @@ -1,12 +1,13 @@ -package(default_visibility = ["//visibility:public"]) - load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc", "rust_library", "rust_test") load("@rules_rust//proto:toolchain.bzl", "PROTO_COMPILE_DEPS") +package(default_visibility = ["//visibility:public"]) + rust_library( - name = "rust_psi", + name = "psi", srcs = [ "src/client.rs", + "src/datastructure.rs", "src/lib.rs", "src/server.rs", ], @@ -20,31 +21,31 @@ rust_library( ) rust_test( - name = "rust_psi_unit_test", - crate = ":rust_psi", + name = "version", + crate = ":psi", deps = [ "//third_party/cargo/cargo:semver", ], ) rust_test( - name = "rust_psi_test", - srcs = ["tests/client_server_test.rs"], + name = "integration", + srcs = ["tests/integration_test.rs"], deps = [ - ":rust_psi", + ":psi", ], ) rust_binary( - name = "rust_psi_bench", - srcs = ["benches/psi_bench.rs"], + name = "bench", + srcs = ["benches/bench.rs"], deps = [ - ":rust_psi", + ":psi", "//third_party/cargo/cargo:bencher", ], ) rust_doc( - name = "rust_psi_doc", - crate = ":rust_psi", + name = "doc", + crate = ":psi", ) diff --git a/private_set_intersection/rust/README.md b/private_set_intersection/rust/README.md index f4e4de94..d86dfb0f 100644 --- a/private_set_intersection/rust/README.md +++ b/private_set_intersection/rust/README.md @@ -33,12 +33,12 @@ bazel test -c opt //private_set_intersection/rust/... Run the benchmark: ``` -bazel run -c opt //private_set_intersection/rust:rust_psi_bench +bazel run -c opt //private_set_intersection/rust:bench ``` ## Use in other projects -Add `deps = ["@org_openmined_psi//private_set_intersection/rust:rust_psi"]` to your Bazel rule +Add `deps = ["@org_openmined_psi//private_set_intersection/rust:psi"]` to your Bazel rule in your project's `BUILD` file. ## Developing diff --git a/private_set_intersection/rust/benches/bench.rs b/private_set_intersection/rust/benches/bench.rs new file mode 100644 index 00000000..89f8ec81 --- /dev/null +++ b/private_set_intersection/rust/benches/bench.rs @@ -0,0 +1,343 @@ +#[macro_use] +extern crate bencher; +use bencher::{black_box, Bencher}; +use psi::*; + +fn bench_client_create_request(reveal: bool, n: usize, b: &mut Bencher) { + let mut elements = vec![]; + + for i in 0..n { + elements.push(format!("Elements {}", i)); + } + + elements = black_box(elements); + + let client = client::PsiClient::create_with_new_key(reveal).unwrap(); + + b.iter(|| client.create_request(&elements).unwrap()); +} + +fn bench_client_create_request_no_reveal_1(b: &mut Bencher) { + bench_client_create_request(false, 1, b); +} + +fn bench_client_create_request_no_reveal_10(b: &mut Bencher) { + bench_client_create_request(false, 10, b); +} + +fn bench_client_create_request_no_reveal_100(b: &mut Bencher) { + bench_client_create_request(false, 100, b); +} + +fn bench_client_create_request_no_reveal_1000(b: &mut Bencher) { + bench_client_create_request(false, 1000, b); +} + +fn bench_client_create_request_no_reveal_10000(b: &mut Bencher) { + bench_client_create_request(false, 10000, b); +} + +fn bench_client_create_request_reveal_1(b: &mut Bencher) { + bench_client_create_request(true, 1, b); +} + +fn bench_client_create_request_reveal_10(b: &mut Bencher) { + bench_client_create_request(true, 10, b); +} + +fn bench_client_create_request_reveal_100(b: &mut Bencher) { + bench_client_create_request(true, 100, b); +} + +fn bench_client_create_request_reveal_1000(b: &mut Bencher) { + bench_client_create_request(true, 1000, b); +} + +fn bench_client_create_request_reveal_10000(b: &mut Bencher) { + bench_client_create_request(true, 10000, b); +} + +fn bench_client_process_response(reveal: bool, n: usize, b: &mut Bencher) { + let mut elements = vec![]; + + for i in 0..n { + elements.push(format!("Elements {}", i)); + } + + elements = black_box(elements); + + let client = client::PsiClient::create_with_new_key(reveal).unwrap(); + let server = server::PsiServer::create_with_new_key(reveal).unwrap(); + + let fpr = 1e-9f64; + + let setup = server + .create_setup_message(fpr, n, &elements, None) + .unwrap(); + let request = client.create_request(&elements).unwrap(); + let response = server.process_request(&request).unwrap(); + + b.iter(|| { + if reveal { + let intersection = client.get_intersection(&setup, &response).unwrap(); + black_box(intersection); + } else { + let intersection_size = client.get_intersection_size(&setup, &response).unwrap(); + black_box(intersection_size); + } + }); +} + +fn bench_client_process_response_no_reveal_1(b: &mut Bencher) { + bench_client_process_response(false, 1, b); +} + +fn bench_client_process_response_no_reveal_10(b: &mut Bencher) { + bench_client_process_response(false, 10, b); +} + +fn bench_client_process_response_no_reveal_100(b: &mut Bencher) { + bench_client_process_response(false, 100, b); +} + +fn bench_client_process_response_no_reveal_1000(b: &mut Bencher) { + bench_client_process_response(false, 1000, b); +} + +fn bench_client_process_response_no_reveal_10000(b: &mut Bencher) { + bench_client_process_response(false, 10000, b); +} + +fn bench_client_process_response_reveal_1(b: &mut Bencher) { + bench_client_process_response(true, 1, b); +} + +fn bench_client_process_response_reveal_10(b: &mut Bencher) { + bench_client_process_response(true, 10, b); +} + +fn bench_client_process_response_reveal_100(b: &mut Bencher) { + bench_client_process_response(true, 100, b); +} + +fn bench_client_process_response_reveal_1000(b: &mut Bencher) { + bench_client_process_response(true, 1000, b); +} + +fn bench_client_process_response_reveal_10000(b: &mut Bencher) { + bench_client_process_response(true, 10000, b); +} + +fn bench_server_setup(reveal: bool, n: usize, fpr: f64, b: &mut Bencher) { + let mut elements = vec![]; + + for i in 0..n { + elements.push(format!("Elements {}", i)); + } + + elements = black_box(elements); + + let server = server::PsiServer::create_with_new_key(reveal).unwrap(); + + b.iter(|| { + server + .create_setup_message(fpr, 10000, &elements, None) + .unwrap() + }); +} + +const FPR3: f64 = 1e-3f64; +const FPR6: f64 = 1e-6f64; + +fn bench_server_setup_no_reveal_1_fpr3(b: &mut Bencher) { + bench_server_setup(false, 1, FPR3, b); +} + +fn bench_server_setup_no_reveal_10_fpr3(b: &mut Bencher) { + bench_server_setup(false, 10, FPR3, b); +} + +fn bench_server_setup_no_reveal_100_fpr3(b: &mut Bencher) { + bench_server_setup(false, 100, FPR3, b); +} + +fn bench_server_setup_no_reveal_1000_fpr3(b: &mut Bencher) { + bench_server_setup(false, 1000, FPR3, b); +} + +fn bench_server_setup_no_reveal_10000_fpr3(b: &mut Bencher) { + bench_server_setup(false, 10000, FPR3, b); +} + +fn bench_server_setup_reveal_1_fpr3(b: &mut Bencher) { + bench_server_setup(true, 1, FPR3, b); +} + +fn bench_server_setup_reveal_10_fpr3(b: &mut Bencher) { + bench_server_setup(true, 10, FPR3, b); +} + +fn bench_server_setup_reveal_100_fpr3(b: &mut Bencher) { + bench_server_setup(true, 100, FPR3, b); +} + +fn bench_server_setup_reveal_1000_fpr3(b: &mut Bencher) { + bench_server_setup(true, 1000, FPR3, b); +} + +fn bench_server_setup_reveal_10000_fpr3(b: &mut Bencher) { + bench_server_setup(true, 10000, FPR3, b); +} + +fn bench_server_setup_no_reveal_1_fpr6(b: &mut Bencher) { + bench_server_setup(false, 1, FPR6, b); +} + +fn bench_server_setup_no_reveal_10_fpr6(b: &mut Bencher) { + bench_server_setup(false, 10, FPR6, b); +} + +fn bench_server_setup_no_reveal_100_fpr6(b: &mut Bencher) { + bench_server_setup(false, 100, FPR6, b); +} + +fn bench_server_setup_no_reveal_1000_fpr6(b: &mut Bencher) { + bench_server_setup(false, 1000, FPR6, b); +} + +fn bench_server_setup_no_reveal_10000_fpr6(b: &mut Bencher) { + bench_server_setup(false, 10000, FPR6, b); +} + +fn bench_server_setup_reveal_1_fpr6(b: &mut Bencher) { + bench_server_setup(true, 1, FPR6, b); +} + +fn bench_server_setup_reveal_10_fpr6(b: &mut Bencher) { + bench_server_setup(true, 10, FPR6, b); +} + +fn bench_server_setup_reveal_100_fpr6(b: &mut Bencher) { + bench_server_setup(true, 100, FPR6, b); +} + +fn bench_server_setup_reveal_1000_fpr6(b: &mut Bencher) { + bench_server_setup(true, 1000, FPR6, b); +} + +fn bench_server_setup_reveal_10000_fpr6(b: &mut Bencher) { + bench_server_setup(true, 10000, FPR6, b); +} + +fn bench_server_process_request(reveal: bool, n: usize, b: &mut Bencher) { + let mut elements = vec![]; + + for i in 0..n { + elements.push(format!("Elements {}", i)); + } + + elements = black_box(elements); + + let client = client::PsiClient::create_with_new_key(reveal).unwrap(); + let server = server::PsiServer::create_with_new_key(reveal).unwrap(); + + let request = client.create_request(&elements).unwrap(); + + b.iter(|| server.process_request(&request).unwrap()); +} + +fn bench_server_process_request_no_reveal_1(b: &mut Bencher) { + bench_server_process_request(false, 1, b); +} + +fn bench_server_process_request_no_reveal_10(b: &mut Bencher) { + bench_server_process_request(false, 10, b); +} + +fn bench_server_process_request_no_reveal_100(b: &mut Bencher) { + bench_server_process_request(false, 100, b); +} + +fn bench_server_process_request_no_reveal_1000(b: &mut Bencher) { + bench_server_process_request(false, 1000, b); +} + +fn bench_server_process_request_no_reveal_10000(b: &mut Bencher) { + bench_server_process_request(false, 10000, b); +} + +fn bench_server_process_request_reveal_1(b: &mut Bencher) { + bench_server_process_request(true, 1, b); +} + +fn bench_server_process_request_reveal_10(b: &mut Bencher) { + bench_server_process_request(true, 10, b); +} + +fn bench_server_process_request_reveal_100(b: &mut Bencher) { + bench_server_process_request(true, 100, b); +} + +fn bench_server_process_request_reveal_1000(b: &mut Bencher) { + bench_server_process_request(true, 1000, b); +} + +fn bench_server_process_request_reveal_10000(b: &mut Bencher) { + bench_server_process_request(true, 10000, b); +} + +benchmark_group!( + benches, + bench_client_create_request_no_reveal_1, + bench_client_create_request_no_reveal_10, + bench_client_create_request_no_reveal_100, + bench_client_create_request_no_reveal_1000, + bench_client_create_request_no_reveal_10000, + bench_client_create_request_reveal_1, + bench_client_create_request_reveal_10, + bench_client_create_request_reveal_100, + bench_client_create_request_reveal_1000, + bench_client_create_request_reveal_10000, + bench_client_process_response_no_reveal_1, + bench_client_process_response_no_reveal_10, + bench_client_process_response_no_reveal_100, + bench_client_process_response_no_reveal_1000, + bench_client_process_response_no_reveal_10000, + bench_client_process_response_reveal_1, + bench_client_process_response_reveal_10, + bench_client_process_response_reveal_100, + bench_client_process_response_reveal_1000, + bench_client_process_response_reveal_10000, + bench_server_setup_no_reveal_1_fpr3, + bench_server_setup_no_reveal_10_fpr3, + bench_server_setup_no_reveal_100_fpr3, + bench_server_setup_no_reveal_1000_fpr3, + bench_server_setup_no_reveal_10000_fpr3, + bench_server_setup_reveal_1_fpr3, + bench_server_setup_reveal_10_fpr3, + bench_server_setup_reveal_100_fpr3, + bench_server_setup_reveal_1000_fpr3, + bench_server_setup_reveal_10000_fpr3, + bench_server_setup_no_reveal_1_fpr6, + bench_server_setup_no_reveal_10_fpr6, + bench_server_setup_no_reveal_100_fpr6, + bench_server_setup_no_reveal_1000_fpr6, + bench_server_setup_no_reveal_10000_fpr6, + bench_server_setup_reveal_1_fpr6, + bench_server_setup_reveal_10_fpr6, + bench_server_setup_reveal_100_fpr6, + bench_server_setup_reveal_1000_fpr6, + bench_server_setup_reveal_10000_fpr6, + bench_server_process_request_no_reveal_1, + bench_server_process_request_no_reveal_10, + bench_server_process_request_no_reveal_100, + bench_server_process_request_no_reveal_1000, + bench_server_process_request_no_reveal_10000, + bench_server_process_request_reveal_1, + bench_server_process_request_reveal_10, + bench_server_process_request_reveal_100, + bench_server_process_request_reveal_1000, + bench_server_process_request_reveal_10000 +); + +benchmark_main!(benches); diff --git a/private_set_intersection/rust/benches/psi_bench.rs b/private_set_intersection/rust/benches/psi_bench.rs deleted file mode 100644 index d3079a51..00000000 --- a/private_set_intersection/rust/benches/psi_bench.rs +++ /dev/null @@ -1,246 +0,0 @@ -#[macro_use] -extern crate bencher; -extern crate rust_psi; - -use bencher::{Bencher, black_box}; - -use rust_psi::*; - -fn bench_client_create_request(reveal: bool, n: usize, b: &mut Bencher) { - let mut elements = vec![]; - - for i in 0..n { - elements.push(format!("Elements {}", i)); - } - - elements = black_box(elements); - - let client = client::PsiClient::create_with_new_key(reveal).unwrap(); - - b.iter(|| { - client.create_request(&elements).unwrap() - }); -} - -fn bench_client_create_request_no_reveal_1(b: &mut Bencher) { bench_client_create_request(false, 1, b); } - -fn bench_client_create_request_no_reveal_10(b: &mut Bencher) { bench_client_create_request(false, 10, b); } - -fn bench_client_create_request_no_reveal_100(b: &mut Bencher) { bench_client_create_request(false, 100, b); } - -fn bench_client_create_request_no_reveal_1000(b: &mut Bencher) { bench_client_create_request(false, 1000, b); } - -fn bench_client_create_request_no_reveal_10000(b: &mut Bencher) { bench_client_create_request(false, 10000, b); } - -fn bench_client_create_request_reveal_1(b: &mut Bencher) { bench_client_create_request(true, 1, b); } - -fn bench_client_create_request_reveal_10(b: &mut Bencher) { bench_client_create_request(true, 10, b); } - -fn bench_client_create_request_reveal_100(b: &mut Bencher) { bench_client_create_request(true, 100, b); } - -fn bench_client_create_request_reveal_1000(b: &mut Bencher) { bench_client_create_request(true, 1000, b); } - -fn bench_client_create_request_reveal_10000(b: &mut Bencher) { bench_client_create_request(true, 10000, b); } - -fn bench_client_process_response(reveal: bool, n: usize, b: &mut Bencher) { - let mut elements = vec![]; - - for i in 0..n { - elements.push(format!("Elements {}", i)); - } - - elements = black_box(elements); - - let client = client::PsiClient::create_with_new_key(reveal).unwrap(); - let server = server::PsiServer::create_with_new_key(reveal).unwrap(); - - let fpr = 1e-9f64; - - let setup = server.create_setup_message(fpr, n, &elements).unwrap(); - let request = client.create_request(&elements).unwrap(); - let response = server.process_request(&request).unwrap(); - - b.iter(|| { - if reveal { - let intersection = client.get_intersection(&setup, &response).unwrap(); - black_box(intersection); - } else { - let intersection_size = client.get_intersection_size(&setup, &response).unwrap(); - black_box(intersection_size); - } - }); -} - -fn bench_client_process_response_no_reveal_1(b: &mut Bencher) { bench_client_process_response(false, 1, b); } - -fn bench_client_process_response_no_reveal_10(b: &mut Bencher) { bench_client_process_response(false, 10, b); } - -fn bench_client_process_response_no_reveal_100(b: &mut Bencher) { bench_client_process_response(false, 100, b); } - -fn bench_client_process_response_no_reveal_1000(b: &mut Bencher) { bench_client_process_response(false, 1000, b); } - -fn bench_client_process_response_no_reveal_10000(b: &mut Bencher) { bench_client_process_response(false, 10000, b); } - -fn bench_client_process_response_reveal_1(b: &mut Bencher) { bench_client_process_response(true, 1, b); } - -fn bench_client_process_response_reveal_10(b: &mut Bencher) { bench_client_process_response(true, 10, b); } - -fn bench_client_process_response_reveal_100(b: &mut Bencher) { bench_client_process_response(true, 100, b); } - -fn bench_client_process_response_reveal_1000(b: &mut Bencher) { bench_client_process_response(true, 1000, b); } - -fn bench_client_process_response_reveal_10000(b: &mut Bencher) { bench_client_process_response(true, 10000, b); } - -fn bench_server_setup(reveal: bool, n: usize, fpr: f64, b: &mut Bencher) { - let mut elements = vec![]; - - for i in 0..n { - elements.push(format!("Elements {}", i)); - } - - elements = black_box(elements); - - let server = server::PsiServer::create_with_new_key(reveal).unwrap(); - - b.iter(|| { - server.create_setup_message(fpr, 10000, &elements).unwrap() - }); -} - -const FPR3: f64 = 1e-3f64; -const FPR6: f64 = 1e-6f64; - -fn bench_server_setup_no_reveal_1_fpr3(b: &mut Bencher) { bench_server_setup(false, 1, FPR3, b); } - -fn bench_server_setup_no_reveal_10_fpr3(b: &mut Bencher) { bench_server_setup(false, 10, FPR3, b); } - -fn bench_server_setup_no_reveal_100_fpr3(b: &mut Bencher) { bench_server_setup(false, 100, FPR3, b); } - -fn bench_server_setup_no_reveal_1000_fpr3(b: &mut Bencher) { bench_server_setup(false, 1000, FPR3, b); } - -fn bench_server_setup_no_reveal_10000_fpr3(b: &mut Bencher) { bench_server_setup(false, 10000, FPR3, b); } - -fn bench_server_setup_reveal_1_fpr3(b: &mut Bencher) { bench_server_setup(true, 1, FPR3, b); } - -fn bench_server_setup_reveal_10_fpr3(b: &mut Bencher) { bench_server_setup(true, 10, FPR3, b); } - -fn bench_server_setup_reveal_100_fpr3(b: &mut Bencher) { bench_server_setup(true, 100, FPR3, b); } - -fn bench_server_setup_reveal_1000_fpr3(b: &mut Bencher) { bench_server_setup(true, 1000, FPR3, b); } - -fn bench_server_setup_reveal_10000_fpr3(b: &mut Bencher) { bench_server_setup(true, 10000, FPR3, b); } - -fn bench_server_setup_no_reveal_1_fpr6(b: &mut Bencher) { bench_server_setup(false, 1, FPR6, b); } - -fn bench_server_setup_no_reveal_10_fpr6(b: &mut Bencher) { bench_server_setup(false, 10, FPR6, b); } - -fn bench_server_setup_no_reveal_100_fpr6(b: &mut Bencher) { bench_server_setup(false, 100, FPR6, b); } - -fn bench_server_setup_no_reveal_1000_fpr6(b: &mut Bencher) { bench_server_setup(false, 1000, FPR6, b); } - -fn bench_server_setup_no_reveal_10000_fpr6(b: &mut Bencher) { bench_server_setup(false, 10000, FPR6, b); } - -fn bench_server_setup_reveal_1_fpr6(b: &mut Bencher) { bench_server_setup(true, 1, FPR6, b); } - -fn bench_server_setup_reveal_10_fpr6(b: &mut Bencher) { bench_server_setup(true, 10, FPR6, b); } - -fn bench_server_setup_reveal_100_fpr6(b: &mut Bencher) { bench_server_setup(true, 100, FPR6, b); } - -fn bench_server_setup_reveal_1000_fpr6(b: &mut Bencher) { bench_server_setup(true, 1000, FPR6, b); } - -fn bench_server_setup_reveal_10000_fpr6(b: &mut Bencher) { bench_server_setup(true, 10000, FPR6, b); } - -fn bench_server_process_request(reveal: bool, n: usize, b: &mut Bencher) { - let mut elements = vec![]; - - for i in 0..n { - elements.push(format!("Elements {}", i)); - } - - elements = black_box(elements); - - let client = client::PsiClient::create_with_new_key(reveal).unwrap(); - let server = server::PsiServer::create_with_new_key(reveal).unwrap(); - - let request = client.create_request(&elements).unwrap(); - - b.iter(|| { - server.process_request(&request).unwrap() - }); -} - -fn bench_server_process_request_no_reveal_1(b: &mut Bencher) { bench_server_process_request(false, 1, b); } - -fn bench_server_process_request_no_reveal_10(b: &mut Bencher) { bench_server_process_request(false, 10, b); } - -fn bench_server_process_request_no_reveal_100(b: &mut Bencher) { bench_server_process_request(false, 100, b); } - -fn bench_server_process_request_no_reveal_1000(b: &mut Bencher) { bench_server_process_request(false, 1000, b); } - -fn bench_server_process_request_no_reveal_10000(b: &mut Bencher) { bench_server_process_request(false, 10000, b); } - -fn bench_server_process_request_reveal_1(b: &mut Bencher) { bench_server_process_request(true, 1, b); } - -fn bench_server_process_request_reveal_10(b: &mut Bencher) { bench_server_process_request(true, 10, b); } - -fn bench_server_process_request_reveal_100(b: &mut Bencher) { bench_server_process_request(true, 100, b); } - -fn bench_server_process_request_reveal_1000(b: &mut Bencher) { bench_server_process_request(true, 1000, b); } - -fn bench_server_process_request_reveal_10000(b: &mut Bencher) { bench_server_process_request(true, 10000, b); } - -benchmark_group!( - benches, - bench_client_create_request_no_reveal_1, - bench_client_create_request_no_reveal_10, - bench_client_create_request_no_reveal_100, - bench_client_create_request_no_reveal_1000, - bench_client_create_request_no_reveal_10000, - bench_client_create_request_reveal_1, - bench_client_create_request_reveal_10, - bench_client_create_request_reveal_100, - bench_client_create_request_reveal_1000, - bench_client_create_request_reveal_10000, - bench_client_process_response_no_reveal_1, - bench_client_process_response_no_reveal_10, - bench_client_process_response_no_reveal_100, - bench_client_process_response_no_reveal_1000, - bench_client_process_response_no_reveal_10000, - bench_client_process_response_reveal_1, - bench_client_process_response_reveal_10, - bench_client_process_response_reveal_100, - bench_client_process_response_reveal_1000, - bench_client_process_response_reveal_10000, - bench_server_setup_no_reveal_1_fpr3, - bench_server_setup_no_reveal_10_fpr3, - bench_server_setup_no_reveal_100_fpr3, - bench_server_setup_no_reveal_1000_fpr3, - bench_server_setup_no_reveal_10000_fpr3, - bench_server_setup_reveal_1_fpr3, - bench_server_setup_reveal_10_fpr3, - bench_server_setup_reveal_100_fpr3, - bench_server_setup_reveal_1000_fpr3, - bench_server_setup_reveal_10000_fpr3, - bench_server_setup_no_reveal_1_fpr6, - bench_server_setup_no_reveal_10_fpr6, - bench_server_setup_no_reveal_100_fpr6, - bench_server_setup_no_reveal_1000_fpr6, - bench_server_setup_no_reveal_10000_fpr6, - bench_server_setup_reveal_1_fpr6, - bench_server_setup_reveal_10_fpr6, - bench_server_setup_reveal_100_fpr6, - bench_server_setup_reveal_1000_fpr6, - bench_server_setup_reveal_10000_fpr6, - bench_server_process_request_no_reveal_1, - bench_server_process_request_no_reveal_10, - bench_server_process_request_no_reveal_100, - bench_server_process_request_no_reveal_1000, - bench_server_process_request_no_reveal_10000, - bench_server_process_request_reveal_1, - bench_server_process_request_reveal_10, - bench_server_process_request_reveal_100, - bench_server_process_request_reveal_1000, - bench_server_process_request_reveal_10000 -); - -benchmark_main!(benches); diff --git a/private_set_intersection/rust/src/client.rs b/private_set_intersection/rust/src/client.rs index 8dc6dcbe..8cdd7f48 100644 --- a/private_set_intersection/rust/src/client.rs +++ b/private_set_intersection/rust/src/client.rs @@ -2,53 +2,96 @@ //! protocol. use libc::*; - -use std::{fmt, error, ptr, slice}; -use std::ffi::CStr; - use protobuf::{self, Message}; - use psi_rust_proto::*; +use std::ffi::CStr; +use std::{error, fmt, ptr, slice}; type PsiClientContext = *mut c_void; /// A handle for the C context of a PSI client. pub struct PsiClient { ctx: PsiClientContext, - reveal_intersection: bool + reveal_intersection: bool, } #[repr(C)] struct PsiClientBuffer { ptr: *const c_char, - len: size_t + len: size_t, } -extern { - fn psi_client_create_with_new_key(reveal_intersection: bool, ctx: *mut PsiClientContext, error_out: *mut *mut c_char) -> c_int; - fn psi_client_create_from_key(key_bytes: PsiClientBuffer, reveal_intersection: bool, ctx: *mut PsiClientContext, error_out: *mut *mut c_char) -> c_int; +extern "C" { + fn psi_client_create_with_new_key( + reveal_intersection: bool, + ctx: *mut PsiClientContext, + error_out: *mut *mut c_char, + ) -> c_int; + fn psi_client_create_from_key( + key_bytes: PsiClientBuffer, + reveal_intersection: bool, + ctx: *mut PsiClientContext, + error_out: *mut *mut c_char, + ) -> c_int; fn psi_client_delete(ctx: *mut PsiClientContext); - fn psi_client_create_request(ctx: PsiClientContext, inputs: *const PsiClientBuffer, input_len: size_t, output: *mut *mut c_char, output_len: *mut size_t, error_out: *mut *mut c_char) -> c_int; - fn psi_client_get_intersection_size(ctx: PsiClientContext, server_setup: PsiClientBuffer, server_response: PsiClientBuffer, output: *mut i64, error_out: *mut *mut c_char) -> c_int; - fn psi_client_get_intersection(ctx: PsiClientContext, server_setup: PsiClientBuffer, server_response: PsiClientBuffer, output: *mut *mut i64, output_len: *mut size_t, error_out: *mut *mut c_char) -> c_int; - fn psi_client_get_private_key_bytes(ctx: PsiClientContext, output: *mut *mut c_char, output_len: *mut size_t, error_out: *mut *mut c_char) -> c_int; + fn psi_client_create_request( + ctx: PsiClientContext, + inputs: *const PsiClientBuffer, + input_len: size_t, + output: *mut *mut c_char, + output_len: *mut size_t, + error_out: *mut *mut c_char, + ) -> c_int; + fn psi_client_get_intersection_size( + ctx: PsiClientContext, + server_setup: PsiClientBuffer, + server_response: PsiClientBuffer, + output: *mut i64, + error_out: *mut *mut c_char, + ) -> c_int; + fn psi_client_get_intersection( + ctx: PsiClientContext, + server_setup: PsiClientBuffer, + server_response: PsiClientBuffer, + output: *mut *mut i64, + output_len: *mut size_t, + error_out: *mut *mut c_char, + ) -> c_int; + fn psi_client_get_private_key_bytes( + ctx: PsiClientContext, + output: *mut *mut c_char, + output_len: *mut size_t, + error_out: *mut *mut c_char, + ) -> c_int; } impl PsiClient { /// Creates a new `PsiClient` instance with a fresh private key. pub fn create_with_new_key(reveal_intersection: bool) -> ClientResult { - let mut client = Self { ctx: ptr::null_mut(), reveal_intersection: reveal_intersection }; + let mut client = Self { + ctx: ptr::null_mut(), + reveal_intersection: reveal_intersection, + }; let mut error_null_ptr: *mut c_char = ptr::null_mut(); let error_ptr = &mut error_null_ptr; - let res_code = unsafe { psi_client_create_with_new_key(reveal_intersection, &mut client.ctx, error_ptr) }; + let res_code = unsafe { + psi_client_create_with_new_key(reveal_intersection, &mut client.ctx, error_ptr) + }; if res_code != 0 { - return Err(get_error("Failed to create client context", *error_ptr, res_code)); + return Err(get_error( + "Failed to create client context", + *error_ptr, + res_code, + )); } if client.ctx.is_null() { - return Err(ClientError::new("Failed to create client context: Context is NULL. This should never happen.".to_string())); + return Err(ClientError::new( + "Failed to create client context: Context is NULL. This should never happen." + .to_string(), + )); } Ok(client) @@ -60,22 +103,34 @@ impl PsiClient { /// for multiple requests can reveal information about the input sets. If in doubt, /// use `PsiClient::create_with_new_key`.** pub fn create_from_key(key: &[u8], reveal_intersection: bool) -> ClientResult { - let mut client = Self { ctx: ptr::null_mut(), reveal_intersection: reveal_intersection }; + let mut client = Self { + ctx: ptr::null_mut(), + reveal_intersection: reveal_intersection, + }; let mut error_null_ptr: *mut c_char = ptr::null_mut(); let error_ptr = &mut error_null_ptr; let key_bytes = PsiClientBuffer { ptr: key.as_ptr() as *const c_char, - len: key.len() as size_t + len: key.len() as size_t, }; - let res_code = unsafe { psi_client_create_from_key(key_bytes, reveal_intersection, &mut client.ctx, error_ptr) }; + let res_code = unsafe { + psi_client_create_from_key(key_bytes, reveal_intersection, &mut client.ctx, error_ptr) + }; if res_code != 0 { - return Err(get_error("Failed to create client context", *error_ptr, res_code)); + return Err(get_error( + "Failed to create client context", + *error_ptr, + res_code, + )); } if client.ctx.is_null() { - return Err(ClientError::new("Failed to create client context: Context is NULL. This should never happen.".to_string())); + return Err(ClientError::new( + "Failed to create client context: Context is NULL. This should never happen." + .to_string(), + )); } Ok(client) @@ -86,10 +141,13 @@ impl PsiClient { /// For each input element `x`, this computes `H(x)^c`, where `c` is the client's /// secret key for `ec_cipher`. pub fn create_request>(&self, raw_input: &[T]) -> ClientResult { - let input: Vec = raw_input.iter().map(|s| PsiClientBuffer { - ptr: s.as_ref().as_ptr() as *const c_char, - len: s.as_ref().len() as size_t - }).collect(); + let input: Vec = raw_input + .iter() + .map(|s| PsiClientBuffer { + ptr: s.as_ref().as_ptr() as *const c_char, + len: s.as_ref().len() as size_t, + }) + .collect(); let mut error_null_ptr: *mut c_char = ptr::null_mut(); let error_ptr = &mut error_null_ptr; @@ -97,17 +155,27 @@ impl PsiClient { let out_ptr = &mut out_null_ptr; let mut out_len = 0 as size_t; - let res_code = unsafe { psi_client_create_request(self.ctx, input.as_ptr(), input.len() as size_t, out_ptr, &mut out_len, error_ptr) }; + let res_code = unsafe { + psi_client_create_request( + self.ctx, + input.as_ptr(), + input.len() as size_t, + out_ptr, + &mut out_len, + error_ptr, + ) + }; if res_code != 0 { return Err(get_error("Failed to create request", *error_ptr, res_code)); } - let res = unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); + let res = + unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); unsafe { free(*out_ptr as *mut c_void) }; let request: Request = match protobuf::parse_from_bytes(&res) { Ok(r) => r, - Err(e) => return Err(ClientError::new(e.to_string())) + Err(e) => return Err(ClientError::new(e.to_string())), }; Ok(request) @@ -119,18 +187,24 @@ impl PsiClient { /// /// This should be used if this `PsiClient` instance was created with /// `reveal_intersection = false`. - pub fn get_intersection_size(&self, server_setup: &ServerSetup, response_proto: &Response) -> ClientResult { + pub fn get_intersection_size( + &self, + server_setup: &ServerSetup, + response_proto: &Response, + ) -> ClientResult { if self.reveal_intersection { - return Err(ClientError::new("reveal_intersection must be false!".to_string())); + return Err(ClientError::new( + "reveal_intersection must be false!".to_string(), + )); } let setup = match server_setup.write_to_bytes() { Ok(s) => s, - Err(e) => return Err(ClientError::new(e.to_string())) + Err(e) => return Err(ClientError::new(e.to_string())), }; let response = match response_proto.write_to_bytes() { Ok(r) => r, - Err(e) => return Err(ClientError::new(e.to_string())) + Err(e) => return Err(ClientError::new(e.to_string())), }; let mut error_null_ptr: *mut c_char = ptr::null_mut(); @@ -138,17 +212,29 @@ impl PsiClient { let mut out_res = 0i64; let setup_buf = PsiClientBuffer { ptr: setup.as_ptr() as *const c_char, - len: setup.len() as size_t + len: setup.len() as size_t, }; let response_buf = PsiClientBuffer { ptr: response.as_ptr() as *const c_char, - len: response.len() as size_t + len: response.len() as size_t, }; - let res_code = unsafe { psi_client_get_intersection_size(self.ctx, setup_buf, response_buf, &mut out_res, error_ptr) }; + let res_code = unsafe { + psi_client_get_intersection_size( + self.ctx, + setup_buf, + response_buf, + &mut out_res, + error_ptr, + ) + }; if res_code != 0 { - return Err(get_error("Failed to get intersection size", *error_ptr, res_code)); + return Err(get_error( + "Failed to get intersection size", + *error_ptr, + res_code, + )); } Ok(out_res as usize) @@ -160,18 +246,24 @@ impl PsiClient { /// /// This should be used if this `PsiClient` instance was created with /// `reveal_intersection = true`. - pub fn get_intersection(&self, server_setup: &ServerSetup, response_proto: &Response) -> ClientResult> { + pub fn get_intersection( + &self, + server_setup: &ServerSetup, + response_proto: &Response, + ) -> ClientResult> { if !self.reveal_intersection { - return Err(ClientError::new("reveal_intersection must be true!".to_string())); + return Err(ClientError::new( + "reveal_intersection must be true!".to_string(), + )); } let setup = match server_setup.write_to_bytes() { Ok(s) => s, - Err(e) => return Err(ClientError::new(e.to_string())) + Err(e) => return Err(ClientError::new(e.to_string())), }; let response = match response_proto.write_to_bytes() { Ok(r) => r, - Err(e) => return Err(ClientError::new(e.to_string())) + Err(e) => return Err(ClientError::new(e.to_string())), }; let mut error_null_ptr: *mut c_char = ptr::null_mut(); @@ -181,20 +273,34 @@ impl PsiClient { let mut out_len = 0 as size_t; let setup_buf = PsiClientBuffer { ptr: setup.as_ptr() as *const c_char, - len: setup.len() as size_t + len: setup.len() as size_t, }; let response_buf = PsiClientBuffer { ptr: response.as_ptr() as *const c_char, - len: response.len() as size_t + len: response.len() as size_t, }; - let res_code = unsafe { psi_client_get_intersection(self.ctx, setup_buf, response_buf, out_ptr, &mut out_len, error_ptr) }; + let res_code = unsafe { + psi_client_get_intersection( + self.ctx, + setup_buf, + response_buf, + out_ptr, + &mut out_len, + error_ptr, + ) + }; if res_code != 0 { - return Err(get_error("Failed to get intersection", *error_ptr, res_code)); + return Err(get_error( + "Failed to get intersection", + *error_ptr, + res_code, + )); } - let res = unsafe { slice::from_raw_parts(*out_ptr as *const i64, out_len as usize) }.to_owned(); + let res = + unsafe { slice::from_raw_parts(*out_ptr as *const i64, out_len as usize) }.to_owned(); unsafe { free(*out_ptr as *mut c_void) }; Ok(res) @@ -211,16 +317,22 @@ impl PsiClient { let out_ptr = &mut out_null_ptr; let mut out_len = 0 as size_t; - let res_code = unsafe { psi_client_get_private_key_bytes(self.ctx, out_ptr, &mut out_len, error_ptr) }; + let res_code = + unsafe { psi_client_get_private_key_bytes(self.ctx, out_ptr, &mut out_len, error_ptr) }; if res_code != 0 { - return Err(get_error("Failed to get private key bytes", *error_ptr, res_code)); + return Err(get_error( + "Failed to get private key bytes", + *error_ptr, + res_code, + )); } // private key is 32 bytes long assert_eq!(out_len as usize, 32); - let res = unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); + let res = + unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); unsafe { free(*out_ptr as *mut c_void) }; Ok(res) @@ -236,7 +348,12 @@ impl Drop for PsiClient { } fn get_error(msg: &str, error_ptr: *mut c_char, res_code: c_int) -> ClientError { - let error_str = unsafe { CStr::from_ptr(error_ptr).to_str().expect("Failed to get error string.").to_owned() }; + let error_str = unsafe { + CStr::from_ptr(error_ptr) + .to_str() + .expect("Failed to get error string.") + .to_owned() + }; unsafe { free(error_ptr as *mut c_void); @@ -251,7 +368,7 @@ pub type ClientResult = Result; /// Error type typically used to indicate an encryption or C interface error for PSI clients. #[derive(Debug)] pub struct ClientError { - msg: String + msg: String, } impl ClientError { @@ -276,24 +393,9 @@ impl error::Error for ClientError { mod tests { use super::*; - #[test] - fn test_create() { - for &reveal in &[false, true] { - let client = PsiClient::create_with_new_key(reveal).unwrap(); - client.create_request::(&vec![]).unwrap(); - - let client = PsiClient::create_with_new_key(reveal).unwrap(); - let new_client = PsiClient::create_from_key(&client.get_private_key_bytes().unwrap(), reveal).unwrap(); - assert_eq!(client.get_private_key_bytes().unwrap(), new_client.get_private_key_bytes().unwrap()); - - let client = PsiClient::create_from_key(&vec![1u8; 32], reveal).unwrap(); - assert_eq!(client.get_private_key_bytes().unwrap(), vec![1u8; 32]); - } - } - #[test] fn test_error() { - for &reveal in &[false, true] { + for reveal in [false, true] { assert!(PsiClient::create_from_key(&vec![0u8; 32], reveal).is_err()); } } diff --git a/private_set_intersection/rust/src/datastructure.rs b/private_set_intersection/rust/src/datastructure.rs new file mode 100644 index 00000000..456d5674 --- /dev/null +++ b/private_set_intersection/rust/src/datastructure.rs @@ -0,0 +1,9 @@ +#[repr(C)] +#[non_exhaustive] +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] +pub enum PsiDataStructure { + Raw, + #[default] + Gcs, + BloomFilter, +} diff --git a/private_set_intersection/rust/src/lib.rs b/private_set_intersection/rust/src/lib.rs index 3dcbb15c..cdb167f2 100644 --- a/private_set_intersection/rust/src/lib.rs +++ b/private_set_intersection/rust/src/lib.rs @@ -2,30 +2,33 @@ //! //! This crate provides Rust bindings to the core C++ PSI library, by wrapping the C interface. -extern crate libc; -extern crate protobuf; +use libc; // re-export protobufs so they can be used by the user -pub extern crate psi_rust_proto; - -pub mod server; +pub use psi_rust_proto; pub mod client; +pub mod datastructure; +pub mod server; use std::ffi::CStr; -extern { +extern "C" { fn psi_version() -> *const libc::c_char; } /// Returns the version of the core C++ PSI library. pub fn version() -> String { - unsafe { CStr::from_ptr(psi_version()).to_str().expect("The version string is not valid UTF-8.").to_owned() } + unsafe { + CStr::from_ptr(psi_version()) + .to_str() + .expect("The version string is not valid UTF-8.") + .to_owned() + } } #[cfg(test)] mod tests { - extern crate semver; - use super::*; + use semver; #[test] fn test_version() { diff --git a/private_set_intersection/rust/src/server.rs b/private_set_intersection/rust/src/server.rs index d703a16c..cc594763 100644 --- a/private_set_intersection/rust/src/server.rs +++ b/private_set_intersection/rust/src/server.rs @@ -1,52 +1,90 @@ //! Provides a way to create a `PsiServer` for the server side of the Private Set Intersection //! protocol. +use crate::datastructure::PsiDataStructure; use libc::*; - -use std::{fmt, error, ptr, slice}; -use std::ffi::CStr; - use protobuf::{self, Message}; - use psi_rust_proto::*; - +use std::ffi::CStr; +use std::{error, fmt, ptr, slice}; type PsiServerContext = *mut c_void; /// A handle for the C context of a PSI server. pub struct PsiServer { - ctx: PsiServerContext + ctx: PsiServerContext, } #[repr(C)] struct PsiServerBuffer { ptr: *const c_char, - len: size_t + len: size_t, } -extern { - fn psi_server_create_with_new_key(reveal_intersection: bool, ctx: *mut PsiServerContext, error_out: *mut *mut c_char) -> c_int; - fn psi_server_create_from_key(key_bytes: PsiServerBuffer, reveal_intersection: bool, ctx: *mut PsiServerContext, error_out: *mut *mut c_char) -> c_int; +extern "C" { + fn psi_server_create_with_new_key( + reveal_intersection: bool, + ctx: *mut PsiServerContext, + error_out: *mut *mut c_char, + ) -> c_int; + fn psi_server_create_from_key( + key_bytes: PsiServerBuffer, + reveal_intersection: bool, + ctx: *mut PsiServerContext, + error_out: *mut *mut c_char, + ) -> c_int; fn psi_server_delete(ctx: *mut PsiServerContext); - fn psi_server_create_setup_message(ctx: PsiServerContext, fpr: c_double, num_client_inputs: i64, input: *const PsiServerBuffer, input_len: size_t, output: *mut *mut c_char, output_len: *mut size_t, error_out: *mut *mut c_char) -> c_int; - fn psi_server_process_request(ctx: PsiServerContext, client_request: PsiServerBuffer, output: *mut *mut c_char, output_len: *mut size_t, error_out: *mut *mut c_char) -> c_int; - fn psi_server_get_private_key_bytes(ctx: PsiServerContext, output: *mut *mut c_char, output_len: *mut size_t, error_out: *mut *mut c_char) -> c_int; + fn psi_server_create_setup_message( + ctx: PsiServerContext, + fpr: c_double, + num_client_inputs: i64, + input: *const PsiServerBuffer, + input_len: size_t, + output: *mut *mut c_char, + output_len: *mut size_t, + error_out: *mut *mut c_char, + ds: PsiDataStructure, + ) -> c_int; + fn psi_server_process_request( + ctx: PsiServerContext, + client_request: PsiServerBuffer, + output: *mut *mut c_char, + output_len: *mut size_t, + error_out: *mut *mut c_char, + ) -> c_int; + fn psi_server_get_private_key_bytes( + ctx: PsiServerContext, + output: *mut *mut c_char, + output_len: *mut size_t, + error_out: *mut *mut c_char, + ) -> c_int; } impl PsiServer { /// Creates a new `PsiServer` instance with a fresh private key. pub fn create_with_new_key(reveal_intersection: bool) -> ServerResult { - let mut server = Self { ctx: ptr::null_mut() }; + let mut server = Self { + ctx: ptr::null_mut(), + }; let mut error_null_ptr: *mut c_char = ptr::null_mut(); let error_ptr = &mut error_null_ptr; - let res_code = unsafe { psi_server_create_with_new_key(reveal_intersection, &mut server.ctx, error_ptr) }; + let res_code = unsafe { + psi_server_create_with_new_key(reveal_intersection, &mut server.ctx, error_ptr) + }; if res_code != 0 { - return Err(get_error("Failed to create server context", *error_ptr, res_code)); + return Err(get_error( + "Failed to create server context", + *error_ptr, + res_code, + )); } if server.ctx.is_null() { - return Err(ServerError::new("Failed to create server context: Context is NULL. This should never happen.".to_string())); + return Err(ServerError::new( + "Failed to create server context: Context is NULL. This should never happen." + .to_string(), + )); } Ok(server) @@ -58,23 +96,34 @@ impl PsiServer { /// for multiple requests can reveal information about the input sets. If in doubt, /// use `PsiServer::create_with_new_key`.** pub fn create_from_key(key: &[u8], reveal_intersection: bool) -> ServerResult { - let mut server = Self { ctx: ptr::null_mut() }; + let mut server = Self { + ctx: ptr::null_mut(), + }; let mut error_null_ptr: *mut c_char = ptr::null_mut(); let error_ptr = &mut error_null_ptr; let key_bytes = PsiServerBuffer { ptr: key.as_ptr() as *const c_char, - len: key.len() as size_t + len: key.len() as size_t, }; - let res_code = unsafe { psi_server_create_from_key(key_bytes, reveal_intersection, &mut server.ctx, error_ptr) }; + let res_code = unsafe { + psi_server_create_from_key(key_bytes, reveal_intersection, &mut server.ctx, error_ptr) + }; if res_code != 0 { - return Err(get_error("Failed to create server context", *error_ptr, res_code)); + return Err(get_error( + "Failed to create server context", + *error_ptr, + res_code, + )); } if server.ctx.is_null() { - return Err(ServerError::new("Failed to create server context: Context is NULL. This should never happen.".to_string())); + return Err(ServerError::new( + "Failed to create server context: Context is NULL. This should never happen." + .to_string(), + )); } Ok(server) @@ -86,11 +135,20 @@ impl PsiServer { /// /// The false-positive rate `fpr` is the probability that any query of size `input_count` /// will result in a false positive. - pub fn create_setup_message>(&self, fpr: f64, input_count: usize, raw_input: &[T]) -> ServerResult { - let input: Vec = raw_input.iter().map(|s| PsiServerBuffer { - ptr: s.as_ref().as_ptr() as *const c_char, - len: s.as_ref().len() as size_t - }).collect(); + pub fn create_setup_message>( + &self, + fpr: f64, + input_count: usize, + raw_input: &[T], + ds: Option, + ) -> ServerResult { + let input: Vec = raw_input + .iter() + .map(|s| PsiServerBuffer { + ptr: s.as_ref().as_ptr() as *const c_char, + len: s.as_ref().len() as size_t, + }) + .collect(); let mut error_null_ptr: *mut c_char = ptr::null_mut(); let error_ptr = &mut error_null_ptr; @@ -98,17 +156,34 @@ impl PsiServer { let out_ptr = &mut out_null_ptr; let mut out_len = 0 as size_t; - let res_code = unsafe { psi_server_create_setup_message(self.ctx, fpr as c_double, input_count as i64, input.as_ptr(), input.len() as size_t, out_ptr, &mut out_len, error_ptr) }; + let res_code = unsafe { + psi_server_create_setup_message( + self.ctx, + fpr as c_double, + input_count as i64, + input.as_ptr(), + input.len() as size_t, + out_ptr, + &mut out_len, + error_ptr, + ds.unwrap_or_default(), + ) + }; if res_code != 0 { - return Err(get_error("Failed to create setup message", *error_ptr, res_code)); + return Err(get_error( + "Failed to create setup message", + *error_ptr, + res_code, + )); } - let res = unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); + let res = + unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); unsafe { free(*out_ptr as *mut c_void) }; let server_setup: ServerSetup = match protobuf::parse_from_bytes(&res) { Ok(s) => s, - Err(e) => return Err(ServerError::new(e.to_string())) + Err(e) => return Err(ServerError::new(e.to_string())), }; Ok(server_setup) @@ -126,7 +201,7 @@ impl PsiServer { pub fn process_request(&self, request_proto: &Request) -> ServerResult { let request = match request_proto.write_to_bytes() { Ok(r) => r, - Err(e) => return Err(ServerError::new(e.to_string())) + Err(e) => return Err(ServerError::new(e.to_string())), }; let mut error_null_ptr: *mut c_char = ptr::null_mut(); @@ -136,20 +211,23 @@ impl PsiServer { let mut out_len = 0 as size_t; let request_buf = PsiServerBuffer { ptr: request.as_ptr() as *const c_char, - len: request.len() as size_t + len: request.len() as size_t, }; - let res_code = unsafe { psi_server_process_request(self.ctx, request_buf, out_ptr, &mut out_len, error_ptr) }; + let res_code = unsafe { + psi_server_process_request(self.ctx, request_buf, out_ptr, &mut out_len, error_ptr) + }; if res_code != 0 { return Err(get_error("Failed to process request", *error_ptr, res_code)); } - let res = unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); + let res = + unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); unsafe { free(*out_ptr as *mut c_void) }; let response: Response = match protobuf::parse_from_bytes(&res) { Ok(r) => r, - Err(e) => return Err(ServerError::new(e.to_string())) + Err(e) => return Err(ServerError::new(e.to_string())), }; Ok(response) @@ -166,16 +244,22 @@ impl PsiServer { let out_ptr = &mut out_null_ptr; let mut out_len = 0 as size_t; - let res_code = unsafe { psi_server_get_private_key_bytes(self.ctx, out_ptr, &mut out_len, error_ptr) }; + let res_code = + unsafe { psi_server_get_private_key_bytes(self.ctx, out_ptr, &mut out_len, error_ptr) }; if res_code != 0 { - return Err(get_error("Failed to get private key bytes", *error_ptr, res_code)); + return Err(get_error( + "Failed to get private key bytes", + *error_ptr, + res_code, + )); } // private key is 32 bytes long assert_eq!(out_len as usize, 32); - let res = unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); + let res = + unsafe { slice::from_raw_parts(*out_ptr as *const u8, out_len as usize) }.to_owned(); unsafe { free(*out_ptr as *mut c_void) }; Ok(res) @@ -191,7 +275,12 @@ impl Drop for PsiServer { } fn get_error(msg: &str, error_ptr: *mut c_char, res_code: c_int) -> ServerError { - let error_str = unsafe { CStr::from_ptr(error_ptr).to_str().expect("Failed to get error string.").to_owned() }; + let error_str = unsafe { + CStr::from_ptr(error_ptr) + .to_str() + .expect("Failed to get error string.") + .to_owned() + }; unsafe { free(error_ptr as *mut c_void); @@ -206,7 +295,7 @@ pub type ServerResult = Result; /// Error type typically used to indicate an encryption or C interface error for PSI servers. #[derive(Debug)] pub struct ServerError { - msg: String + msg: String, } impl ServerError { @@ -231,24 +320,9 @@ impl error::Error for ServerError { mod tests { use super::*; - #[test] - fn test_create() { - for &reveal in &[false, true] { - let server = PsiServer::create_with_new_key(reveal).unwrap(); - server.create_setup_message::(0.001, 1000, &vec![]).unwrap(); - - let server = PsiServer::create_with_new_key(reveal).unwrap(); - let new_server = PsiServer::create_from_key(&server.get_private_key_bytes().unwrap(), reveal).unwrap(); - assert_eq!(server.get_private_key_bytes().unwrap(), new_server.get_private_key_bytes().unwrap()); - - let server = PsiServer::create_from_key(&vec![1u8; 32], reveal).unwrap(); - assert_eq!(server.get_private_key_bytes().unwrap(), vec![1u8; 32]); - } - } - #[test] fn test_error() { - for &reveal in &[false, true] { + for reveal in [false, true] { assert!(PsiServer::create_from_key(&vec![0u8; 32], reveal).is_err()); } } diff --git a/private_set_intersection/rust/tests/client_server_test.rs b/private_set_intersection/rust/tests/client_server_test.rs deleted file mode 100644 index 47c1e97a..00000000 --- a/private_set_intersection/rust/tests/client_server_test.rs +++ /dev/null @@ -1,54 +0,0 @@ -extern crate rust_psi; - -use rust_psi::*; - -use std::collections::HashSet; - -use std::iter::FromIterator; - -#[test] -fn test_client_server() { - for &reveal in &[false, true] { - let client = client::PsiClient::create_with_new_key(reveal).unwrap(); - let server = server::PsiServer::create_with_new_key(reveal).unwrap(); - - let num_client_elements = 1000; - let num_server_elements = 10000; - let client_elements = generate_elements(num_client_elements, 1); - let server_elements = generate_elements(num_server_elements, 2); - let fpr = 0.000000001f64; - - let setup = server.create_setup_message(fpr, num_client_elements, &server_elements).unwrap(); - - // setup message contains server elements - // setup message is sent to the client - - let request = client.create_request(&client_elements).unwrap(); - - // request contains client elements encrypted with client secret key - // request is sent to the server - - let response = server.process_request(&request).unwrap(); - - // response contains client elements encrypted with both client and server secret keys - // response is sent to the client - - if reveal { - let intersection = client.get_intersection(&setup, &response).unwrap(); - let set: HashSet = HashSet::from_iter(intersection.into_iter()); - - for i in 0..num_client_elements as i64 { - assert_eq!(set.contains(&i), i % 2 == 0); - } - } else { - let intersection_size = client.get_intersection_size(&setup, &response).unwrap(); - - assert!(intersection_size >= (num_client_elements / 2)); - assert!((intersection_size as f64) < ((num_client_elements as f64) / 2.0 * 1.1)); - } - } -} - -fn generate_elements(n: usize, m: usize) -> Vec { - (0..n).map(|i| format!("Element {}", i * m)).collect() -} diff --git a/private_set_intersection/rust/tests/integration_test.rs b/private_set_intersection/rust/tests/integration_test.rs new file mode 100644 index 00000000..bf852f5f --- /dev/null +++ b/private_set_intersection/rust/tests/integration_test.rs @@ -0,0 +1,78 @@ +use psi::client::PsiClient; +use psi::server::PsiServer; +use psi::*; +use std::collections::HashSet; +use std::iter::FromIterator; + +static CLIENT_KEY: &'static [u8] = &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, +]; +static SERVER_KEY: &'static [u8] = &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, +]; +const FPR: f64 = 0.01; +const NUM_CLIENT_ELEMENTS: usize = 10; +const NUM_SERVER_ELEMENTS: usize = 100; + +#[test] +fn test_static_key() { + let client = PsiClient::create_from_key(CLIENT_KEY, false).unwrap(); + assert_eq!(client.get_private_key_bytes().unwrap(), CLIENT_KEY); + + let server = PsiServer::create_from_key(SERVER_KEY, false).unwrap(); + assert_eq!(server.get_private_key_bytes().unwrap(), SERVER_KEY); +} + +#[test] +fn integration_test() { + for reveal in [false, true] { + for ds in [ + datastructure::PsiDataStructure::Raw, + datastructure::PsiDataStructure::Gcs, + datastructure::PsiDataStructure::BloomFilter, + ] { + let client = client::PsiClient::create_with_new_key(reveal).unwrap(); + let server = server::PsiServer::create_with_new_key(reveal).unwrap(); + + let client_elements: Vec = (0..NUM_CLIENT_ELEMENTS) + .map(|i| format!("Element {}", i)) + .collect(); + let server_elements: Vec = (0..NUM_SERVER_ELEMENTS) + .map(|i| format!("Element {}", i * 2)) + .collect(); + + let setup = server + .create_setup_message(FPR, NUM_CLIENT_ELEMENTS, &server_elements, Some(ds)) + .unwrap(); + + // setup message contains server elements + // setup message is sent to the client + + let request = client.create_request(&client_elements).unwrap(); + + // request contains client elements encrypted with client secret key + // request is sent to the server + + let response = server.process_request(&request).unwrap(); + + // response contains client elements encrypted with both client and server secret keys + // response is sent to the client + + if reveal { + let intersection = client.get_intersection(&setup, &response).unwrap(); + let set: HashSet = HashSet::from_iter(intersection.into_iter()); + + for i in 0..NUM_CLIENT_ELEMENTS as i64 { + assert_eq!(set.contains(&i), i % 2 == 0); + } + } else { + let intersection_size = client.get_intersection_size(&setup, &response).unwrap(); + + assert!(intersection_size >= (NUM_CLIENT_ELEMENTS / 2)); + assert!((intersection_size as f64) < ((NUM_CLIENT_ELEMENTS as f64) / 2.0 * 1.1)); + } + } + } +} diff --git a/rollup.config.js b/rollup.config.mjs similarity index 100% rename from rollup.config.js rename to rollup.config.mjs diff --git a/tools/package.bzl b/tools/package.bzl index 6f3236c1..99874ce5 100644 --- a/tools/package.bzl +++ b/tools/package.bzl @@ -1,2 +1,2 @@ """ Version of the current release """ -VERSION_LABEL = "1.1.1" +VERSION_LABEL = "2.0.0"