From 061aa6b7bde7ee0832611d7d7eb5a0e6db54bd15 Mon Sep 17 00:00:00 2001 From: Tommy Verrall Date: Fri, 8 Dec 2023 15:10:26 +0100 Subject: [PATCH 1/7] update sandbox references --- .../dev-portal/src/tutorials/cosmos-service/lib.md | 2 +- documentation/docs/src/bandwidth-credentials.md | 6 +++--- documentation/operators/src/nodes/validator-setup.md | 8 ++++---- envs/sandbox.env | 2 +- explorer-api/.env.dev | 2 +- explorer/.env.dev | 2 +- nym-wallet/nym-wallet-types/src/network/sandbox.rs | 2 +- sdk/typescript/docs/components/client/index.ts | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/documentation/dev-portal/src/tutorials/cosmos-service/lib.md b/documentation/dev-portal/src/tutorials/cosmos-service/lib.md index 9982403657..0e8e2ad050 100644 --- a/documentation/dev-portal/src/tutorials/cosmos-service/lib.md +++ b/documentation/dev-portal/src/tutorials/cosmos-service/lib.md @@ -26,7 +26,7 @@ Since this is the file where client creation and message parsing are handled, th Below this are the chain-related `const` variables. These have been hardcoded for this demo. ```rust -pub const DEFAULT_VALIDATOR_RPC: &str = "https://sandbox-validator1.nymtech.net"; +pub const DEFAULT_VALIDATOR_RPC: &str = "https://rpc.sandbox.nymtech.net"; pub const DEFAULT_DENOM: &str = "unym"; pub const DEFAULT_PREFIX: &str = "n"; ``` diff --git a/documentation/docs/src/bandwidth-credentials.md b/documentation/docs/src/bandwidth-credentials.md index f267cb045d..f7ee0ff087 100644 --- a/documentation/docs/src/bandwidth-credentials.md +++ b/documentation/docs/src/bandwidth-credentials.md @@ -28,7 +28,7 @@ COCONUT_DKG_CONTRACT_ADDRESS="nymt1gwk6muhmzeuxje7df7rjvqwl2vex0kj4t2hwuzmyx5k62 GROUP_CONTRACT_ADDRESS="nymt14ry36mwauycz08v8ndcujghxz4hmua5epxcn0mamlr3suqe0l2qsqx5ya2" STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0" -NYXD="https://sandbox-validator1.nymtech.net" +NYXD="https://rpc.sandbox.nymtech.net" NYM_API="https://sandbox-validator1-api.nymtech.net/api" ``` @@ -44,7 +44,7 @@ Next, you init the nym-client with the enabled credentials mode set to true: Using the new credentials binary, purchase some credentials for the client. The recovery directory is a directory where the credentials will be temporarily stored in case the request fails. -```./credential --config-env-file sandbox.env run --client-home-directory --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic "" --amount 50 --recovery-dir ``` +```./credential --config-env-file sandbox.env run --client-home-directory --nyxd-url https://rpc.sandbox.nymtech.net --mnemonic "" --amount 50 --recovery-dir ``` You can redeem this now by running the nym-client, in enabled credentials mode: @@ -62,7 +62,7 @@ Now time to init the socks5 client: Purchase credentials for this now too: -`./credential --config-env-file sandbox.env run --client-home-directory --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic "" --amount 100 --recovery-dir ` +`./credential --config-env-file sandbox.env run --client-home-directory --nyxd-url https://rpc.sandbox.nymtech.net --mnemonic "" --amount 100 --recovery-dir ` Run the socks5 client: diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 53f979019f..406f5fbea7 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -216,7 +216,7 @@ You can use the following command to download them for the correct network: wget -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json # Sandbox testnet -wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json | jq '.result.genesis' +wget -O $HOME/.nyxd/config/genesis.json https://rpc.sandbox.nymtech.net/snapshots/genesis.json | jq '.result.genesis' ``` ### `config.toml` configuration @@ -232,7 +232,7 @@ laddr = "tcp://0.0.0.0:26656" ``` # Sandbox testnet cors_allowed_origins = ["*"] -persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@sandbox-validator1.nymtech.net:26666" +persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@rpc.sandbox.nymtech.net:26666" laddr = "tcp://0.0.0.0:26656" ``` @@ -346,7 +346,7 @@ sudo apt install snapd -y sudo snap install lz4 # download the snapshot -wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://sandbox-validator1.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4 +wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://rpc.sandbox.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4 # reset your validator state nyxd tendermint unsafe-reset-all @@ -398,7 +398,7 @@ nyxd tx staking create-validator --gas-adjustment=1.15 --gas-prices=0.025unyx --from=<"KEYRING_NAME"> - --node https://sandbox-validator1.nymtech.net:443 + --node https://rpc.sandbox.nymtech.net:443 ``` You'll need Nyx tokens on mainnet / sandbox to perform the above tasks. diff --git a/envs/sandbox.env b/envs/sandbox.env index 2ce9298766..856550cca0 100644 --- a/envs/sandbox.env +++ b/envs/sandbox.env @@ -23,5 +23,5 @@ SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS=n1ps5yutd7sufwg058qd7ac7ldnlazsvmhzq STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0" EXPLORER_API=https://sandbox-explorer.nymtech.net/api -NYXD="https://sandbox-validator1.nymtech.net" +NYXD="https://rpc.sandbox.nymtech.net" NYM_API="https://sandbox-nym-api1.nymtech.net/api" diff --git a/explorer-api/.env.dev b/explorer-api/.env.dev index 0020aba233..7cb2d5a1db 100644 --- a/explorer-api/.env.dev +++ b/explorer-api/.env.dev @@ -22,7 +22,7 @@ NAME_SERVICE_CONTRACT_ADDRESS=n12ne7qtmdwd0j03t9t5es8md66wq4e5xg9neladrsag8fx3y8 SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS=n1ps5yutd7sufwg058qd7ac7ldnlazsvmhzqwucsfxmm445d70u8asqxpur4 STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0" -NYXD="https://sandbox-validator1.nymtech.net" +NYXD="https://rpc.sandbox.nymtech.net" NYM_API="https://sandbox-nym-api1.nymtech.net/api" GEOIP_DB_PATH=geo_ip/GeoLite2-City.mmdb diff --git a/explorer/.env.dev b/explorer/.env.dev index fe4119f671..3cc86ae00c 100644 --- a/explorer/.env.dev +++ b/explorer/.env.dev @@ -3,7 +3,7 @@ EXPLORER_API_URL=https://sandbox-explorer.nymtech.net/api/v1 NYM_API_URL=https://sandbox-nym-api1.nymtech.net -VALIDATOR_URL=https://sandbox-validator1.nymtech.net +VALIDATOR_URL=https://rpc.sandbox.nymtech.net BIG_DIPPER_URL=https://sandbox-blocks.nymtech.net CURRENCY_DENOM=unym CURRENCY_STAKING_DENOM=unyx diff --git a/nym-wallet/nym-wallet-types/src/network/sandbox.rs b/nym-wallet/nym-wallet-types/src/network/sandbox.rs index ace2ff7663..1186c07eac 100644 --- a/nym-wallet/nym-wallet-types/src/network/sandbox.rs +++ b/nym-wallet/nym-wallet-types/src/network/sandbox.rs @@ -30,7 +30,7 @@ pub(crate) const EPHEMERA_CONTRACT_ADDRESS: &str = pub(crate) fn validators() -> Vec { vec![ValidatorDetails::new( - "https://sandbox-validator1.nymtech.net", + "https://rpc.sandbox.nymtech.net", Some("https://sandbox-nym-api1.nymtech.net/api"), )] } diff --git a/sdk/typescript/docs/components/client/index.ts b/sdk/typescript/docs/components/client/index.ts index afaf1253e8..ba7a70ef76 100644 --- a/sdk/typescript/docs/components/client/index.ts +++ b/sdk/typescript/docs/components/client/index.ts @@ -6,7 +6,7 @@ export const mainnetSettings = { }; export const qaSettings = { - url: 'wss://sandbox-validator1.nymtech.net/', + url: 'wss://rpc.sandbox.nymtech.net', mixnetContractAddress: 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav', mnemonic: process.env.QA_MNEMONIC, address: 'n13uryxldwdllpakevsmt6n0uyfn3kgr2wvj5dnf', From 9ea2eafb2cc3062806dcf94cec3f7492ff6f6bb2 Mon Sep 17 00:00:00 2001 From: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:25:26 +0100 Subject: [PATCH 2/7] Update documentation/operators/src/nodes/validator-setup.md Co-authored-by: Sachin Kamath --- documentation/operators/src/nodes/validator-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 406f5fbea7..5f1ddf161c 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -232,7 +232,7 @@ laddr = "tcp://0.0.0.0:26656" ``` # Sandbox testnet cors_allowed_origins = ["*"] -persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@rpc.sandbox.nymtech.net:26666" +persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@:3.72.19.120:26656" laddr = "tcp://0.0.0.0:26656" ``` From 82bfab48a55ed68a3f7db39c9cd058a54cf449e5 Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Fri, 15 Dec 2023 13:25:49 +0100 Subject: [PATCH 3/7] feat(vpn-desktop): integrate nym-vpn-lib (#4244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix initial selected vpn mode * wip * Set gateway config * Init procedure and reading config * Update two comments * add nym-api field to app config * Remove hardcoded RUST_LOG from package.json * Use scope instead of explicit drop * Spawn vpn client in separate thread and separate runtime * Re-set nym-vpn-lib in Cargo.toml * add vpn handle to app state * add vpn client call to disconnect cmd * wip * Setup listener tasks * Read entire env after all * add env config file to app config * doc: add notes on config * refactor env config file as optional * add logic to connection status changes * refactor disconnect command * fix handle click connect button * update doc * add some fake delay to establish connection * localize backend messages * refactor extract registering listeners into modules * add more tracing logs * refactor clean code * refactor clean code * refactor vpn config creation * fix connect app_config read * refactor rename listener functions * add backend support for twohop mode * copy change * base connected status on Ready message Ready message sent from vpn client * filter out specific error * add logs * use exported receiver types from nym_vpn_lib * Handle exit message * Change to nym-vpn for consistency * prefix comment with TODO * update doc * remove nym_api config property use the one provided in the env config file * fix css compile error * log received backend error (frontend) --------- Co-authored-by: Jon Häggblad --- nym-vpn/ui/README.md | 34 + nym-vpn/ui/package.json | 2 +- nym-vpn/ui/src-tauri/Cargo.lock | 6018 ++++++++++++++++- nym-vpn/ui/src-tauri/Cargo.toml | 10 +- .../ui/src-tauri/src/commands/connection.rs | 230 +- nym-vpn/ui/src-tauri/src/fs/config.rs | 9 +- nym-vpn/ui/src-tauri/src/main.rs | 92 +- nym-vpn/ui/src-tauri/src/states/app.rs | 7 +- nym-vpn/ui/src-tauri/src/states/mod.rs | 6 +- nym-vpn/ui/src-tauri/src/vpn_client.rs | 173 + nym-vpn/ui/src-tauri/tauri.conf.json | 2 +- nym-vpn/ui/src/i18n/config.ts | 4 +- nym-vpn/ui/src/i18n/en/backend-messages.json | 6 + nym-vpn/ui/src/i18n/en/home.json | 2 +- .../ui/src/pages/home/ConnectionStatus.tsx | 9 +- nym-vpn/ui/src/pages/home/Home.tsx | 49 +- nym-vpn/ui/src/state/main.ts | 14 +- nym-vpn/ui/src/state/useTauriEvents.ts | 5 +- nym-vpn/ui/src/styles.css | 1 + nym-vpn/ui/src/types/app-state.ts | 6 +- nym-vpn/ui/tailwind.config.ts | 2 +- 21 files changed, 6462 insertions(+), 219 deletions(-) create mode 100644 nym-vpn/ui/src-tauri/src/vpn_client.rs create mode 100644 nym-vpn/ui/src/i18n/en/backend-messages.json diff --git a/nym-vpn/ui/README.md b/nym-vpn/ui/README.md index f4c67d253b..03456e2a44 100644 --- a/nym-vpn/ui/README.md +++ b/nym-vpn/ui/README.md @@ -19,6 +19,32 @@ To install: yarn ``` +## Required config + +First you can provide a network configuration using en env file, +pick the relevant one [here](https://github.com/nymtech/nym/tree/develop/envs). +The mainnet config will be used by default if not provided. + +Then create the main app config file `config.toml` under `nym-vpn` +directory, full path is platform specific: + +- Linux: Resolves to `$XDG_CONFIG_HOME` or `$HOME/.config` +- macOS: Resolves to `$HOME/Library/Application Support` +- Windows: Resolves to `{FOLDERID_RoamingAppData}` + +For example on Linux the path would be `~/.config/nym-vpn/config.toml` + +```toml +# example config on Linux + +# path to the env config file if you provide one +env_config_file = "$HOME/.config/nym-vpn/qa.env" + +# pick a gateway and exit router accordingly to the selected env +entry_gateway = "xxx" +exit_router = "xxx" +``` + ## Dev ``` @@ -32,6 +58,14 @@ cd src-tauri cargo tauri dev ``` +**NOTE** Starting a VPN connection requires root privileges as it will set up a link interface. +If you want to connect during development, you need to run the app as root, +likely using `sudo` (or equivalent) + +```shell +sudo -E RUST_LOG=debug cargo tauri dev +``` + #### Logging Rust logging (standard output) is controlled by the `RUST_LOG` diff --git a/nym-vpn/ui/package.json b/nym-vpn/ui/package.json index 8d81de9d39..800a1efcb5 100644 --- a/nym-vpn/ui/package.json +++ b/nym-vpn/ui/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "dev:app": "RUST_LOG=nymvpn_ui=trace tauri dev", + "dev:app": "tauri dev", "dev:browser": "vite --mode dev-browser", "build": "tsc && vite build", "build:app": "yarn tauri build", diff --git a/nym-vpn/ui/src-tauri/Cargo.lock b/nym-vpn/ui/src-tauri/Cargo.lock index 9e8b65c41e..719b71f123 100644 --- a/nym-vpn/ui/src-tauri/Cargo.lock +++ b/nym-vpn/ui/src-tauri/Cargo.lock @@ -23,6 +23,86 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array 0.14.7", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures", + "ctr 0.8.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead 0.4.3", + "aes 0.7.5", + "cipher 0.3.0", + "ctr 0.8.0", + "ghash", + "subtle 2.4.1", +] + +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom 0.2.10", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -47,6 +127,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -62,12 +148,111 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "atk" version = "0.15.1" @@ -92,12 +277,86 @@ dependencies = [ "system-deps 6.1.2", ] +[[package]] +name = "atoi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atoi" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa 1.0.9", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -113,6 +372,18 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" @@ -125,6 +396,59 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bip32" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e141fb0f8be1c7b45887af94c88b182472b57c96b56773250ae00cd6a14a164" +dependencies = [ + "bs58 0.5.0", + "hmac 0.12.1", + "k256", + "once_cell", + "pbkdf2", + "rand_core 0.6.4", + "ripemd", + "sha2 0.10.8", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "bip39" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "rand_core 0.6.4", + "serde", + "unicode-normalization", + "zeroize", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + [[package]] name = "bitflags" version = "1.3.2" @@ -137,21 +461,102 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" +dependencies = [ + "byte-tools", + "crypto-mac 0.7.0", + "digest 0.8.1", + "opaque-debug 0.2.3", +] + +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + [[package]] name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] +[[package]] +name = "bls12_381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397" +dependencies = [ + "digest 0.9.0", + "ff 0.10.1", + "group 0.10.0", + "pairing 0.20.0", + "rand_core 0.6.4", + "subtle 2.4.1", +] + +[[package]] +name = "bls12_381" +version = "0.6.0" +source = "git+https://github.com/jstuczyn/bls12_381?branch=gt-serialisation#10fb6f700bfda17c8475af3bfd31e3fec15f2278" +dependencies = [ + "digest 0.9.0", + "ff 0.11.1", + "group 0.11.0", + "pairing 0.21.0", + "rand_core 0.6.4", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "bnum" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "845141a4fade3f790628b7daaaa298a25b204fb28907eb54febe5142db6ce653" + [[package]] name = "brotli" version = "3.4.0" @@ -173,6 +578,21 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2 0.10.8", +] + [[package]] name = "bstr" version = "1.7.0" @@ -189,6 +609,28 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byte_string" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11aade7a05aa8c3a351cedc44c3fc45806430543382fcc4743a9b757a2a0b4ed" + +[[package]] +name = "bytecodec" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf4c9d0bbf32eea58d7c0f812058138ee8edaf0f2802b6d03561b504729a325" +dependencies = [ + "byteorder", + "trackable 0.2.24", +] + [[package]] name = "bytemuck" version = "1.14.0" @@ -250,6 +692,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -267,7 +710,7 @@ checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" dependencies = [ "byteorder", "fnv", - "uuid", + "uuid 1.5.0", ] [[package]] @@ -295,6 +738,65 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862" +dependencies = [ + "byteorder", + "keystream", +] + +[[package]] +name = "chacha20" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +dependencies = [ + "aead 0.4.3", + "chacha20 0.8.2", + "cipher 0.3.0", + "poly1305 0.7.2", + "zeroize", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead 0.5.2", + "chacha20 0.9.1", + "cipher 0.4.4", + "poly1305 0.8.0", + "zeroize", +] + [[package]] name = "chrono" version = "0.4.31" @@ -307,7 +809,97 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clap" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.10.0", +] + +[[package]] +name = "clap_complete" +version = "4.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_complete_fig" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e571d70e22ec91d34e1c5317c8308035a2280d925167646bf094fc5de1737c" +dependencies = [ + "clap", + "clap_complete", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "classic-mceliece-rust" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ce62f72a15a9071f83c5084bdf0af4e8cbf31431e79eb4a5509a2f7fe7fe5d" +dependencies = [ + "rand 0.8.5", + "sha3", + "zeroize", ] [[package]] @@ -346,6 +938,23 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "combine" version = "4.6.6" @@ -356,6 +965,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "convert_case" version = "0.4.0" @@ -402,6 +1029,105 @@ dependencies = [ "libc", ] +[[package]] +name = "cosmos-sdk-proto" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32560304ab4c365791fd307282f76637213d8083c1a98490c35159cd67852237" +dependencies = [ + "prost 0.12.3", + "prost-types 0.12.3", + "tendermint-proto", +] + +[[package]] +name = "cosmrs" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47126f5364df9387b9d8559dcef62e99010e1d4098f39eb3f7ee4b5c254e40ea" +dependencies = [ + "bip32", + "cosmos-sdk-proto", + "ecdsa 0.16.9", + "eyre", + "k256", + "rand_core 0.6.4", + "serde", + "serde_json", + "signature 2.2.0", + "subtle-encoding", + "tendermint", + "tendermint-rpc", + "thiserror", +] + +[[package]] +name = "cosmwasm-crypto" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bb3c77c3b7ce472056968c745eb501c440fbc07be5004eba02782c35bfbbe3" +dependencies = [ + "digest 0.10.7", + "ecdsa 0.16.9", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea73e9162e6efde00018d55ed0061e93a108b5d6ec4548b4f8ce3c706249687" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6b2fb76758ef59cddc77f2e2ae91c22f77da49037e9f182e9c2833f0e959b1" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfa39422f0d9f1c9a6fd3711573258495314dfa3aae738ea825ecd9964bc659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-std" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6dc2ee23313add5ecacc3ccac217b9967ad9d2d11bd56e5da6aa65a9da6138" +dependencies = [ + "base64 0.13.1", + "bnum", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.8", + "thiserror", +] + [[package]] name = "cpufeatures" version = "0.2.10" @@ -411,6 +1137,36 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +dependencies = [ + "crc-catalog 1.1.1", +] + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog 2.4.0", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.3.2" @@ -430,6 +1186,40 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -439,16 +1229,61 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle 2.4.1", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +dependencies = [ + "generic-array 0.12.4", + "subtle 1.0.0", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.7", + "subtle 2.4.1", +] + [[package]] name = "cssparser" version = "0.27.2" @@ -486,14 +1321,205 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher 0.3.0", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "cw-controllers" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d8edce4b78785f36413f67387e4be7d0cb7d032b5d4164bcc024f9c3f3f2ea" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw-storage-plus" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2", + "schemars", + "semver 1.0.20", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ac2dc7a55ad64173ca1e0a46697c31b7a5c51342f55a1e84a724da4eb99908" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw20" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011c45920f8200bd5d32d4fe52502506f64f2f75651ab408054d4cfc75ca3a9b" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils", + "schemars", + "serde", +] + +[[package]] +name = "cw3" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171af3d9127de6805a7dd819fb070c7d2f6c3ea85f4193f42cef259f0a7f33d5" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils", + "cw20", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw4" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a398696307efadaaa2d0850076f865fa706c959d493cb4203314f72be6b77a64" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "serde", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.9.3", + "syn 1.0.109", ] [[package]] @@ -506,21 +1532,98 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 2.0.38", ] +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core 0.10.2", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.38", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.2", + "lock_api", + "once_cell", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + +[[package]] +name = "dbus" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +dependencies = [ + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "default-net" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85dc7576d8346d3c86ad64dc64d26d0f6c970ba4795b850f15ee94467d8e53eb" +dependencies = [ + "dlopen2", + "libc", + "memalloc", + "netlink-packet-core 0.7.0", + "netlink-packet-route 0.17.1", + "netlink-sys", + "once_cell", + "system-configuration", + "windows 0.48.0", +] + +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid 0.7.1", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid 0.9.5", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.9" @@ -531,6 +1634,42 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" +dependencies = [ + "darling 0.10.2", + "derive_builder_core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" +dependencies = [ + "darling 0.10.2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -544,14 +1683,52 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", + "const-oid 0.9.5", "crypto-common", + "subtle 2.4.1", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", ] [[package]] @@ -564,6 +1741,29 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -581,6 +1781,23 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dotenvy" version = "0.15.7" @@ -602,12 +1819,157 @@ dependencies = [ "dtoa", ] +[[package]] +name = "duct" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ae3fc31835f74c2a7ceda3aeede378b0ae2e74c8f1c36559fcc9ae2a4e7d3e" +dependencies = [ + "libc", + "once_cell", + "os_pipe 1.1.4", + "shared_child", +] + [[package]] name = "dunce" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der 0.5.1", + "elliptic-curve 0.11.12", + "signature 1.4.0", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.8", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979", + "signature 2.2.0", + "spki", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.4.0", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.3.2", + "der 0.5.1", + "generic-array 0.14.7", + "rand_core 0.6.4", + "sec1 0.2.1", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.0", + "generic-array 0.14.7", + "group 0.13.0", + "pkcs8", + "rand_core 0.6.4", + "sec1 0.7.3", + "subtle 2.4.1", + "zeroize", +] + [[package]] name = "embed-resource" version = "2.4.0" @@ -636,12 +1998,107 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "enum-as-inner" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "enum-iterator" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a0ac4aeb3a18f92eaf09c6bb9b3ac30ff61ca95514fc58cbead1c9a6bf5401" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime 1.3.0", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime 2.1.0", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "err-context" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449aad22b1364e927ff3bf50f55404efd705c40065fb47f73f28704de707c89e" + +[[package]] +name = "err-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34a887c8df3ed90498c1c437ce21f211c8e27672921a8ffa293cb8d6d4caa9e" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + [[package]] name = "errno" version = "0.3.5" @@ -652,6 +2109,42 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "backtrace", + "version_check", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "eyre" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fastrand" version = "2.0.1" @@ -667,13 +2160,49 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "rand_core 0.6.4", + "subtle 2.4.1", +] + +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.4", + "subtle 2.4.1", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle 2.4.1", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset", + "memoffset 0.9.0", "rustc_version", ] @@ -689,6 +2218,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -699,6 +2240,28 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flex-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" +dependencies = [ + "eyre", + "paste", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "pin-project", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -729,6 +2292,27 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futf" version = "0.1.5" @@ -740,25 +2324,41 @@ dependencies = [ ] [[package]] -name = "futures-channel" -version = "0.3.28" +name = "futures" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -766,16 +2366,27 @@ dependencies = [ ] [[package]] -name = "futures-io" -version = "0.3.28" +name = "futures-intrusive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.11.2", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", @@ -790,16 +2401,17 @@ checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -919,14 +2531,25 @@ dependencies = [ "windows 0.48.0", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ + "serde", "typenum", "version_check", + "zeroize", ] [[package]] @@ -936,8 +2559,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -947,8 +2572,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getset" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug 0.3.0", + "polyval", ] [[package]] @@ -987,6 +2636,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "git2" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c" +dependencies = [ + "bitflags 1.3.2", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "glib" version = "0.15.12" @@ -1051,6 +2713,52 @@ dependencies = [ "regex", ] +[[package]] +name = "gloo-net" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gobject-sys" version = "0.15.10" @@ -1062,6 +2770,41 @@ dependencies = [ "system-deps 6.1.2", ] +[[package]] +name = "group" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +dependencies = [ + "byteorder", + "ff 0.10.1", + "rand_core 0.6.4", + "subtle 2.4.1", +] + +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "byteorder", + "ff 0.11.1", + "rand_core 0.6.4", + "subtle 2.4.1", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle 2.4.1", +] + [[package]] name = "gtk" version = "0.15.5" @@ -1132,21 +2875,69 @@ dependencies = [ "indexmap 1.9.3", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.10", "tracing", ] +[[package]] +name = "handlebars" +version = "3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" +dependencies = [ + "log", + "pest", + "pest_derive", + "quick-error 2.0.1", + "serde", + "serde_json", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.7", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.7", +] [[package]] name = "hashbrown" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +dependencies = [ + "ahash 0.8.6", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +dependencies = [ + "hashbrown 0.11.2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.2", +] [[package]] name = "heck" @@ -1162,6 +2953,18 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] [[package]] name = "hermit-abi" @@ -1175,6 +2978,70 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hkdf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" +dependencies = [ + "digest 0.9.0", + "hmac 0.11.0", +] + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "html5ever" version = "0.25.2" @@ -1214,6 +3081,21 @@ dependencies = [ "itoa 1.0.9", ] +[[package]] +name = "http-api-client" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tracing", + "url", + "wasmtimer", +] + [[package]] name = "http-body" version = "0.4.5" @@ -1237,12 +3119,47 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +[[package]] +name = "httpcodec" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f49d64351430cabd543943b79d48aaf0bc95a41d9ccf5b8774c2cfd23422775" +dependencies = [ + "bytecodec", + "trackable 0.2.24", +] + [[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error 1.2.3", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "humantime-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" +dependencies = [ + "humantime 2.1.0", + "serde", +] + [[package]] name = "hyper" version = "0.14.27" @@ -1267,6 +3184,32 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls 0.21.9", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1319,6 +3262,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.4.0" @@ -1359,6 +3313,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.3" @@ -1390,6 +3350,48 @@ dependencies = [ "cfb", ] +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" +dependencies = [ + "bitflags 1.3.2", + "futures-core", + "inotify-sys", + "libc", + "tokio", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "instant" version = "0.1.12" @@ -1399,12 +3401,92 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "internet-checksum" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6d6206008e25125b1f97fbe5d309eb7b85141cf9199d52dbd3729a1584dd16" + +[[package]] +name = "ioctl-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c429fffa658f288669529fc26565f728489a2e39bc7b24a428aaaf51355182e" + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.5", + "widestring", + "windows-sys 0.48.0", + "winreg 0.50.0", +] + [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "ipnetwork" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8eca9f51da27bc908ef3dd85c21e1bbba794edaf94d7841e37356275b82d31e" +dependencies = [ + "serde", +] + +[[package]] +name = "iprange" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00" +dependencies = [ + "ipnet", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.3", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -1440,6 +3522,20 @@ dependencies = [ "system-deps 5.0.0", ] +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + [[package]] name = "jni" version = "0.20.0" @@ -1460,6 +3556,39 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jnix" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd797d41e48568eb956ded20d7e5e3f2df1c02980d9e5b9aab9b47bd3a9f599" +dependencies = [ + "jni 0.19.0", + "jnix-macros", + "once_cell", + "parking_lot 0.12.1", +] + +[[package]] +name = "jnix-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002f4dfe6d97ae88c33f3489c0d31ffc6f81d9a492de98ff113b127d73bafff8" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.64" @@ -1481,6 +3610,66 @@ dependencies = [ "treediff", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "k256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +dependencies = [ + "cfg-if", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "once_cell", + "sha2 0.10.8", + "signature 2.2.0", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keystream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28" + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "kuchiki" version = "0.8.1" @@ -1518,6 +3707,56 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "libdbus-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libgit2-sys" +version = "0.13.5+1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e5ea06c26926f1002dd553fded6cfcdc9784c1f60feeb58368b4d9b07b6dba" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libsqlite3-sys" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "line-wrap" version = "0.1.1" @@ -1527,12 +3766,30 @@ dependencies = [ "safemem", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +[[package]] +name = "lioness" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9" +dependencies = [ + "arrayref", + "blake2", + "chacha", + "keystream", +] + [[package]] name = "lock_api" version = "0.4.11" @@ -1564,6 +3821,21 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "lru_time_cache" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9106e1d747ffd48e6be5bb2d97fa706ed25b144fbee4d5c02eae110cd8d6badd" + [[package]] name = "mac" version = "0.1.1" @@ -1607,6 +3879,12 @@ dependencies = [ "tendril", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -1622,12 +3900,53 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", + "md5-asm", +] + +[[package]] +name = "md5-asm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61d33bc4cdfe5c60340e282bbbee0a6e2bc57f0b9279bb3489c5004d12492e5c" +dependencies = [ + "cc", +] + +[[package]] +name = "memalloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df39d232f5c40b0891c10216992c2f250c054105cb1e56f0fc9032db6203ecc1" + [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -1643,6 +3962,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "minisign-verify" version = "0.2.1" @@ -1666,10 +3991,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] +[[package]] +name = "mnl" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a5469630da93e1813bb257964c0ccee3b26b6879dd858039ddec35cc8681ed" +dependencies = [ + "libc", + "log", + "mnl-sys", +] + +[[package]] +name = "mnl-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9750685b201e1ecfaaf7aa5d0387829170fa565989cc481b49080aa155f70457" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + [[package]] name = "native-tls" version = "0.2.11" @@ -1716,18 +4069,193 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "netlink-packet-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +dependencies = [ + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" +dependencies = [ + "anyhow", + "byteorder", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5dee5ed749373c298237fe694eb0a51887f4cc1a27370c8464bac4382348f1a" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core 0.4.2", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core 0.7.0", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core 0.4.2", + "netlink-sys", + "thiserror", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +dependencies = [ + "bytes", + "futures", + "libc", + "log", + "tokio", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nftnl" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9201688bd0bc571dfa4c21ce0a525480c8b782776cf88e12571fa89108dd920" +dependencies = [ + "bitflags 1.3.2", + "err-derive", + "log", + "nftnl-sys", +] + +[[package]] +name = "nftnl-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b5c587b6a5e76a3a5d51e0a757ae66dbff38c277563485807ae979ce361b56" +dependencies = [ + "cfg-if", + "libc", + "pkg-config", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + [[package]] name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "notify" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486" +dependencies = [ + "bitflags 1.3.2", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify 0.9.6", + "kqueue", + "libc", + "mio", + "walkdir", + "windows-sys 0.45.0", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1738,6 +4266,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1766,6 +4305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1774,7 +4314,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.3", "libc", ] @@ -1800,14 +4340,963 @@ dependencies = [ ] [[package]] -name = "nymvpn-ui" +name = "nym-api-requests" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bs58 0.4.0", + "cosmrs", + "cosmwasm-std", + "getset", + "nym-coconut-interface", + "nym-mixnet-contract-common", + "nym-node-requests", + "schemars", + "serde", +] + +[[package]] +name = "nym-bandwidth-controller" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bip39", + "nym-coconut-interface", + "nym-credential-storage", + "nym-credentials", + "nym-crypto", + "nym-network-defaults", + "nym-validator-client", + "rand 0.7.3", + "thiserror", + "url", +] + +[[package]] +name = "nym-bin-common" +version = "0.6.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "atty", + "clap", + "clap_complete", + "clap_complete_fig", + "log", + "pretty_env_logger", + "schemars", + "semver 0.11.0", + "serde", + "vergen", +] + +[[package]] +name = "nym-client-core" +version = "1.1.15" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "base64 0.21.5", + "cfg-if", + "dashmap", + "dirs 4.0.0", + "futures", + "gloo-timers", + "humantime-serde", + "log", + "nym-bandwidth-controller", + "nym-config", + "nym-credential-storage", + "nym-crypto", + "nym-explorer-client", + "nym-gateway-client", + "nym-gateway-requests", + "nym-network-defaults", + "nym-nonexhaustive-delayqueue", + "nym-pemstore", + "nym-sphinx", + "nym-task", + "nym-topology", + "nym-validator-client", + "rand 0.7.3", + "reqwest", + "serde", + "serde_json", + "sha2 0.10.8", + "sqlx 0.6.3", + "tap", + "thiserror", + "time", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-utils", + "wasmtimer", + "zeroize", +] + +[[package]] +name = "nym-coconut" +version = "0.5.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bls12_381 0.6.0", + "bs58 0.4.0", + "digest 0.9.0", + "ff 0.11.1", + "getrandom 0.2.10", + "group 0.11.0", + "itertools 0.10.5", + "nym-dkg", + "nym-pemstore", + "rand 0.8.5", + "serde", + "serde_derive", + "sha2 0.9.9", + "thiserror", +] + +[[package]] +name = "nym-coconut-bandwidth-contract-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "nym-multisig-contract-common", +] + +[[package]] +name = "nym-coconut-dkg-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils", + "nym-contracts-common", + "nym-multisig-contract-common", +] + +[[package]] +name = "nym-coconut-interface" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bs58 0.4.0", + "getset", + "nym-coconut", + "serde", + "thiserror", +] + +[[package]] +name = "nym-config" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "dirs 5.0.1", + "handlebars", + "log", + "nym-network-defaults", + "serde", + "toml 0.7.8", + "url", +] + +[[package]] +name = "nym-contracts-common" +version = "0.5.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bs58 0.4.0", + "cosmwasm-schema", + "cosmwasm-std", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "nym-credential-storage" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "log", + "sqlx 0.5.13", + "thiserror", + "tokio", +] + +[[package]] +name = "nym-credential-utils" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "log", + "nym-bandwidth-controller", + "nym-client-core", + "nym-config", + "nym-credential-storage", + "nym-credentials", + "nym-validator-client", + "thiserror", + "tokio", +] + +[[package]] +name = "nym-credentials" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bls12_381 0.5.0", + "cosmrs", + "log", + "nym-api-requests", + "nym-coconut-interface", + "nym-crypto", + "nym-validator-client", + "thiserror", +] + +[[package]] +name = "nym-crypto" +version = "0.4.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "aes 0.8.3", + "blake3", + "bs58 0.4.0", + "cipher 0.4.4", + "ctr 0.9.2", + "digest 0.10.7", + "ed25519-dalek", + "generic-array 0.14.7", + "hkdf 0.12.3", + "hmac 0.12.1", + "nym-pemstore", + "nym-sphinx-types", + "rand 0.7.3", + "subtle-encoding", + "thiserror", + "x25519-dalek 1.1.1", + "zeroize", +] + +[[package]] +name = "nym-dkg" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bitvec", + "bls12_381 0.6.0", + "bs58 0.4.0", + "ff 0.11.1", + "group 0.11.0", + "lazy_static", + "nym-pemstore", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "serde", + "serde_derive", + "sha2 0.9.9", + "thiserror", + "zeroize", +] + +[[package]] +name = "nym-ephemera-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils", + "nym-contracts-common", +] + +[[package]] +name = "nym-exit-policy" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "serde", + "thiserror", + "tracing", +] + +[[package]] +name = "nym-explorer-api-requests" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-api-requests", + "nym-contracts-common", + "nym-mixnet-contract-common", + "schemars", + "serde", +] + +[[package]] +name = "nym-explorer-client" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "log", + "nym-explorer-api-requests", + "reqwest", + "serde", + "thiserror", + "url", +] + +[[package]] +name = "nym-gateway-client" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "futures", + "getrandom 0.2.10", + "gloo-utils", + "log", + "nym-bandwidth-controller", + "nym-coconut-interface", + "nym-credential-storage", + "nym-crypto", + "nym-gateway-requests", + "nym-network-defaults", + "nym-pemstore", + "nym-sphinx", + "nym-task", + "nym-validator-client", + "rand 0.7.3", + "serde", + "thiserror", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-utils", + "wasmtimer", +] + +[[package]] +name = "nym-gateway-requests" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bs58 0.4.0", + "futures", + "generic-array 0.14.7", + "log", + "nym-coconut-interface", + "nym-credentials", + "nym-crypto", + "nym-pemstore", + "nym-sphinx", + "rand 0.7.3", + "serde", + "serde_json", + "thiserror", + "tungstenite", + "zeroize", +] + +[[package]] +name = "nym-group-contract-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cw-controllers", + "cw4", + "schemars", + "serde", +] + +[[package]] +name = "nym-ip-packet-requests" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bincode", + "bytes", + "nym-sphinx", + "rand 0.8.5", + "serde", + "thiserror", +] + +[[package]] +name = "nym-mixnet-contract-common" +version = "0.6.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bs58 0.4.0", + "cosmwasm-schema", + "cosmwasm-std", + "humantime-serde", + "log", + "nym-contracts-common", + "schemars", + "serde", + "serde-json-wasm", + "serde_repr", + "thiserror", + "time", +] + +[[package]] +name = "nym-multisig-contract-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "cw3", + "cw4", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "nym-name-service-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-controllers", + "cw-utils", + "nym-contracts-common", + "serde", + "thiserror", +] + +[[package]] +name = "nym-network-defaults" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cfg-if", + "dotenvy", + "hex-literal", + "once_cell", + "schemars", + "serde", + "thiserror", + "url", +] + +[[package]] +name = "nym-node-requests" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "base64 0.21.5", + "http-api-client", + "nym-bin-common", + "nym-crypto", + "nym-exit-policy", + "nym-wireguard-types", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "nym-nonexhaustive-delayqueue" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "tokio", + "tokio-stream", + "tokio-util 0.7.10", + "wasmtimer", +] + +[[package]] +name = "nym-ordered-buffer" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "log", + "thiserror", +] + +[[package]] +name = "nym-outfox" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "blake3", + "chacha20 0.9.1", + "chacha20poly1305 0.10.1", + "curve25519-dalek 3.2.0", + "getrandom 0.2.10", + "log", + "rand 0.7.3", + "rayon", + "sphinx-packet", + "thiserror", + "zeroize", +] + +[[package]] +name = "nym-pemstore" +version = "0.3.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "pem", +] + +[[package]] +name = "nym-sdk" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "bip39", + "bytecodec", + "bytes", + "futures", + "http", + "httpcodec", + "log", + "nym-bandwidth-controller", + "nym-client-core", + "nym-credential-storage", + "nym-credential-utils", + "nym-credentials", + "nym-crypto", + "nym-gateway-requests", + "nym-network-defaults", + "nym-ordered-buffer", + "nym-service-providers-common", + "nym-socks5-client-core", + "nym-socks5-requests", + "nym-sphinx", + "nym-task", + "nym-topology", + "nym-validator-client", + "rand 0.7.3", + "tap", + "thiserror", + "toml 0.5.11", + "url", +] + +[[package]] +name = "nym-service-provider-directory-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-controllers", + "cw-utils", + "nym-contracts-common", + "thiserror", +] + +[[package]] +name = "nym-service-providers-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "log", + "nym-bin-common", + "nym-sphinx-anonymous-replies", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "nym-socks5-client-core" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "anyhow", + "dirs 4.0.0", + "futures", + "log", + "nym-bandwidth-controller", + "nym-client-core", + "nym-config", + "nym-contracts-common", + "nym-credential-storage", + "nym-mixnet-contract-common", + "nym-network-defaults", + "nym-service-providers-common", + "nym-socks5-proxy-helpers", + "nym-socks5-requests", + "nym-sphinx", + "nym-task", + "nym-validator-client", + "pin-project", + "rand 0.7.3", + "reqwest", + "schemars", + "serde", + "tap", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "nym-socks5-proxy-helpers" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bytes", + "futures", + "log", + "nym-ordered-buffer", + "nym-socks5-requests", + "nym-task", + "tokio", + "tokio-util 0.7.10", +] + +[[package]] +name = "nym-socks5-requests" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bincode", + "log", + "nym-exit-policy", + "nym-service-providers-common", + "nym-sphinx-addressing", + "serde", + "serde_json", + "tap", + "thiserror", +] + +[[package]] +name = "nym-sphinx" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "log", + "nym-crypto", + "nym-sphinx-acknowledgements", + "nym-sphinx-addressing", + "nym-sphinx-anonymous-replies", + "nym-sphinx-chunking", + "nym-sphinx-cover", + "nym-sphinx-forwarding", + "nym-sphinx-framing", + "nym-sphinx-params", + "nym-sphinx-routing", + "nym-sphinx-types", + "nym-topology", + "rand 0.7.3", + "rand_distr", + "thiserror", + "tokio", +] + +[[package]] +name = "nym-sphinx-acknowledgements" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-crypto", + "nym-pemstore", + "nym-sphinx-addressing", + "nym-sphinx-params", + "nym-sphinx-routing", + "nym-sphinx-types", + "nym-topology", + "rand 0.7.3", + "thiserror", + "zeroize", +] + +[[package]] +name = "nym-sphinx-addressing" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-crypto", + "nym-sphinx-types", + "serde", + "thiserror", +] + +[[package]] +name = "nym-sphinx-anonymous-replies" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bs58 0.4.0", + "nym-crypto", + "nym-sphinx-addressing", + "nym-sphinx-params", + "nym-sphinx-routing", + "nym-sphinx-types", + "nym-topology", + "rand 0.7.3", + "serde", + "thiserror", + "wasm-bindgen", +] + +[[package]] +name = "nym-sphinx-chunking" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "log", + "nym-sphinx-addressing", + "nym-sphinx-params", + "nym-sphinx-types", + "rand 0.7.3", + "thiserror", +] + +[[package]] +name = "nym-sphinx-cover" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-crypto", + "nym-sphinx-acknowledgements", + "nym-sphinx-addressing", + "nym-sphinx-chunking", + "nym-sphinx-forwarding", + "nym-sphinx-params", + "nym-sphinx-routing", + "nym-sphinx-types", + "nym-topology", + "rand 0.7.3", + "thiserror", +] + +[[package]] +name = "nym-sphinx-forwarding" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-outfox", + "nym-sphinx-addressing", + "nym-sphinx-params", + "nym-sphinx-types", + "thiserror", +] + +[[package]] +name = "nym-sphinx-framing" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "bytes", + "nym-sphinx-params", + "nym-sphinx-types", + "thiserror", + "tokio-util 0.7.10", +] + +[[package]] +name = "nym-sphinx-params" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-crypto", + "nym-sphinx-types", + "serde", + "thiserror", +] + +[[package]] +name = "nym-sphinx-routing" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-sphinx-addressing", + "nym-sphinx-types", + "thiserror", +] + +[[package]] +name = "nym-sphinx-types" +version = "0.2.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "nym-outfox", + "sphinx-packet", + "thiserror", +] + +[[package]] +name = "nym-task" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "futures", + "log", + "thiserror", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasmtimer", +] + +[[package]] +name = "nym-topology" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "bs58 0.4.0", + "log", + "nym-api-requests", + "nym-bin-common", + "nym-config", + "nym-crypto", + "nym-mixnet-contract-common", + "nym-sphinx-addressing", + "nym-sphinx-routing", + "nym-sphinx-types", + "rand 0.7.3", + "semver 0.11.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "nym-validator-client" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bip32", + "bip39", + "colored", + "cosmrs", + "cosmwasm-std", + "cw-controllers", + "cw-utils", + "cw2", + "cw3", + "cw4", + "eyre", + "flate2", + "futures", + "http-api-client", + "itertools 0.10.5", + "log", + "nym-api-requests", + "nym-coconut-bandwidth-contract-common", + "nym-coconut-dkg-common", + "nym-coconut-interface", + "nym-config", + "nym-contracts-common", + "nym-ephemera-common", + "nym-group-contract-common", + "nym-mixnet-contract-common", + "nym-multisig-contract-common", + "nym-name-service-common", + "nym-network-defaults", + "nym-service-provider-directory-common", + "nym-vesting-contract-common", + "openssl", + "prost 0.12.3", + "reqwest", + "serde", + "serde_json", + "sha2 0.9.9", + "tendermint-rpc", + "thiserror", + "tokio", + "url", + "wasmtimer", + "zeroize", +] + +[[package]] +name = "nym-vesting-contract-common" +version = "0.7.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "nym-contracts-common", + "nym-mixnet-contract-common", + "serde", + "thiserror", +] + +[[package]] +name = "nym-vpn-lib" +version = "0.1.0" +dependencies = [ + "bincode", + "bytes", + "default-net", + "futures", + "ipnetwork", + "log", + "nym-bin-common", + "nym-client-core", + "nym-config", + "nym-crypto", + "nym-ip-packet-requests", + "nym-node-requests", + "nym-sdk", + "nym-task", + "nym-validator-client", + "nym-wireguard-types", + "serde", + "serde_json", + "signature 1.4.0", + "talpid-core", + "talpid-routing", + "talpid-tunnel", + "talpid-types", + "talpid-wireguard", + "tap", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", + "tun", + "url", +] + +[[package]] +name = "nym-vpn-ui" version = "0.0.0" dependencies = [ "anyhow", "dotenvy", + "futures", + "nym-vpn-lib", "once_cell", "serde", "serde_json", + "shadowsocks", + "shadowsocks-service", "tauri", "tauri-build", "thiserror", @@ -1819,6 +5308,22 @@ dependencies = [ "ts-rs", ] +[[package]] +name = "nym-wireguard-types" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "base64 0.21.5", + "dashmap", + "hmac 0.12.1", + "log", + "nym-crypto", + "serde", + "sha2 0.10.8", + "thiserror", + "x25519-dalek 2.0.0", +] + [[package]] name = "objc" version = "0.2.7" @@ -1873,6 +5378,18 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "open" version = "3.2.0" @@ -1915,6 +5432,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.1.6+3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.95" @@ -1923,16 +5449,83 @@ checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "os_pipe" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb233f06c2307e1f5ce2ecad9f8121cffbbee2c95428f44ea85222e460d0d213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "os_pipe" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19736d80675fbe9fe33426268150b951a3fb8f5cfca2a23a17c85ef3adb24e3b" +dependencies = [ + "ecdsa 0.13.4", + "elliptic-curve 0.11.12", + "sec1 0.2.1", +] + +[[package]] +name = "p384" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755d8266e41f57bd8562ed9b6e93cdcf73ead050e1e8c3a27ea3871b6643a20c" +dependencies = [ + "ecdsa 0.13.4", + "elliptic-curve 0.11.12", + "sec1 0.2.1", +] + +[[package]] +name = "pairing" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de9d09263c9966e8196fe0380c9dbbc7ea114b5cf371ba29004bc1f9c6db7f3" +dependencies = [ + "group 0.10.0", +] + +[[package]] +name = "pairing" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42" +dependencies = [ + "group 0.11.0", +] + [[package]] name = "pango" version = "0.15.10" @@ -1958,6 +5551,31 @@ dependencies = [ "system-deps 6.1.2", ] +[[package]] +name = "parity-tokio-ipc" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" +dependencies = [ + "futures", + "libc", + "log", + "rand 0.7.3", + "tokio", + "winapi", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1965,7 +5583,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -1978,21 +5610,144 @@ dependencies = [ "libc", "redox_syscall 0.4.1", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pathdiff" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + +[[package]] +name = "peg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" + +[[package]] +name = "pem" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +dependencies = [ + "base64 0.13.1", + "once_cell", + "regex", +] + [[package]] name = "percent-encoding" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pest" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "pest_meta" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.8", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.0.2", +] + +[[package]] +name = "pfctl" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e0c1e1bc65fb241166b7ec8278d89cc2432d41adcbe57ffe1095c81e1d7b44" +dependencies = [ + "derive_builder", + "errno 0.2.8", + "error-chain", + "ioctl-sys", + "ipnetwork", + "libc", +] + [[package]] name = "phf" version = "0.8.0" @@ -2101,6 +5856,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2113,12 +5888,28 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.8", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + [[package]] name = "plist" version = "1.5.1" @@ -2146,6 +5937,40 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.4.1", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.5.1", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.4.1", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2164,6 +5989,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger 0.7.1", + "log", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -2213,6 +6058,104 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +dependencies = [ + "bytes", + "prost-derive 0.12.3", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools 0.10.5", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost 0.11.9", + "prost-types 0.11.9", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +dependencies = [ + "anyhow", + "itertools 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + +[[package]] +name = "prost-types" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +dependencies = [ + "prost 0.12.3", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.30.0" @@ -2231,6 +6174,22 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.7.3" @@ -2294,6 +6253,16 @@ dependencies = [ "getrandom 0.2.10", ] +[[package]] +name = "rand_distr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9532ada3929fb8b2e9dbe28d1e06c9b2cc65813f074fcb6bd5fbefeff9d56" +dependencies = [ + "num-traits", + "rand 0.7.3", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -2318,6 +6287,26 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -2415,6 +6404,7 @@ dependencies = [ "http", "http-body", "hyper", + "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -2424,13 +6414,17 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls 0.21.9", + "rustls-native-certs", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "system-configuration", "tokio", "tokio-native-tls", - "tokio-util", + "tokio-rustls 0.24.1", + "tokio-util 0.7.10", "tower-service", "url", "wasm-bindgen", @@ -2440,6 +6434,26 @@ dependencies = [ "winreg 0.50.0", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error 1.2.3", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle 2.4.1", +] + [[package]] name = "rfd" version = "0.10.0" @@ -2464,6 +6478,76 @@ dependencies = [ "windows 0.37.0", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom 0.2.10", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "ring-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6242f589b69a0555addb0bb759f81e5cba40485d38b36f780ab3a588b2bdf064" +dependencies = [ + "aead 0.4.3", + "digest 0.9.0", + "ecdsa 0.13.4", + "ed25519 1.5.3", + "generic-array 0.14.7", + "opaque-debug 0.3.0", + "p256", + "p384", + "ring 0.16.20", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rtnetlink" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f1cfa18f8cebe685373a2697915d7e0db3b4554918bba118385e0f71f258a7" +dependencies = [ + "futures", + "log", + "netlink-packet-route 0.13.0", + "netlink-proto", + "nix 0.24.3", + "thiserror", + "tokio", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2476,7 +6560,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.20", ] [[package]] @@ -2486,12 +6570,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" dependencies = [ "bitflags 2.4.1", - "errno", + "errno 0.3.5", "libc", "linux-raw-sys", "windows-sys 0.48.0", ] +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.1", + "log", + "ring 0.16.20", + "sct 0.6.1", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +dependencies = [ + "log", + "ring 0.16.20", + "sct 0.7.1", + "webpki 0.22.4", +] + +[[package]] +name = "rustls" +version = "0.21.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-webpki", + "sct 0.7.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.5", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -2528,6 +6680,31 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -2540,6 +6717,52 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring 0.16.20", + "untrusted 0.7.1", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der 0.5.1", + "generic-array 0.14.7", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.8", + "generic-array 0.14.7", + "pkcs8", + "subtle 2.4.1", + "zeroize", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -2583,6 +6806,15 @@ dependencies = [ "thin-slice", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.20" @@ -2593,25 +6825,73 @@ dependencies = [ ] [[package]] -name = "serde" -version = "1.0.189" +name = "semver-parser" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "sendfd" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604b71b8fc267e13bb3023a2c901126c8f349393666a6d98ac1ae5729b701798" +dependencies = [ + "libc", + "tokio", +] + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] -name = "serde_derive" -version = "1.0.189" +name = "serde-json-wasm" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", "syn 2.0.38", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_json" version = "1.0.107" @@ -2678,7 +6958,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.38", @@ -2716,6 +6996,40 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", + "sha1-asm", +] + +[[package]] +name = "sha1-asm" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba6947745e7f86be3b8af00b7355857085dbdf8901393c89514510eb61f4e21" +dependencies = [ + "cc", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "sha2" version = "0.10.8" @@ -2724,7 +7038,101 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shadowsocks" +version = "1.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16fc99441d1a1b91b5f7b5093773d631ad506761a973e0a632f1836d1b05939" +dependencies = [ + "arc-swap", + "async-trait", + "base64 0.13.1", + "byte_string", + "bytes", + "cfg-if", + "futures", + "libc", + "log", + "nix 0.23.2", + "notify", + "once_cell", + "pin-project", + "sendfd", + "serde", + "serde_json", + "serde_urlencoded", + "shadowsocks-crypto", + "socket2 0.4.10", + "thiserror", + "tokio", + "tokio-tfo", + "trust-dns-resolver", + "url", + "winapi", +] + +[[package]] +name = "shadowsocks-crypto" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd381517e3eb8fec5090696debfdea972d8afe6fc926c26c7bfd5fee9053efbd" +dependencies = [ + "aes 0.7.5", + "aes-gcm", + "cfg-if", + "chacha20 0.8.2", + "chacha20poly1305 0.9.1", + "hkdf 0.12.3", + "md-5", + "rand 0.8.5", + "ring-compat", + "sha1", +] + +[[package]] +name = "shadowsocks-service" +version = "1.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c3eb3ce85fb4c1f7451d2a5704503d3146ed7d626a17a63194092f07be45a4" +dependencies = [ + "arc-swap", + "async-trait", + "byte_string", + "byteorder", + "bytes", + "cfg-if", + "futures", + "idna 0.2.3", + "ipnet", + "iprange", + "json5", + "libc", + "log", + "lru_time_cache", + "nix 0.23.2", + "once_cell", + "pin-project", + "regex", + "serde", + "shadowsocks", + "socket2 0.4.10", + "spin 0.9.8", + "thiserror", + "tokio", + "winapi", ] [[package]] @@ -2736,6 +7144,50 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared_child" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -2811,6 +7263,248 @@ dependencies = [ "system-deps 5.0.0", ] +[[package]] +name = "sphinx-packet" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc43eda802856ee82a7555c7b75ceb9e07451741c7a2f5f23d036020e01189d4" +dependencies = [ + "aes 0.7.5", + "arrayref", + "blake2", + "bs58 0.4.0", + "byteorder", + "chacha", + "curve25519-dalek 3.2.0", + "digest 0.9.0", + "hkdf 0.11.0", + "hmac 0.11.0", + "lioness", + "log", + "rand 0.7.3", + "rand_distr", + "sha2 0.9.9", + "subtle 2.4.1", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.8", +] + +[[package]] +name = "sqlformat" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +dependencies = [ + "itertools 0.10.5", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlformat" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +dependencies = [ + "itertools 0.12.0", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" +dependencies = [ + "sqlx-core 0.5.13", + "sqlx-macros 0.5.13", +] + +[[package]] +name = "sqlx" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188" +dependencies = [ + "sqlx-core 0.6.3", + "sqlx-macros 0.6.3", +] + +[[package]] +name = "sqlx-core" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" +dependencies = [ + "ahash 0.7.7", + "atoi 0.4.0", + "bitflags 1.3.2", + "byteorder", + "bytes", + "crc 2.1.0", + "crossbeam-queue", + "either", + "event-listener", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "hashlink 0.7.0", + "hex", + "indexmap 1.9.3", + "itoa 1.0.9", + "libc", + "libsqlite3-sys", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "rustls 0.19.1", + "sha2 0.10.8", + "smallvec", + "sqlformat 0.1.8", + "sqlx-rt 0.5.13", + "stringprep", + "thiserror", + "tokio-stream", + "url", + "webpki 0.21.4", + "webpki-roots 0.21.1", +] + +[[package]] +name = "sqlx-core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" +dependencies = [ + "ahash 0.7.7", + "atoi 1.0.0", + "bitflags 1.3.2", + "byteorder", + "bytes", + "crc 3.0.1", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "hashlink 0.8.4", + "hex", + "indexmap 1.9.3", + "itoa 1.0.9", + "libc", + "libsqlite3-sys", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "rustls 0.20.9", + "rustls-pemfile", + "sha2 0.10.8", + "smallvec", + "sqlformat 0.2.3", + "sqlx-rt 0.6.3", + "stringprep", + "thiserror", + "tokio-stream", + "url", + "webpki-roots 0.22.6", +] + +[[package]] +name = "sqlx-macros" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" +dependencies = [ + "dotenv", + "either", + "heck 0.4.1", + "once_cell", + "proc-macro2", + "quote", + "sha2 0.10.8", + "sqlx-core 0.5.13", + "sqlx-rt 0.5.13", + "syn 1.0.109", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" +dependencies = [ + "dotenvy", + "either", + "heck 0.4.1", + "once_cell", + "proc-macro2", + "quote", + "sha2 0.10.8", + "sqlx-core 0.6.3", + "sqlx-rt 0.6.3", + "syn 1.0.109", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" +dependencies = [ + "once_cell", + "tokio", + "tokio-rustls 0.22.0", +] + +[[package]] +name = "sqlx-rt" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" +dependencies = [ + "once_cell", + "tokio", + "tokio-rustls 0.23.4", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2834,7 +7528,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot", + "parking_lot 0.12.1", "phf_shared 0.10.0", "precomputed-hash", "serde", @@ -2852,12 +7546,65 @@ dependencies = [ "quote", ] +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subslice" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a8e4809a3bb02de01f1f7faf1ba01a83af9e8eabcd4d31dd6e413d14d56aae" +dependencies = [ + "memchr", +] + +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + [[package]] name = "syn" version = "1.0.109" @@ -2880,6 +7627,24 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2927,6 +7692,260 @@ dependencies = [ "version-compare 0.1.1", ] +[[package]] +name = "talpid-core" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "async-trait", + "atty", + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "chrono", + "duct", + "err-derive", + "futures", + "hex", + "inotify 0.10.2", + "internet-checksum", + "ipnetwork", + "jnix", + "lazy_static", + "libc", + "log", + "memoffset 0.6.5", + "mnl", + "netlink-packet-route 0.13.0", + "netlink-sys", + "nftnl", + "nix 0.23.2", + "once_cell", + "os_pipe 0.9.2", + "parity-tokio-ipc", + "parking_lot 0.11.2", + "pfctl", + "prost 0.11.9", + "rand 0.8.5", + "regex", + "resolv-conf", + "rtnetlink", + "shadowsocks-service", + "shell-escape", + "socket2 0.4.10", + "subslice", + "system-configuration", + "talpid-dbus", + "talpid-openvpn", + "talpid-routing", + "talpid-time", + "talpid-tunnel", + "talpid-tunnel-config-client", + "talpid-types", + "talpid-windows-net", + "talpid-wireguard", + "tokio", + "tonic", + "tonic-build", + "triggered", + "trust-dns-server", + "tun", + "uuid 0.8.2", + "which", + "widestring", + "windows-service", + "windows-sys 0.42.0", + "winreg 0.7.0", + "zeroize", +] + +[[package]] +name = "talpid-dbus" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "dbus", + "err-derive", + "lazy_static", + "libc", + "log", + "tokio", +] + +[[package]] +name = "talpid-openvpn" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "async-trait", + "atty", + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "duct", + "err-derive", + "futures", + "lazy_static", + "log", + "os_pipe 0.9.2", + "parity-tokio-ipc", + "parking_lot 0.11.2", + "prost 0.11.9", + "shadowsocks-service", + "shell-escape", + "socket2 0.4.10", + "talpid-routing", + "talpid-tunnel", + "talpid-types", + "talpid-windows-net", + "tokio", + "tonic", + "tonic-build", + "triggered", + "uuid 0.8.2", + "which", + "widestring", + "windows-sys 0.42.0", + "winreg 0.7.0", +] + +[[package]] +name = "talpid-routing" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "err-derive", + "futures", + "ipnetwork", + "lazy_static", + "libc", + "log", + "netlink-packet-route 0.13.0", + "netlink-sys", + "rtnetlink", + "socket2 0.4.10", + "talpid-types", + "talpid-windows-net", + "tokio", + "tokio-stream", + "widestring", + "windows-sys 0.42.0", +] + +[[package]] +name = "talpid-time" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "libc", + "tokio", +] + +[[package]] +name = "talpid-tunnel" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "cfg-if", + "duct", + "err-derive", + "futures", + "ipnetwork", + "jnix", + "log", + "nix 0.23.2", + "talpid-routing", + "talpid-types", + "talpid-windows-net", + "tokio", + "tun", + "windows-sys 0.42.0", +] + +[[package]] +name = "talpid-tunnel-config-client" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "classic-mceliece-rust", + "log", + "prost 0.11.9", + "rand 0.8.5", + "talpid-types", + "tokio", + "tonic", + "tonic-build", + "tower", +] + +[[package]] +name = "talpid-types" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "base64 0.13.1", + "err-derive", + "ipnetwork", + "jnix", + "rand 0.8.5", + "serde", + "x25519-dalek 2.0.0", + "zeroize", +] + +[[package]] +name = "talpid-windows-net" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "err-derive", + "futures", + "libc", + "socket2 0.4.10", + "winapi", + "windows-sys 0.42.0", +] + +[[package]] +name = "talpid-wireguard" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "chrono", + "duct", + "err-derive", + "futures", + "hex", + "internet-checksum", + "ipnetwork", + "lazy_static", + "libc", + "log", + "netlink-packet-core 0.4.2", + "netlink-packet-route 0.13.0", + "netlink-packet-utils", + "netlink-proto", + "nix 0.23.2", + "parking_lot 0.11.2", + "rand 0.8.5", + "rtnetlink", + "socket2 0.4.10", + "talpid-dbus", + "talpid-routing", + "talpid-tunnel", + "talpid-tunnel-config-client", + "talpid-types", + "talpid-windows-net", + "tokio", + "tokio-stream", + "tunnel-obfuscation", + "widestring", + "windows-sys 0.42.0", + "zeroize", +] + [[package]] name = "tao" version = "0.16.4" @@ -2952,7 +7971,7 @@ dependencies = [ "gtk", "image", "instant", - "jni", + "jni 0.20.0", "lazy_static", "libc", "log", @@ -2961,14 +7980,14 @@ dependencies = [ "ndk-sys", "objc", "once_cell", - "parking_lot", + "parking_lot 0.12.1", "png", "raw-window-handle", "scopeguard", "serde", "tao-macros", "unicode-segmentation", - "uuid", + "uuid 1.5.0", "windows 0.39.0", "windows-implement", "x11-dl", @@ -2985,6 +8004,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tar" version = "0.4.40" @@ -3033,7 +8058,7 @@ dependencies = [ "regex", "reqwest", "rfd", - "semver", + "semver 1.0.20", "serde", "serde_json", "serde_repr", @@ -3049,7 +8074,7 @@ dependencies = [ "time", "tokio", "url", - "uuid", + "uuid 1.5.0", "webkit2gtk", "webview2-com", "windows 0.39.0", @@ -3067,7 +8092,7 @@ dependencies = [ "dirs-next", "heck 0.4.1", "json-patch", - "semver", + "semver 1.0.20", "serde", "serde_json", "tauri-utils", @@ -3090,14 +8115,14 @@ dependencies = [ "proc-macro2", "quote", "regex", - "semver", + "semver 1.0.20", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "tauri-utils", "thiserror", "time", - "uuid", + "uuid 1.5.0", "walkdir", ] @@ -3131,7 +8156,7 @@ dependencies = [ "tauri-utils", "thiserror", "url", - "uuid", + "uuid 1.5.0", "webview2-com", "windows 0.39.0", ] @@ -3149,7 +8174,7 @@ dependencies = [ "raw-window-handle", "tauri-runtime", "tauri-utils", - "uuid", + "uuid 1.5.0", "webkit2gtk", "webview2-com", "windows 0.39.0", @@ -3176,7 +8201,7 @@ dependencies = [ "phf 0.10.1", "proc-macro2", "quote", - "semver", + "semver 1.0.20", "serde", "serde_json", "serde_with", @@ -3209,6 +8234,101 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tendermint" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc2294fa667c8b548ee27a9ba59115472d0a09c2ba255771092a7f1dcf03a789" +dependencies = [ + "bytes", + "digest 0.10.7", + "ed25519 2.2.3", + "ed25519-consensus", + "flex-error", + "futures", + "k256", + "num-traits", + "once_cell", + "prost 0.12.3", + "prost-types 0.12.3", + "ripemd", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2 0.10.8", + "signature 2.2.0", + "subtle 2.4.1", + "subtle-encoding", + "tendermint-proto", + "time", + "zeroize", +] + +[[package]] +name = "tendermint-config" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a25dbe8b953e80f3d61789fbdb83bf9ad6c0ef16df5ca6546f49912542cc137" +dependencies = [ + "flex-error", + "serde", + "serde_json", + "tendermint", + "toml 0.5.11", + "url", +] + +[[package]] +name = "tendermint-proto" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc728a4f9e891d71adf66af6ecaece146f9c7a11312288a3107b3e1d6979aaf" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost 0.12.3", + "prost-types 0.12.3", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + +[[package]] +name = "tendermint-rpc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbf0a4753b46a190f367337e0163d0b552a2674a6bac54e74f9f2cdcde2969b" +dependencies = [ + "async-trait", + "bytes", + "flex-error", + "futures", + "getrandom 0.2.10", + "peg", + "pin-project", + "reqwest", + "semver 1.0.20", + "serde", + "serde_bytes", + "serde_json", + "subtle 2.4.1", + "subtle-encoding", + "tendermint", + "tendermint-config", + "tendermint-proto", + "thiserror", + "time", + "tokio", + "tracing", + "url", + "uuid 0.8.2", + "walkdir", +] + [[package]] name = "tendril" version = "0.4.3" @@ -3273,6 +8393,7 @@ checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", "itoa 1.0.9", + "js-sys", "powerfmt", "serde", "time-core", @@ -3320,11 +8441,35 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot 0.12.1", "pin-project-lite", + "signal-hook-registry", "socket2 0.5.5", + "tokio-macros", "windows-sys 0.48.0", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -3335,6 +8480,95 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls 0.19.1", + "tokio", + "webpki 0.21.4", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.9", + "tokio", + "webpki 0.22.4", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.9", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util 0.7.10", +] + +[[package]] +name = "tokio-tfo" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4279aec5ded232170bf39130dd0e0deaed2c9f31cd3b5db1f2021056bcf5f94a" +dependencies = [ + "cfg-if", + "futures", + "libc", + "log", + "once_cell", + "pin-project", + "socket2 0.4.10", + "tokio", + "winapi", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "native-tls", + "tokio", + "tokio-native-tls", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.10" @@ -3345,6 +8579,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", + "slab", "tokio", "tracing", ] @@ -3417,6 +8652,77 @@ dependencies = [ "winnow", ] +[[package]] +name = "tonic" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.13.1", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.11.9", + "prost-derive 0.11.9", + "tokio", + "tokio-stream", + "tokio-util 0.7.10", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util 0.7.10", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -3429,6 +8735,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3455,6 +8762,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.1.3" @@ -3484,6 +8801,35 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "trackable" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98abb9e7300b9ac902cc04920945a874c1973e08c310627cc4458c04b70dd32" +dependencies = [ + "trackable 1.3.0", + "trackable_derive", +] + +[[package]] +name = "trackable" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15bd114abb99ef8cee977e517c8f37aee63f184f2d08e3e6ceca092373369ae" +dependencies = [ + "trackable_derive", +] + +[[package]] +name = "trackable_derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "treediff" version = "4.0.2" @@ -3493,6 +8839,103 @@ dependencies = [ "serde_json", ] +[[package]] +name = "triggered" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce148eae0d1a376c1b94ae651fc3261d9cb8294788b962b7382066376503a2d1" + +[[package]] +name = "trust-dns-client" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6d9ba1c6079f6f9b4664e482db1700bd53d2ee77b1c9752c1d7a66c0c8bda99" +dependencies = [ + "cfg-if", + "data-encoding", + "futures-channel", + "futures-util", + "lazy_static", + "log", + "radix_trie", + "rand 0.8.5", + "thiserror", + "time", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "trust-dns-proto" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "log", + "rand 0.8.5", + "serde", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "parking_lot 0.12.1", + "resolv-conf", + "serde", + "smallvec", + "thiserror", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "trust-dns-server" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a395a2e0fd8aac9b4613767a5b4ba4b2040de1b767fa03ace8c9d6f351d60b2d" +dependencies = [ + "async-trait", + "bytes", + "cfg-if", + "enum-as-inner", + "env_logger 0.9.3", + "futures-executor", + "futures-util", + "log", + "serde", + "thiserror", + "time", + "tokio", + "toml 0.5.11", + "trust-dns-client", + "trust-dns-proto", + "trust-dns-resolver", +] + [[package]] name = "try-lock" version = "0.2.4" @@ -3523,12 +8966,79 @@ dependencies = [ "termcolor", ] +[[package]] +name = "tun" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc25e23adc6cac7dd895ce2780f255902290fc39b00e1ae3c33e89f3d20fa66" +dependencies = [ + "byteorder", + "bytes", + "futures-core", + "ioctl-sys", + "libc", + "thiserror", + "tokio", + "tokio-util 0.6.10", +] + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "native-tls", + "rand 0.8.5", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "tunnel-obfuscation" +version = "0.0.0" +source = "git+https://github.com/mullvad/mullvadvpn-app?tag=2023.2#ccfbaa279d04b4f93dff489880e3fb3ae67025bd" +dependencies = [ + "async-trait", + "err-derive", + "futures", + "tokio", + "udp-over-tcp", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "udp-over-tcp" +version = "0.2.0" +source = "git+https://github.com/mullvad/udp-over-tcp?rev=4d52f93cd9962562cb52d66e36771d5f5c70e25a#4d52f93cd9962562cb52d66e36771d5f5c70e25a" +dependencies = [ + "err-context", + "futures", + "lazy_static", + "log", + "nix 0.23.2", + "tokio", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -3556,6 +9066,50 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array 0.14.7", + "subtle 2.4.1", +] + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle 2.4.1", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.4.1" @@ -3563,7 +9117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", - "idna", + "idna 0.4.0", "percent-encoding", "serde", ] @@ -3574,6 +9128,21 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.10", +] + [[package]] name = "uuid" version = "1.5.0" @@ -3595,6 +9164,23 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vergen" +version = "7.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447f9238a4553957277b3ee09d80babeae0811f1b3baefb093de1c0448437a37" +dependencies = [ + "anyhow", + "cfg-if", + "enum-iterator", + "getset", + "git2", + "rustc_version", + "rustversion", + "thiserror", + "time", +] + [[package]] name = "version-compare" version = "0.0.11" @@ -3743,6 +9329,36 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-utils" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym?rev=e8956603d76fb12be7f70052981dce32367e0405#e8956603d76fb12be7f70052981dce32367e0405" +dependencies = [ + "futures", + "getrandom 0.2.10", + "gloo-net", + "gloo-utils", + "js-sys", + "tungstenite", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmtimer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.12.1", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" version = "0.3.64" @@ -3800,6 +9416,44 @@ dependencies = [ "system-deps 6.1.2", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring 0.16.20", + "untrusted 0.7.1", +] + +[[package]] +name = "webpki" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki 0.21.4", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki 0.22.4", +] + [[package]] name = "webview2-com" version = "0.19.1" @@ -3838,6 +9492,24 @@ dependencies = [ "windows-metadata", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + [[package]] name = "winapi" version = "0.3.9" @@ -3902,7 +9574,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3921,7 +9593,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3940,6 +9612,31 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" +[[package]] +name = "windows-service" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917fdb865e7ff03af9dd86609f8767bc88fefba89e8efd569de8e208af8724b3" +dependencies = [ + "bitflags 1.3.2", + "err-derive", + "widestring", + "windows-sys 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -3955,13 +9652,46 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -3979,6 +9709,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows-tokens" version = "0.39.0" @@ -3997,6 +9742,18 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + [[package]] name = "windows_aarch64_msvc" version = "0.37.0" @@ -4021,6 +9778,18 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + [[package]] name = "windows_i686_gnu" version = "0.37.0" @@ -4045,6 +9814,18 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + [[package]] name = "windows_i686_msvc" version = "0.37.0" @@ -4069,6 +9850,18 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + [[package]] name = "windows_x86_64_gnu" version = "0.37.0" @@ -4093,6 +9886,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -4105,6 +9904,18 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "windows_x86_64_msvc" version = "0.37.0" @@ -4129,6 +9940,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.17" @@ -4138,6 +9955,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi", +] + [[package]] name = "winreg" version = "0.50.0" @@ -4184,7 +10010,7 @@ dependencies = [ "once_cell", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "soup2", "tao", "thiserror", @@ -4196,6 +10022,15 @@ dependencies = [ "windows-implement", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x11" version = "2.21.0" @@ -4217,6 +10052,29 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "x25519-dalek" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +dependencies = [ + "curve25519-dalek 3.2.0", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +dependencies = [ + "curve25519-dalek 4.1.1", + "rand_core 0.6.4", + "serde", + "zeroize", +] + [[package]] name = "xattr" version = "1.0.1" @@ -4226,6 +10084,46 @@ dependencies = [ "libc", ] +[[package]] +name = "zerocopy" +version = "0.7.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d075cf85bbb114e933343e087b92f2146bac0d55b534cbb8188becf0039948e" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86cd5ca076997b97ef09d3ad65efe811fa68c9e874cb636ccb211223a813b0c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "zip" version = "0.6.6" diff --git a/nym-vpn/ui/src-tauri/Cargo.toml b/nym-vpn/ui/src-tauri/Cargo.toml index 0edbe87d18..6054029d0d 100644 --- a/nym-vpn/ui/src-tauri/Cargo.toml +++ b/nym-vpn/ui/src-tauri/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "nymvpn-ui" +name = "nym-vpn-ui" version = "0.0.0" description = "Application UI for Nym VPN desktop clients" authors = ["you"] @@ -24,8 +24,16 @@ ts-rs = { version = "7.0.0", features = ["chrono-impl"] } once_cell = "1.18.0" toml = "0.8.5" time = "0.3.9" +nym-vpn-lib = { path = "../../../../nym-vpn-client/nym-vpn-lib" } +futures = "0.3.15" + +# TODO Ugly workaround to force a working setup for nym-vpn-lib +# We should get rid of this ASAP +shadowsocks = { version = "~1.14.2" } +shadowsocks-service = { version = "~1.14.3" } [features] # this feature is used for production builds or when `devPath` points to the filesystem # DO NOT REMOVE!! custom-protocol = ["tauri/custom-protocol"] + diff --git a/nym-vpn/ui/src-tauri/src/commands/connection.rs b/nym-vpn/ui/src-tauri/src/commands/connection.rs index b642a06352..adeb092e4e 100644 --- a/nym-vpn/ui/src-tauri/src/commands/connection.rs +++ b/nym-vpn/ui/src-tauri/src/commands/connection.rs @@ -1,43 +1,21 @@ -use std::time::Duration; - +use futures::SinkExt; +use nym_vpn_lib::{NymVpnCtrlMessage, NymVpnHandle}; use tauri::{Manager, State}; -use time::OffsetDateTime; -use tokio::time::sleep; -use tracing::{debug, error, instrument, trace}; +use tracing::{debug, error, info, instrument, trace}; use crate::{ error::{CmdError, CmdErrorSource}, states::{ app::{ConnectionState, VpnMode}, - SharedAppData, SharedAppState, + SharedAppConfig, SharedAppData, SharedAppState, + }, + vpn_client::{ + create_vpn_config, spawn_exit_listener, spawn_status_listener, ConnectProgressMsg, + ConnectionEventPayload, ProgressEventPayload, EVENT_CONNECTION_PROGRESS, + EVENT_CONNECTION_STATE, }, }; -const EVENT_CONNECTION_STATE: &str = "connection-state"; -const EVENT_CONNECTION_PROGRESS: &str = "connection-progress"; - -#[derive(Clone, serde::Serialize)] -struct ConnectionEventPayload { - state: ConnectionState, - error: Option, - start_time: Option, // unix timestamp in seconds -} - -impl ConnectionEventPayload { - fn new(state: ConnectionState, error: Option, start_time: Option) -> Self { - Self { - state, - error, - start_time, - } - } -} - -#[derive(Clone, serde::Serialize)] -struct ProgressEventPayload { - message: String, -} - #[instrument(skip_all)] #[tauri::command] pub async fn get_connection_state( @@ -53,74 +31,111 @@ pub async fn get_connection_state( pub async fn connect( app: tauri::AppHandle, state: State<'_, SharedAppState>, + config_store: State<'_, SharedAppConfig>, ) -> Result { debug!("connect"); - let mut app_state = state.lock().await; - let ConnectionState::Disconnected = app_state.state else { - return Err(CmdError::new( - CmdErrorSource::CallerError, - format!("cannot connect from state {:?}", app_state.state), - )); - }; + { + let mut app_state = state.lock().await; + if app_state.state != ConnectionState::Disconnected { + return Err(CmdError::new( + CmdErrorSource::CallerError, + format!("cannot connect from state {:?}", app_state.state), + )); + }; - // switch to "Connecting" state - app_state.state = ConnectionState::Connecting; - // unlock the mutex - drop(app_state); + // switch to "Connecting" state + trace!("update connection state [Connecting]"); + app_state.state = ConnectionState::Connecting; + } + + debug!("sending event [{}]: Connecting", EVENT_CONNECTION_STATE); app.emit_all( EVENT_CONNECTION_STATE, ConnectionEventPayload::new(ConnectionState::Connecting, None, None), ) .ok(); - // TODO fake some delay to establish connection - let app_state_cloned = state.inner().clone(); - let task = tokio::spawn(async move { - app.emit_all( - EVENT_CONNECTION_PROGRESS, - ProgressEventPayload { - message: "Connecting to the network…".to_string(), - }, + trace!( + "sending event [{}]: Initializing", + EVENT_CONNECTION_PROGRESS + ); + app.emit_all( + EVENT_CONNECTION_PROGRESS, + ProgressEventPayload { + key: ConnectProgressMsg::Initializing, + }, + ) + .ok(); + + let app_config = config_store.lock().await.read().await.map_err(|e| { + CmdError::new( + CmdErrorSource::InternalError, + format!("failed to read app config: {}", e), ) - .ok(); - sleep(Duration::from_millis(300)).await; - app.emit_all( - EVENT_CONNECTION_PROGRESS, - ProgressEventPayload { - message: "Fetching nodes and gateways…".to_string(), - }, - ) - .ok(); - sleep(Duration::from_millis(400)).await; - app.emit_all( - EVENT_CONNECTION_PROGRESS, - ProgressEventPayload { - message: "Done".to_string(), - }, - ) - .ok(); - sleep(Duration::from_millis(200)).await; - trace!("connected"); - let now = OffsetDateTime::now_utc(); - let mut state = app_state_cloned.lock().await; - state.state = ConnectionState::Connected; - state.connection_start_time = Some(now); - debug!("sending event [{}]: connected", EVENT_CONNECTION_STATE); + })?; + let mut vpn_config = create_vpn_config(&app_config); + { + let app_state = state.lock().await; + if let VpnMode::TwoHop = app_state.vpn_mode { + info!("2-hop mode enabled"); + vpn_config.enable_two_hop = true; + } else { + info!("5-hop mode enabled"); + } + } + // vpn_config.disable_routing = true; + + // spawn the VPN client and start a new connection + let NymVpnHandle { + vpn_ctrl_tx, + vpn_status_rx, + vpn_exit_rx, + } = nym_vpn_lib::spawn_nym_vpn(vpn_config).map_err(|e| { + let err_message = format!("fail to initialize Nym VPN client: {}", e); + error!(err_message); + debug!("sending event [{}]: Disconnected", EVENT_CONNECTION_STATE); app.emit_all( EVENT_CONNECTION_STATE, ConnectionEventPayload::new( - ConnectionState::Connected, + ConnectionState::Disconnected, + Some(err_message.clone()), None, - Some(now.unix_timestamp()), ), ) .ok(); - }); + CmdError::new(CmdErrorSource::InternalError, err_message) + })?; + info!("nym vpn client spawned"); + trace!("sending event [{}]: InitDone", EVENT_CONNECTION_PROGRESS); + app.emit_all( + EVENT_CONNECTION_PROGRESS, + ProgressEventPayload { + key: ConnectProgressMsg::InitDone, + }, + ) + .ok(); - let _ = task.await; + // Start exit message listener + // This will listen for the (single) exit message from the VPN client and update the UI accordingly + debug!("starting exit listener"); + spawn_exit_listener(app.clone(), state.inner().clone(), vpn_exit_rx) + .await + .ok(); - let app_state = state.lock().await; - Ok(app_state.state) + // Start the VPN status listener + // This will listen for status messages from the VPN client and update the UI accordingly + debug!("starting status listener"); + spawn_status_listener(app, state.inner().clone(), vpn_status_rx) + .await + .ok(); + + // Store the vpn control tx in the app state, which will be used to send control messages to + // the running background VPN task, such as to disconnect. + trace!("added vpn_ctrl_tx to app state"); + let mut state = state.lock().await; + state.vpn_ctrl_tx = Some(vpn_ctrl_tx); + + Ok(state.state) } #[instrument(skip_all)] @@ -131,7 +146,7 @@ pub async fn disconnect( ) -> Result { debug!("disconnect"); let mut app_state = state.lock().await; - let ConnectionState::Connected = app_state.state else { + if app_state.state != ConnectionState::Connected { return Err(CmdError::new( CmdErrorSource::CallerError, format!("cannot disconnect from state {:?}", app_state.state), @@ -139,36 +154,55 @@ pub async fn disconnect( }; // switch to "Disconnecting" state + trace!("update connection state [Disconnecting]"); app_state.state = ConnectionState::Disconnecting; - // unlock the mutex - drop(app_state); + + debug!("sending event [{}]: Disconnecting", EVENT_CONNECTION_STATE); app.emit_all( EVENT_CONNECTION_STATE, ConnectionEventPayload::new(ConnectionState::Disconnecting, None, None), ) .ok(); - // TODO fake some delay to confirm disconnection - let app_state_cloned = state.inner().clone(); - let task = tokio::spawn(async move { - sleep(Duration::from_secs(1)).await; - trace!("disconnected"); - - let mut state = app_state_cloned.lock().await; - state.state = ConnectionState::Disconnected; - state.connection_start_time = None; - - debug!("sending event [{}]: disconnected", EVENT_CONNECTION_STATE); + let Some(ref mut vpn_tx) = app_state.vpn_ctrl_tx else { + trace!("update connection state [Disconnected]"); + app_state.state = ConnectionState::Disconnected; + app_state.connection_start_time = None; + debug!("sending event [{}]: Disconnected", EVENT_CONNECTION_STATE); app.emit_all( EVENT_CONNECTION_STATE, - ConnectionEventPayload::new(ConnectionState::Disconnected, None, None), + ConnectionEventPayload::new( + ConnectionState::Disconnected, + Some("vpn handle has not been initialized".to_string()), + None, + ), ) .ok(); - }); + return Err(CmdError::new( + CmdErrorSource::InternalError, + "vpn handle has not been initialized".to_string(), + )); + }; - let _ = task.await; + // send Stop message to the VPN client + debug!("sending Stop message to VPN client"); + vpn_tx.send(NymVpnCtrlMessage::Stop).await.map_err(|e| { + let err_message = format!("failed to send Stop message to VPN client: {}", e); + error!(err_message); + debug!("sending event [{}]: Disconnected", EVENT_CONNECTION_STATE); + app.emit_all( + EVENT_CONNECTION_STATE, + ConnectionEventPayload::new( + ConnectionState::Disconnected, + Some(err_message.clone()), + None, + ), + ) + .ok(); + CmdError::new(CmdErrorSource::InternalError, err_message) + })?; + debug!("Stop message sent"); - let app_state = state.lock().await; Ok(app_state.state) } diff --git a/nym-vpn/ui/src-tauri/src/fs/config.rs b/nym-vpn/ui/src-tauri/src/fs/config.rs index 3755d701a8..72005fe58f 100644 --- a/nym-vpn/ui/src-tauri/src/fs/config.rs +++ b/nym-vpn/ui/src-tauri/src/fs/config.rs @@ -1,6 +1,13 @@ +use std::path::PathBuf; + use serde::{Deserialize, Serialize}; #[derive(Default, Serialize, Deserialize, Debug, Clone)] pub struct AppConfig { - // TODO + /// Path pointing to an env configuration file describing the network + pub env_config_file: Option, + /// Mixnet public ID of the entry gateway + pub entry_gateway: String, + /// Mixnet recipient address + pub exit_router: String, } diff --git a/nym-vpn/ui/src-tauri/src/main.rs b/nym-vpn/ui/src-tauri/src/main.rs index 67dc63f384..51949f4884 100644 --- a/nym-vpn/ui/src-tauri/src/main.rs +++ b/nym-vpn/ui/src-tauri/src/main.rs @@ -1,44 +1,89 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -use std::sync::Arc; +use std::{env, sync::Arc}; -use anyhow::anyhow; -use anyhow::Result; +use anyhow::{anyhow, Context, Result}; use tauri::api::path::{config_dir, data_dir}; -use tokio::sync::Mutex; -use tracing::info; +use tokio::{fs::try_exists, sync::Mutex}; +use tracing::{debug, error, info}; + +use commands::*; +use states::app::AppState; + +use nym_vpn_lib::nym_config; + +use crate::fs::{config::AppConfig, data::AppData, storage::AppStorage}; mod commands; mod error; mod fs; mod states; +mod vpn_client; -use commands::*; -use states::app::AppState; - -use crate::fs::config::AppConfig; -use crate::fs::data::AppData; -use crate::fs::storage::AppStorage; - -const APP_DIR: &str = "nymvpn"; +const APP_DIR: &str = "nym-vpn"; const APP_DATA_FILE: &str = "app-data.toml"; const APP_CONFIG_FILE: &str = "config.toml"; -fn main() -> Result<()> { +pub fn setup_logging() { + let filter = tracing_subscriber::EnvFilter::builder() + .with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into()) + .from_env() + .unwrap() + .add_directive("hyper::proto=info".parse().unwrap()) + .add_directive("netlink_proto=info".parse().unwrap()); + + tracing_subscriber::fmt() + .with_env_filter(filter) + .compact() + .init(); +} + +#[tokio::main] +async fn main() -> Result<()> { dotenvy::dotenv().ok(); + setup_logging(); - // uses RUST_LOG value for logging level - // eg. RUST_LOG=tauri=debug,nymvpn_ui=trace - tracing_subscriber::fmt::init(); + let app_data_store = { + let mut app_data_path = + data_dir().ok_or(anyhow!("Failed to retrieve data directory path"))?; + app_data_path.push(APP_DIR); + AppStorage::::new(app_data_path, APP_DATA_FILE, None) + }; + debug!("app_data_store: {}", app_data_store.full_path.display()); - let mut app_data_path = data_dir().ok_or(anyhow!("Failed to retrieve data directory"))?; - app_data_path.push(APP_DIR); - let app_data_store = AppStorage::::new(app_data_path, APP_DATA_FILE, None); + let app_config_store = { + let mut app_config_path = + config_dir().ok_or(anyhow!("Failed to retrieve config directory path"))?; + app_config_path.push(APP_DIR); + AppStorage::::new(app_config_path, APP_CONFIG_FILE, None) + }; + debug!( + "app_config_store: {}", + &app_config_store.full_path.display() + ); - let mut app_config_path = config_dir().ok_or(anyhow!("Failed to retrieve config directory"))?; - app_config_path.push(APP_DIR); - let app_config_store = AppStorage::::new(app_config_path, APP_CONFIG_FILE, None); + let app_config = app_config_store.read().await?; + debug!("app_config: {app_config:?}"); + + // check for the existence of the env_config_file if provided + if let Some(env_config_file) = &app_config.env_config_file { + debug!("provided env_config_file: {}", env_config_file.display()); + if !(try_exists(env_config_file) + .await + .context("an error happened while trying to read env_config_file `{}`")?) + { + let err_message = format!( + "app config, env_config_file `{}`: file not found", + env_config_file.display() + ); + error!(err_message); + return Err(anyhow!(err_message)); + } + } + + // Read the env variables in the provided file and export them all to the local environment. + nym_config::defaults::setup_env(app_config.env_config_file); info!("Starting tauri app"); @@ -64,5 +109,6 @@ fn main() -> Result<()> { ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); + Ok(()) } diff --git a/nym-vpn/ui/src-tauri/src/states/app.rs b/nym-vpn/ui/src-tauri/src/states/app.rs index b0c09ba8c7..1ef6f1a540 100644 --- a/nym-vpn/ui/src-tauri/src/states/app.rs +++ b/nym-vpn/ui/src-tauri/src/states/app.rs @@ -1,3 +1,5 @@ +use futures::channel::mpsc::UnboundedSender; +use nym_vpn_lib::NymVpnCtrlMessage; use serde::{Deserialize, Serialize}; use time::OffsetDateTime; use ts_rs::TS; @@ -9,7 +11,7 @@ pub struct NodeConfig { pub country: Country, } -#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, TS)] +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, TS)] #[ts(export)] pub enum ConnectionState { Connected, @@ -20,7 +22,7 @@ pub enum ConnectionState { Unknown, } -#[derive(Default, Debug, Serialize, Deserialize, TS, Clone)] +#[derive(Default, Debug, Serialize, Deserialize, TS, Clone, PartialEq, Eq)] #[ts(export)] pub enum VpnMode { Mixnet, @@ -46,6 +48,7 @@ pub struct AppState { pub exit_node_location: Option, pub tunnel: Option, pub connection_start_time: Option, + pub vpn_ctrl_tx: Option>, } #[derive(Default, Serialize, Deserialize, Debug, Clone, TS)] diff --git a/nym-vpn/ui/src-tauri/src/states/mod.rs b/nym-vpn/ui/src-tauri/src/states/mod.rs index b02b90be7b..66deba9a51 100644 --- a/nym-vpn/ui/src-tauri/src/states/mod.rs +++ b/nym-vpn/ui/src-tauri/src/states/mod.rs @@ -1,8 +1,6 @@ -use std::sync::Arc; - -use tokio::sync::Mutex; - use crate::fs::{config::AppConfig, data::AppData, storage::AppStorage}; +use std::sync::Arc; +use tokio::sync::Mutex; pub mod app; diff --git a/nym-vpn/ui/src-tauri/src/vpn_client.rs b/nym-vpn/ui/src-tauri/src/vpn_client.rs new file mode 100644 index 0000000000..ea2eb9073f --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/vpn_client.rs @@ -0,0 +1,173 @@ +use crate::fs::config::AppConfig; +use crate::states::{app::ConnectionState, SharedAppState}; +use anyhow::Result; +use futures::channel::oneshot::Receiver as OneshotReceiver; +use futures::StreamExt; +use nym_vpn_lib::gateway_client::Config as GatewayClientConfig; +use nym_vpn_lib::nym_config::OptionalSet; +use nym_vpn_lib::{NymVpn, NymVpnExitError, NymVpnExitStatusMessage, StatusReceiver}; +use tauri::Manager; +use time::OffsetDateTime; +use tracing::{debug, error, info, instrument, trace}; + +pub const EVENT_CONNECTION_STATE: &str = "connection-state"; +pub const EVENT_CONNECTION_PROGRESS: &str = "connection-progress"; + +#[derive(Clone, serde::Serialize)] +pub enum ConnectProgressMsg { + Initializing, + InitDone, +} + +#[derive(Clone, serde::Serialize)] +pub struct ProgressEventPayload { + pub key: ConnectProgressMsg, +} + +#[derive(Clone, serde::Serialize)] +pub struct ConnectionEventPayload { + state: ConnectionState, + error: Option, + start_time: Option, // unix timestamp in seconds +} + +impl ConnectionEventPayload { + pub fn new(state: ConnectionState, error: Option, start_time: Option) -> Self { + Self { + state, + error, + start_time, + } + } +} + +fn handle_vpn_exit_error(e: Box) -> String { + match e.downcast::>() { + Ok(e) => { + // TODO The double boxing here is unexpected, we should look into that + match **e { + NymVpnExitError::Generic { reason } => reason.to_string(), + NymVpnExitError::FailedToResetFirewallPolicy { reason } => reason.to_string(), + NymVpnExitError::FailedToResetDnsMonitor { reason } => reason.to_string(), + } + } + Err(e) => format!("unknown error: {e}"), + } +} + +#[instrument(skip_all)] +pub async fn spawn_exit_listener( + app: tauri::AppHandle, + app_state: SharedAppState, + exit_rx: OneshotReceiver, +) -> Result<()> { + tokio::spawn(async move { + match exit_rx.await { + Ok(res) => { + debug!("received vpn exit message: {res:?}"); + match res { + NymVpnExitStatusMessage::Stopped => { + info!("vpn connection stopped"); + debug!( + "vpn stopped, sending event [{}]: disconnected", + EVENT_CONNECTION_STATE + ); + app.emit_all( + EVENT_CONNECTION_STATE, + ConnectionEventPayload::new(ConnectionState::Disconnected, None, None), + ) + .ok(); + } + NymVpnExitStatusMessage::Failed(e) => { + let error = handle_vpn_exit_error(e); + debug!( + "vpn failed, sending event [{}]: disconnected", + EVENT_CONNECTION_STATE + ); + app.emit_all( + EVENT_CONNECTION_STATE, + ConnectionEventPayload::new( + ConnectionState::Disconnected, + Some(error), + None, + ), + ) + .ok(); + } + } + } + Err(e) => { + error!("vpn_exit_rx failed to receive exit message: {}", e); + app.emit_all( + EVENT_CONNECTION_STATE, + ConnectionEventPayload::new( + ConnectionState::Disconnected, + Some("exit channel with vpn client has been closed".to_string()), + None, + ), + ) + .ok(); + } + } + // update the connection state + let mut state = app_state.lock().await; + state.state = ConnectionState::Disconnected; + state.connection_start_time = None; + info!("vpn exit listener has exited"); + }); + Ok(()) +} + +#[instrument(skip_all)] +pub async fn spawn_status_listener( + app: tauri::AppHandle, + app_state: SharedAppState, + mut status_rx: StatusReceiver, +) -> Result<()> { + tokio::spawn(async move { + while let Some(msg) = status_rx.next().await { + info!("received vpn status message: {msg:?}"); + if "Ready" == msg.to_string().as_str() { + info!("vpn connection has been established"); + let now = OffsetDateTime::now_utc(); + { + let mut state = app_state.lock().await; + trace!("update connection state [Connected]"); + state.state = ConnectionState::Connected; + state.connection_start_time = Some(now); + } + debug!("sending event [{}]: Connected", EVENT_CONNECTION_STATE); + app.emit_all( + EVENT_CONNECTION_STATE, + ConnectionEventPayload::new( + ConnectionState::Connected, + None, + Some(now.unix_timestamp()), + ), + ) + .ok(); + } + } + info!("vpn status listener has exited"); + }); + Ok(()) +} + +fn setup_gateway_client_config(private_key: Option<&str>) -> GatewayClientConfig { + let mut config = GatewayClientConfig::default() + // Read in the environment variable NYM_API if it exists + .with_optional_env(GatewayClientConfig::with_custom_api_url, None, "NYM_API"); + info!("Using nym-api: {}", config.api_url()); + + if let Some(key) = private_key { + config = config.with_local_private_key(key.into()); + } + config +} + +#[instrument(skip_all)] +pub fn create_vpn_config(app_config: &AppConfig) -> NymVpn { + let mut nym_vpn = NymVpn::new(&app_config.entry_gateway, &app_config.exit_router); + nym_vpn.gateway_config = setup_gateway_client_config(None); + nym_vpn +} diff --git a/nym-vpn/ui/src-tauri/tauri.conf.json b/nym-vpn/ui/src-tauri/tauri.conf.json index 7c565fd47d..532d960be3 100644 --- a/nym-vpn/ui/src-tauri/tauri.conf.json +++ b/nym-vpn/ui/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ "withGlobalTauri": false }, "package": { - "productName": "nymvpn-ui", + "productName": "nym-vpn-ui", "version": "0.0.0" }, "tauri": { diff --git a/nym-vpn/ui/src/i18n/config.ts b/nym-vpn/ui/src/i18n/config.ts index 2acb27fb6c..ffdb86b44c 100644 --- a/nym-vpn/ui/src/i18n/config.ts +++ b/nym-vpn/ui/src/i18n/config.ts @@ -4,6 +4,7 @@ import common from './en/common.json'; import home from './en/home.json'; import settings from './en/settings.json'; import nodeLocation from './en/node-location.json'; +import backendMessages from './en/backend-messages.json'; const defaultNS = 'common'; @@ -16,9 +17,10 @@ i18n.use(initReactI18next).init({ home, settings, nodeLocation, + backendMessages, }, }, - ns: ['common', 'home', 'settings', 'nodeLocation'], + ns: ['common', 'home', 'settings', 'nodeLocation', 'backendMessages'], defaultNS, interpolation: { diff --git a/nym-vpn/ui/src/i18n/en/backend-messages.json b/nym-vpn/ui/src/i18n/en/backend-messages.json new file mode 100644 index 0000000000..95dd6222a5 --- /dev/null +++ b/nym-vpn/ui/src/i18n/en/backend-messages.json @@ -0,0 +1,6 @@ +{ + "connection-progress": { + "Initializing": "Initializing Nym VPN client…", + "InitDone": "Nym VPN client initialized" + } +} diff --git a/nym-vpn/ui/src/i18n/en/home.json b/nym-vpn/ui/src/i18n/en/home.json index 4ef4caf841..2403849864 100644 --- a/nym-vpn/ui/src/i18n/en/home.json +++ b/nym-vpn/ui/src/i18n/en/home.json @@ -19,7 +19,7 @@ "desc": "Best for payments, emails, messages" }, "twohop-mode": { - "title": "2-hop WireGuard", + "title": "2-hop", "desc": "Best for browsing, streaming, sharing" }, "last-node-select": { diff --git a/nym-vpn/ui/src/pages/home/ConnectionStatus.tsx b/nym-vpn/ui/src/pages/home/ConnectionStatus.tsx index 0da9232f4a..ad9a4acbcb 100644 --- a/nym-vpn/ui/src/pages/home/ConnectionStatus.tsx +++ b/nym-vpn/ui/src/pages/home/ConnectionStatus.tsx @@ -69,7 +69,14 @@ function ConnectionStatus() {
{state.loading && state.progressMessages.length > 0 && (

- {state.progressMessages[state.progressMessages.length - 1]} + {t( + `connection-progress.${ + state.progressMessages[state.progressMessages.length - 1] + }`, + { + ns: 'backendMessages', + }, + )}

)} {state.state === 'Connected' && } diff --git a/nym-vpn/ui/src/pages/home/Home.tsx b/nym-vpn/ui/src/pages/home/Home.tsx index 598d229479..843bf5b5a1 100644 --- a/nym-vpn/ui/src/pages/home/Home.tsx +++ b/nym-vpn/ui/src/pages/home/Home.tsx @@ -1,36 +1,49 @@ +import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { invoke } from '@tauri-apps/api'; import clsx from 'clsx'; import { Button } from '@mui/base'; import { useNavigate } from 'react-router-dom'; import { useMainDispatch, useMainState } from '../../contexts'; -import { ConnectionState, StateDispatch } from '../../types'; +import { StateDispatch } from '../../types'; import { QuickConnectCountry, routes } from '../../constants'; import NetworkModeSelect from './NetworkModeSelect'; import ConnectionStatus from './ConnectionStatus'; import HopSelect from './HopSelect'; function Home() { - const state = useMainState(); + const { state, loading, exitNodeLocation } = useMainState(); const dispatch = useMainDispatch() as StateDispatch; const navigate = useNavigate(); const { t } = useTranslation('home'); const handleClick = async () => { - if (state.state === 'Connected') { - dispatch({ type: 'disconnect' }); - invoke('disconnect').then((result) => { - console.log(result); - }); - } else if (state.state === 'Disconnected') { + dispatch({ type: 'disconnect' }); + if (state === 'Connected') { + invoke('disconnect') + .then((result) => { + console.log('disconnect result'); + console.log(result); + }) + .catch((e) => { + console.log(e); + dispatch({ type: 'set-error', error: e }); + }); + } else if (state === 'Disconnected') { dispatch({ type: 'connect' }); - invoke('connect').then((result) => { - console.log(result); - }); + invoke('connect') + .then((result) => { + console.log('connect result'); + console.log(result); + }) + .catch((e) => { + console.log(e); + dispatch({ type: 'set-error', error: e }); + }); } }; - const getButtonText = (state: ConnectionState) => { + const getButtonText = useCallback(() => { switch (state) { case 'Connected': return t('disconnect'); @@ -51,7 +64,7 @@ function Home() { case 'Unknown': return t('status.unknown'); } - }; + }, [state, t]); return (
@@ -61,7 +74,7 @@ function Home() {
navigate(routes.exitNodeLocation)} nodeHop="exit" /> @@ -69,15 +82,15 @@ function Home() {
diff --git a/nym-vpn/ui/src/state/main.ts b/nym-vpn/ui/src/state/main.ts index 5e74b2aebd..c7e498966c 100644 --- a/nym-vpn/ui/src/state/main.ts +++ b/nym-vpn/ui/src/state/main.ts @@ -1,6 +1,7 @@ import dayjs from 'dayjs'; import { AppState, + ConnectProgressMsg, ConnectionState, Country, NodeHop, @@ -14,7 +15,7 @@ export type StateAction = | { type: 'set-vpn-mode'; mode: VpnMode } | { type: 'set-error'; error: string } | { type: 'reset-error' } - | { type: 'new-progress-message'; message: string } + | { type: 'new-progress-message'; message: ConnectProgressMsg } | { type: 'connect' } | { type: 'disconnect' } | { type: 'set-connected'; startTime: number } @@ -27,7 +28,7 @@ export type StateAction = export const initialState: AppState = { state: 'Disconnected', loading: false, - vpnMode: 'TwoHop', + vpnMode: 'Mixnet', tunnel: { name: 'nym', id: 'nym' }, uiTheme: 'Light', progressMessages: [], @@ -57,6 +58,9 @@ export function reducer(state: AppState, action: StateAction): AppState { return { ...state, ...action.partialState }; } case 'change-connection-state': { + console.log( + `__REDUCER [change-connection-state] changing connection state to ${action.state}`, + ); if (action.state === state.state) { return state; } @@ -68,12 +72,18 @@ export function reducer(state: AppState, action: StateAction): AppState { }; } case 'connect': { + console.log( + `__REDUCER [connect] changing connection state to Connecting`, + ); return { ...state, state: 'Connecting', loading: true }; } case 'disconnect': { return { ...state, state: 'Disconnecting', loading: true }; } case 'set-connected': { + console.log( + `__REDUCER [set-connected] changing connection state to Connected`, + ); return { ...state, state: 'Connected', diff --git a/nym-vpn/ui/src/state/useTauriEvents.ts b/nym-vpn/ui/src/state/useTauriEvents.ts index 794df421a9..9c22566c1b 100644 --- a/nym-vpn/ui/src/state/useTauriEvents.ts +++ b/nym-vpn/ui/src/state/useTauriEvents.ts @@ -13,6 +13,7 @@ function handleError(dispatch: StateDispatch, error?: string | null) { dispatch({ type: 'reset-error' }); return; } + console.warn(`received backend error: ${error}`); dispatch({ type: 'set-error', error }); } @@ -53,11 +54,11 @@ export function useTauriEvents(dispatch: StateDispatch) { const registerProgressListener = useCallback(() => { return listen(ProgressEvent, (event) => { console.log( - `received event ${event.event}, message: ${event.payload.message}`, + `received event ${event.event}, message: ${event.payload.key}`, ); dispatch({ type: 'new-progress-message', - message: event.payload.message, + message: event.payload.key, }); }); }, [dispatch]); diff --git a/nym-vpn/ui/src/styles.css b/nym-vpn/ui/src/styles.css index aed8571c63..431acd4eae 100644 --- a/nym-vpn/ui/src/styles.css +++ b/nym-vpn/ui/src/styles.css @@ -6,6 +6,7 @@ @font-face { font-family: 'Material Symbols Outlined'; font-style: normal; + font-wight: 400; src: url(assets/fonts/MaterialSymbolsOutlined.woff2) format('woff2'); } } diff --git a/nym-vpn/ui/src/types/app-state.ts b/nym-vpn/ui/src/types/app-state.ts index 4caea2a137..38d0017c5c 100644 --- a/nym-vpn/ui/src/types/app-state.ts +++ b/nym-vpn/ui/src/types/app-state.ts @@ -21,7 +21,7 @@ export type AppState = { state: ConnectionState; loading: boolean; error?: string | null; - progressMessages: string[]; + progressMessages: ConnectProgressMsg[]; sessionStartDate?: Dayjs | null; vpnMode: VpnMode; tunnel: TunnelConfig; @@ -36,8 +36,10 @@ export type ConnectionEventPayload = { start_time?: number | null; // unix timestamp in seconds }; +export type ConnectProgressMsg = 'Initializing' | 'InitDone'; + export type ProgressEventPayload = { - message: string; + key: ConnectProgressMsg; }; export type StateDispatch = Dispatch; diff --git a/nym-vpn/ui/tailwind.config.ts b/nym-vpn/ui/tailwind.config.ts index 7a1a584e34..1c07f2b97c 100644 --- a/nym-vpn/ui/tailwind.config.ts +++ b/nym-vpn/ui/tailwind.config.ts @@ -76,7 +76,7 @@ export default { icon: [ 'Material Symbols Outlined', { - fontVariationSettings: '"opsz" 24; "wght" 400;', + fontVariationSettings: '"opsz" 24;', }, ], }, From e09b33baff1646adbeef47d154ad4f5935bb46a9 Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Fri, 15 Dec 2023 14:17:12 +0100 Subject: [PATCH 4/7] fix(vpn-desktop): typo (#4252) --- nym-vpn/ui/src/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nym-vpn/ui/src/styles.css b/nym-vpn/ui/src/styles.css index 431acd4eae..0bb0a1a72d 100644 --- a/nym-vpn/ui/src/styles.css +++ b/nym-vpn/ui/src/styles.css @@ -6,7 +6,7 @@ @font-face { font-family: 'Material Symbols Outlined'; font-style: normal; - font-wight: 400; + font-weight: 400; src: url(assets/fonts/MaterialSymbolsOutlined.woff2) format('woff2'); } } From 404b043591111ab59c4bf7d8dc1c8b76730e9a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Sat, 16 Dec 2023 22:16:29 +0100 Subject: [PATCH 5/7] Add ci-cargo-deny (#4254) --- .github/workflows/ci-cargo-deny.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/ci-cargo-deny.yml diff --git a/.github/workflows/ci-cargo-deny.yml b/.github/workflows/ci-cargo-deny.yml new file mode 100644 index 0000000000..a9a84fc271 --- /dev/null +++ b/.github/workflows/ci-cargo-deny.yml @@ -0,0 +1,21 @@ +name: ci-cargo-deny +on: [workflow_dispatch] +jobs: + cargo-deny: + runs-on: ubuntu-22.04 + strategy: + matrix: + checks: + # - advisories + - licenses + - bans sources + + continue-on-error: ${{ matrix.checks == 'licenses' }} + + steps: + - uses: actions/checkout@v3 + - uses: EmbarkStudios/cargo-deny-action@v1 + with: + log-level: warn + command: check ${{ matrix.checks }} + argument: --all-features From bac0f24cf748bb5464e7a209cd4c71469df4bc68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 18 Dec 2023 11:51:34 +0000 Subject: [PATCH 6/7] Feature/issued credentials api (#4207) * split up coconut module a bit * internal tool for watching dkg state and updating group contract * debug dkg state * display past dealer data * improved EpochState Display impl * display contract errors + advance epoch state * check admin * panic handler * simplify app.rs * split action enum * added new tab with logger information * new dealing display * sort by index * [fixedup] wip: updating epoch issued credentials - OG 92ade10384a6d7b6c6c222d2e29d69d3b3446a4c * storing and signing partial blinded credentials * starting cleanup * fixed coconut tests + clippy * fixed nym-api tests * removed dkg-manager tool it was moved to a different branch * implemented remaining endpoints * unit tests + bug fixes * clippy * added persistent identity keys to nym-api theyre not yet announced - this will be in another PR * cargo fmt * clippy * fixed loading of old configs without storage paths set * added additional logs for blind-sign endpoint * fixed up licenses * lowercasing error variants * changed 'issued_credentials' to a post * added minimal client support * fixed the unit test --- .gitignore | 1 + Cargo.lock | 123 ++-- Cargo.toml | 12 +- common/bandwidth-controller/Cargo.toml | 1 + .../bandwidth-controller/src/acquire/mod.rs | 27 +- .../bandwidth-controller/src/acquire/state.rs | 29 +- common/bandwidth-controller/src/lib.rs | 15 +- common/client-libs/mixnet-client/Cargo.toml | 4 +- .../validator-client/src/nym_api/mod.rs | 61 +- .../validator-client/src/nym_api/routes.rs | 3 + .../coconut_bandwidth_signing_client.rs | 2 +- .../contract_traits/multisig_query_client.rs | 24 +- .../validator-client/src/nyxd/helpers.rs | 13 + .../validator-client/src/nyxd/mod.rs | 5 + common/coconut-interface/src/lib.rs | 22 +- .../commands/src/coconut/issue_credentials.rs | 4 + .../coconut-bandwidth-contract/src/events.rs | 3 + .../coconut-dkg/src/types.rs | 12 +- common/credentials/Cargo.toml | 5 +- common/credentials/src/coconut/bandwidth.rs | 144 +++-- common/credentials/src/coconut/mod.rs | 1 - common/credentials/src/coconut/params.rs | 15 - common/credentials/src/coconut/utils.rs | 61 +- .../crypto/src/asymmetric/encryption/mod.rs | 11 + common/crypto/src/asymmetric/identity/mod.rs | 26 +- common/dkg/Cargo.toml | 6 +- common/mixnode-common/Cargo.toml | 2 +- common/nymcoconut/Cargo.toml | 9 +- common/nymcoconut/benches/benchmarks.rs | 26 +- common/nymcoconut/src/elgamal.rs | 47 +- common/nymcoconut/src/error.rs | 16 + common/nymcoconut/src/lib.rs | 21 +- common/nymcoconut/src/proofs/mod.rs | 64 +- common/nymcoconut/src/scheme/aggregation.rs | 50 +- common/nymcoconut/src/scheme/double_use.rs | 2 + common/nymcoconut/src/scheme/issuance.rs | 84 +-- common/nymcoconut/src/scheme/keygen.rs | 43 +- common/nymcoconut/src/scheme/mod.rs | 240 ++++---- common/nymcoconut/src/scheme/verification.rs | 44 +- common/nymcoconut/src/tests/e2e.rs | 9 +- common/nymcoconut/src/tests/helpers.rs | 29 +- common/nymcoconut/src/traits.rs | 69 ++- common/nymcoconut/src/utils.rs | 3 + common/nymsphinx/framing/Cargo.toml | 2 +- common/socks5/proxy-helpers/Cargo.toml | 4 +- ephemera/Cargo.toml | 2 +- gateway/Cargo.toml | 2 +- mixnode/Cargo.toml | 4 +- nym-api/Cargo.toml | 3 +- ...0231127120000_partial_credentials_info.sql | 28 + nym-api/nym-api-requests/Cargo.toml | 3 + nym-api/nym-api-requests/src/coconut.rs | 158 ----- .../nym-api-requests/src/coconut/helpers.rs | 33 ++ nym-api/nym-api-requests/src/coconut/mod.rs | 10 + .../nym-api-requests/src/coconut/models.rs | 233 ++++++++ nym-api/src/coconut/api_routes/helpers.rs | 28 + nym-api/src/coconut/api_routes/mod.rs | 211 +++++++ nym-api/src/coconut/client.rs | 4 +- nym-api/src/coconut/comm.rs | 74 ++- nym-api/src/coconut/deposit.rs | 389 +++++-------- nym-api/src/coconut/dkg/dealing.rs | 12 +- nym-api/src/coconut/dkg/state.rs | 16 +- nym-api/src/coconut/dkg/verification_key.rs | 38 +- nym-api/src/coconut/error.rs | 72 ++- nym-api/src/coconut/helpers.rs | 18 + nym-api/src/coconut/keypair.rs | 4 + nym-api/src/coconut/mod.rs | 311 ++-------- nym-api/src/coconut/state.rs | 151 +++++ nym-api/src/coconut/storage/manager.rs | 381 ++++++++++++ nym-api/src/coconut/storage/mod.rs | 166 ++++++ nym-api/src/coconut/storage/models.rs | 119 ++++ .../src/coconut/tests/issued_credentials.rs | 276 +++++++++ .../src/coconut/{tests.rs => tests/mod.rs} | 549 +++++++++++------- nym-api/src/main.rs | 2 + nym-api/src/support/cli/mod.rs | 11 +- nym-api/src/support/config/mod.rs | 23 +- .../src/support/config/old_config_v1_1_21.rs | 1 + .../src/support/config/old_config_v1_1_27.rs | 1 + nym-api/src/support/config/persistence.rs | 70 +++ nym-api/src/support/config/template.rs | 6 + nym-api/src/support/http/mod.rs | 7 +- nym-api/src/support/nyxd/mod.rs | 12 +- nym-api/src/support/storage/manager.rs | 59 +- nym-api/src/support/storage/mod.rs | 21 - nym-connect/desktop/Cargo.lock | 134 ++--- sdk/rust/nym-sdk/Cargo.toml | 2 +- 86 files changed, 3360 insertions(+), 1678 deletions(-) create mode 100644 common/client-libs/validator-client/src/nyxd/helpers.rs delete mode 100644 common/credentials/src/coconut/params.rs create mode 100644 nym-api/migrations/20231127120000_partial_credentials_info.sql delete mode 100644 nym-api/nym-api-requests/src/coconut.rs create mode 100644 nym-api/nym-api-requests/src/coconut/helpers.rs create mode 100644 nym-api/nym-api-requests/src/coconut/mod.rs create mode 100644 nym-api/nym-api-requests/src/coconut/models.rs create mode 100644 nym-api/src/coconut/api_routes/helpers.rs create mode 100644 nym-api/src/coconut/api_routes/mod.rs create mode 100644 nym-api/src/coconut/state.rs create mode 100644 nym-api/src/coconut/storage/manager.rs create mode 100644 nym-api/src/coconut/storage/mod.rs create mode 100644 nym-api/src/coconut/storage/models.rs create mode 100644 nym-api/src/coconut/tests/issued_credentials.rs rename nym-api/src/coconut/{tests.rs => tests/mod.rs} (75%) diff --git a/.gitignore b/.gitignore index 9d4cada8a2..4dfbe52586 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ target .env .env.dev +envs/devnet.env /.vscode/settings.json validator/.vscode sample-configs/validator-config.toml diff --git a/Cargo.lock b/Cargo.lock index 26ecc4a3b9..153ba1b793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -987,27 +987,13 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bls12_381" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397" +version = "0.8.0" +source = "git+https://github.com/jstuczyn/bls12_381?branch=feature/gt-serialization-0.8.0#c4543fde7d02efea6ecfcf22e14476ddb516b483" dependencies = [ "digest 0.9.0", - "ff 0.10.1", - "group 0.10.0", - "pairing 0.20.0", - "rand_core 0.6.4", - "subtle 2.4.1", -] - -[[package]] -name = "bls12_381" -version = "0.6.0" -source = "git+https://github.com/jstuczyn/bls12_381?branch=gt-serialisation#10fb6f700bfda17c8475af3bfd31e3fec15f2278" -dependencies = [ - "digest 0.9.0", - "ff 0.11.1", - "group 0.11.0", - "pairing 0.21.0", + "ff 0.13.0", + "group 0.13.0", + "pairing", "rand_core 0.6.4", "subtle 2.4.1", "zeroize", @@ -3030,26 +3016,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" -[[package]] -name = "ff" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" -dependencies = [ - "rand_core 0.6.4", - "subtle 2.4.1", -] - -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.4", - "subtle 2.4.1", -] - [[package]] name = "ff" version = "0.12.1" @@ -3066,6 +3032,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ + "bitvec", "rand_core 0.6.4", "subtle 2.4.1", ] @@ -3519,30 +3486,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "group" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" -dependencies = [ - "byteorder", - "ff 0.10.1", - "rand_core 0.6.4", - "subtle 2.4.1", -] - -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "byteorder", - "ff 0.11.1", - "rand_core 0.6.4", - "subtle 2.4.1", -] - [[package]] name = "group" version = "0.12.1" @@ -4286,6 +4229,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -5937,6 +5889,7 @@ dependencies = [ "futures-util", "getset", "humantime-serde", + "itertools 0.12.0", "lazy_static", "log", "nym-api-requests", @@ -6001,10 +5954,12 @@ dependencies = [ "cosmwasm-std", "getset", "nym-coconut-interface", + "nym-crypto", "nym-mixnet-contract-common", "nym-node-requests", "schemars", "serde", + "tendermint", "ts-rs", ] @@ -6022,6 +5977,7 @@ dependencies = [ "rand 0.7.3", "thiserror", "url", + "zeroize", ] [[package]] @@ -6257,14 +6213,14 @@ dependencies = [ name = "nym-coconut" version = "0.5.0" dependencies = [ - "bls12_381 0.6.0", + "bls12_381", "bs58 0.4.0", "criterion", "digest 0.9.0", "doc-comment", - "ff 0.11.1", + "ff 0.13.0", "getrandom 0.2.10", - "group 0.11.0", + "group 0.13.0", "itertools 0.10.5", "nym-dkg", "nym-pemstore", @@ -6274,6 +6230,7 @@ dependencies = [ "serde_derive", "sha2 0.9.9", "thiserror", + "zeroize", ] [[package]] @@ -6364,7 +6321,7 @@ dependencies = [ name = "nym-credentials" version = "0.1.0" dependencies = [ - "bls12_381 0.5.0", + "bls12_381", "cosmrs", "log", "nym-api-requests", @@ -6373,6 +6330,7 @@ dependencies = [ "nym-validator-client", "rand 0.7.3", "thiserror", + "zeroize", ] [[package]] @@ -6406,11 +6364,11 @@ name = "nym-dkg" version = "0.1.0" dependencies = [ "bitvec", - "bls12_381 0.6.0", + "bls12_381", "bs58 0.4.0", "criterion", - "ff 0.11.1", - "group 0.11.0", + "ff 0.13.0", + "group 0.13.0", "lazy_static", "nym-contracts-common", "nym-pemstore", @@ -7882,20 +7840,11 @@ dependencies = [ [[package]] name = "pairing" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de9d09263c9966e8196fe0380c9dbbc7ea114b5cf371ba29004bc1f9c6db7f3" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" dependencies = [ - "group 0.10.0", -] - -[[package]] -name = "pairing" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42" -dependencies = [ - "group 0.11.0", + "group 0.13.0", ] [[package]] @@ -9790,9 +9739,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -11014,16 +10963,16 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", "futures-util", - "hashbrown 0.12.3", + "hashbrown 0.14.1", "pin-project-lite 0.2.13", "slab", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 4d786023d4..52b8a5f382 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -162,7 +162,8 @@ serde_json = "1.0.91" tap = "1.0.1" time = "0.3.30" thiserror = "1.0.48" -tokio = "1.24.1" +tokio = "1.33.0" +tokio-util = "0.7.10" tokio-tungstenite = "0.20.1" tracing = "0.1.37" tungstenite = { version = "0.20.1", default-features = false } @@ -172,6 +173,14 @@ utoipa-swagger-ui = "3.1.5" url = "2.4" zeroize = "1.6.0" +# coconut/DKG related +# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork +# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm +bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="feature/gt-serialization-0.8.0" } +group = "0.13.0" +ff = "0.13.0" + + # cosmwasm-related cosmwasm-derive = "=1.3.0" cosmwasm-schema = "=1.3.0" @@ -192,6 +201,7 @@ cw-controllers = { version = "=1.1.0" } bip32 = "0.5.1" cosmrs = "=0.15.0" tendermint-rpc = "0.34" # same version as used by cosmrs +tendermint = "0.34" # same version as used by cosmrs prost = "0.12" # wasm-related dependencies diff --git a/common/bandwidth-controller/Cargo.toml b/common/bandwidth-controller/Cargo.toml index 7b8e4a51cb..79b5759e94 100644 --- a/common/bandwidth-controller/Cargo.toml +++ b/common/bandwidth-controller/Cargo.toml @@ -10,6 +10,7 @@ bip39 = { workspace = true } rand = "0.7.3" thiserror = { workspace = true } url = { workspace = true } +zeroize = { workspace = true } nym-coconut-interface = { path = "../coconut-interface" } nym-credential-storage = { path = "../credential-storage" } diff --git a/common/bandwidth-controller/src/acquire/mod.rs b/common/bandwidth-controller/src/acquire/mod.rs index c03ae8e90a..116634cf41 100644 --- a/common/bandwidth-controller/src/acquire/mod.rs +++ b/common/bandwidth-controller/src/acquire/mod.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::BandwidthControllerError; -use nym_coconut_interface::{Base58, Parameters}; +use nym_coconut_interface::Base58; use nym_credential_storage::storage::Storage; -use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES}; +use nym_credentials::coconut::bandwidth::BandwidthVoucher; use nym_credentials::coconut::utils::obtain_aggregate_signature; use nym_crypto::asymmetric::{encryption, identity}; use nym_network_defaults::VOUCHER_INFO; @@ -12,10 +12,8 @@ use nym_validator_client::coconut::all_coconut_api_clients; use nym_validator_client::nyxd::contract_traits::CoconutBandwidthSigningClient; use nym_validator_client::nyxd::contract_traits::DkgQueryClient; use nym_validator_client::nyxd::Coin; -use nym_validator_client::nyxd::Hash; use rand::rngs::OsRng; -use state::{KeyPair, State}; -use std::str::FromStr; +use state::State; pub mod state; @@ -24,30 +22,29 @@ where C: CoconutBandwidthSigningClient + Sync, { let mut rng = OsRng; - let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng)); - let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng)); - let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap(); + let signing_key = identity::PrivateKey::new(&mut rng); + let encryption_key = encryption::PrivateKey::new(&mut rng); + let params = BandwidthVoucher::default_parameters(); let voucher_value = amount.amount.to_string(); let tx_hash = client .deposit( amount, String::from(VOUCHER_INFO), - signing_keypair.public_key.clone(), - encryption_keypair.public_key.clone(), + signing_key.public_key().to_base58_string(), + encryption_key.public_key().to_base58_string(), None, ) .await? - .transaction_hash - .to_string(); + .transaction_hash; let voucher = BandwidthVoucher::new( ¶ms, voucher_value, VOUCHER_INFO.to_string(), - Hash::from_str(&tx_hash).map_err(|_| BandwidthControllerError::InvalidTxHash)?, - identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?, - encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?, + tx_hash, + signing_key, + encryption_key, ); let state = State { voucher, params }; diff --git a/common/bandwidth-controller/src/acquire/state.rs b/common/bandwidth-controller/src/acquire/state.rs index de77992962..7c6cc31c05 100644 --- a/common/bandwidth-controller/src/acquire/state.rs +++ b/common/bandwidth-controller/src/acquire/state.rs @@ -2,32 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use nym_coconut_interface::Parameters; -use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES}; - -use nym_crypto::asymmetric::{encryption, identity}; - -pub(crate) struct KeyPair { - pub public_key: String, - pub private_key: String, -} - -impl From for KeyPair { - fn from(kp: identity::KeyPair) -> Self { - Self { - public_key: kp.public_key().to_base58_string(), - private_key: kp.private_key().to_base58_string(), - } - } -} - -impl From for KeyPair { - fn from(kp: encryption::KeyPair) -> Self { - Self { - public_key: kp.public_key().to_base58_string(), - private_key: kp.private_key().to_base58_string(), - } - } -} +use nym_credentials::coconut::bandwidth::BandwidthVoucher; pub struct State { pub voucher: BandwidthVoucher, @@ -38,7 +13,7 @@ impl State { pub fn new(voucher: BandwidthVoucher) -> Self { State { voucher, - params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(), + params: BandwidthVoucher::default_parameters(), } } } diff --git a/common/bandwidth-controller/src/lib.rs b/common/bandwidth-controller/src/lib.rs index d9a714b263..b7d61e2935 100644 --- a/common/bandwidth-controller/src/lib.rs +++ b/common/bandwidth-controller/src/lib.rs @@ -7,6 +7,7 @@ use nym_credential_storage::storage::Storage; use nym_validator_client::coconut::all_coconut_api_clients; use nym_validator_client::nyxd::contract_traits::DkgQueryClient; use std::str::FromStr; +use zeroize::Zeroizing; use { nym_coconut_interface::Base58, nym_credentials::coconut::{ @@ -46,10 +47,12 @@ impl BandwidthController { let voucher_value = u64::from_str(&bandwidth_credential.voucher_value) .map_err(|_| StorageError::InconsistentData)?; let voucher_info = bandwidth_credential.voucher_info.clone(); - let serial_number = - nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.serial_number)?; - let binding_number = - nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.binding_number)?; + let serial_number = Zeroizing::new(nym_coconut_interface::Attribute::try_from_bs58( + bandwidth_credential.serial_number, + )?); + let binding_number = Zeroizing::new(nym_coconut_interface::Attribute::try_from_bs58( + bandwidth_credential.binding_number, + )?); let signature = nym_coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?; let epoch_id = u64::from_str(&bandwidth_credential.epoch_id) @@ -64,8 +67,8 @@ impl BandwidthController { prepare_for_spending( voucher_value, voucher_info, - serial_number, - binding_number, + &serial_number, + &binding_number, epoch_id, &signature, &verification_key, diff --git a/common/client-libs/mixnet-client/Cargo.toml b/common/client-libs/mixnet-client/Cargo.toml index 9eede069da..8496a6fae9 100644 --- a/common/client-libs/mixnet-client/Cargo.toml +++ b/common/client-libs/mixnet-client/Cargo.toml @@ -9,8 +9,8 @@ edition = "2021" [dependencies] futures = { workspace = true } log = { workspace = true } -tokio = { version = "1.24.1", features = ["time", "net", "rt"] } -tokio-util = { version = "0.7.4", features = ["codec"] } +tokio = { workspace = true, features = ["time", "net", "rt"] } +tokio-util = { workspace = true, features = ["codec"] } # internal nym-sphinx = { path = "../../nymsphinx" } diff --git a/common/client-libs/validator-client/src/nym_api/mod.rs b/common/client-libs/validator-client/src/nym_api/mod.rs index 21ac049840..d4902bd1a1 100644 --- a/common/client-libs/validator-client/src/nym_api/mod.rs +++ b/common/client-libs/validator-client/src/nym_api/mod.rs @@ -5,8 +5,12 @@ use crate::nym_api::error::NymAPIError; use crate::nym_api::routes::{CORE_STATUS_COUNT, SINCE_ARG}; use async_trait::async_trait; use http_api_client::{ApiClient, NO_PARAMS}; +use nym_api_requests::coconut::models::{ + EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse, +}; use nym_api_requests::coconut::{ - BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse, + BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody, VerifyCredentialBody, + VerifyCredentialResponse, }; use nym_api_requests::models::{ ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse, @@ -15,6 +19,7 @@ use nym_api_requests::models::{ MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse, }; +use nym_coconut_dkg_common::types::EpochId; use nym_mixnet_contract_common::mixnode::MixNodeDetails; use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId}; use nym_name_service_common::response::NamesListResponse; @@ -399,6 +404,60 @@ pub trait NymApiClientExt: ApiClient { .await } + async fn epoch_credentials( + &self, + dkg_epoch: EpochId, + ) -> Result { + self.get_json( + &[ + routes::API_VERSION, + routes::COCONUT_ROUTES, + routes::BANDWIDTH, + routes::COCONUT_EPOCH_CREDENTIALS, + &dkg_epoch.to_string(), + ], + NO_PARAMS, + ) + .await + } + + async fn issued_credential( + &self, + credential_id: i64, + ) -> Result { + self.get_json( + &[ + routes::API_VERSION, + routes::COCONUT_ROUTES, + routes::BANDWIDTH, + routes::COCONUT_ISSUED_CREDENTIAL, + &credential_id.to_string(), + ], + NO_PARAMS, + ) + .await + } + + async fn issued_credentials( + &self, + credential_ids: Vec, + ) -> Result { + self.post_json( + &[ + routes::API_VERSION, + routes::COCONUT_ROUTES, + routes::BANDWIDTH, + routes::COCONUT_ISSUED_CREDENTIALS, + ], + NO_PARAMS, + &CredentialsRequestBody { + credential_ids, + pagination: None, + }, + ) + .await + } + async fn get_service_providers(&self) -> Result { log::trace!("Getting service providers"); self.get_json(&[routes::API_VERSION, routes::SERVICE_PROVIDERS], NO_PARAMS) diff --git a/common/client-libs/validator-client/src/nym_api/routes.rs b/common/client-libs/validator-client/src/nym_api/routes.rs index df063a114d..d670033049 100644 --- a/common/client-libs/validator-client/src/nym_api/routes.rs +++ b/common/client-libs/validator-client/src/nym_api/routes.rs @@ -17,6 +17,9 @@ pub const BANDWIDTH: &str = "bandwidth"; pub const COCONUT_BLIND_SIGN: &str = "blind-sign"; pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential"; +pub const COCONUT_EPOCH_CREDENTIALS: &str = "epoch-credentials"; +pub const COCONUT_ISSUED_CREDENTIAL: &str = "issued-credential"; +pub const COCONUT_ISSUED_CREDENTIALS: &str = "issued-credentials"; pub const STATUS_ROUTES: &str = "status"; pub const MIXNODE: &str = "mixnode"; diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/coconut_bandwidth_signing_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/coconut_bandwidth_signing_client.rs index 030d78b29a..2402dc078f 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/coconut_bandwidth_signing_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/coconut_bandwidth_signing_client.rs @@ -32,7 +32,7 @@ pub trait CoconutBandwidthSigningClient { fee: Option, ) -> Result { let req = CoconutBandwidthExecuteMsg::DepositFunds { - data: DepositData::new(info.to_string(), verification_key, encryption_key), + data: DepositData::new(info, verification_key, encryption_key), }; self.execute_coconut_bandwidth_contract( fee, diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/multisig_query_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/multisig_query_client.rs index 48fcadc050..57c6ce2bf7 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/multisig_query_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/multisig_query_client.rs @@ -6,8 +6,8 @@ use crate::nyxd::error::NyxdError; use crate::nyxd::CosmWasmClient; use async_trait::async_trait; use cw3::{ - ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterListResponse, - VoterResponse, + ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterDetail, + VoterListResponse, VoterResponse, }; use cw_utils::ThresholdResponse; use nym_multisig_contract_common::msg::QueryMsg as MultisigQueryMsg; @@ -114,6 +114,26 @@ pub trait PagedMultisigQueryClient: MultisigQueryClient { Ok(proposals) } + + async fn get_all_voters(&self) -> Result, NyxdError> { + let mut voters = Vec::new(); + let mut start_after = None; + + loop { + let mut paged_response = self.list_voters(start_after.take(), None).await?; + + let last_voter = paged_response.voters.last().map(|prop| prop.addr.clone()); + voters.append(&mut paged_response.voters); + + if let Some(start_after_res) = last_voter { + start_after = Some(start_after_res) + } else { + break; + } + } + + Ok(voters) + } } #[async_trait] diff --git a/common/client-libs/validator-client/src/nyxd/helpers.rs b/common/client-libs/validator-client/src/nyxd/helpers.rs new file mode 100644 index 0000000000..85999eac6f --- /dev/null +++ b/common/client-libs/validator-client/src/nyxd/helpers.rs @@ -0,0 +1,13 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::nyxd::TxResponse; + +pub fn find_tx_attribute(tx: &TxResponse, event_type: &str, attribute_key: &str) -> Option { + let event = tx.tx_result.events.iter().find(|e| e.kind == event_type)?; + let attribute = event + .attributes + .iter() + .find(|attr| attr.key == attribute_key)?; + Some(attribute.value.clone()) +} diff --git a/common/client-libs/validator-client/src/nyxd/mod.rs b/common/client-libs/validator-client/src/nyxd/mod.rs index f28df6567f..12f941d2aa 100644 --- a/common/client-libs/validator-client/src/nyxd/mod.rs +++ b/common/client-libs/validator-client/src/nyxd/mod.rs @@ -47,6 +47,10 @@ pub use cosmrs::Coin as CosmosCoin; pub use cosmrs::Gas; pub use cosmrs::{bip32, AccountId, Denom}; pub use cosmwasm_std::Coin as CosmWasmCoin; +pub use cw2; +pub use cw3; +pub use cw4; +pub use cw_controllers; pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment}; pub use tendermint_rpc::{ endpoint::{tx::Response as TxResponse, validators::Response as ValidatorResponse}, @@ -67,6 +71,7 @@ pub mod contract_traits; pub mod cosmwasm_client; pub mod error; pub mod fee; +pub mod helpers; #[derive(Debug, Clone)] pub struct Config { diff --git a/common/coconut-interface/src/lib.rs b/common/coconut-interface/src/lib.rs index 2322bc3978..65aab8fb7f 100644 --- a/common/coconut-interface/src/lib.rs +++ b/common/coconut-interface/src/lib.rs @@ -21,10 +21,14 @@ pub use nym_coconut::{ pub struct Credential { #[getset(get = "pub")] n_params: u32, + #[getset(get = "pub")] theta: Theta, + voucher_value: u64, + voucher_info: String, + #[getset(get = "pub")] epoch_id: u64, } @@ -64,14 +68,12 @@ impl Credential { pub fn verify(&self, verification_key: &VerificationKey) -> bool { let params = Parameters::new(self.n_params).unwrap(); - let public_attributes = [ - self.voucher_value.to_string().as_bytes(), - self.voucher_info.as_bytes(), - ] - .iter() - .map(hash_to_scalar) - .collect::>(); - nym_coconut::verify_credential(¶ms, verification_key, &self.theta, &public_attributes) + + let hashed_value = hash_to_scalar(self.voucher_value.to_string()); + let hashed_info = hash_to_scalar(&self.voucher_info); + let public_attributes = &[&hashed_value, &hashed_info]; + + nym_coconut::verify_credential(¶ms, verification_key, &self.theta, public_attributes) } pub fn as_bytes(&self) -> Vec { @@ -180,8 +182,8 @@ mod tests { ¶ms, &verification_key, &signature, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap(); let credential = Credential::new(4, theta, voucher_value, voucher_info, 42); diff --git a/common/commands/src/coconut/issue_credentials.rs b/common/commands/src/coconut/issue_credentials.rs index cd8a9b5f36..9533af614e 100644 --- a/common/commands/src/coconut/issue_credentials.rs +++ b/common/commands/src/coconut/issue_credentials.rs @@ -26,6 +26,10 @@ pub struct Args { } pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> { + if args.amount == 0 { + bail!("did not specify credential amount") + } + let loaded = CommonConfigsWrapper::try_load(args.client_config)?; if let Ok(id) = loaded.try_get_id() { diff --git a/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs index 5204f6a97e..450ecd2543 100644 --- a/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs +++ b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs @@ -4,6 +4,9 @@ // event types pub const DEPOSITED_FUNDS_EVENT_TYPE: &str = "deposited-funds"; +// a 'wasm-' prefix is added to all cosmwasm events +pub const COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE: &str = "wasm-deposited-funds"; + // attributes that are used in multiple places pub const DEPOSIT_VALUE: &str = "deposit-value"; pub const DEPOSIT_INFO: &str = "deposit-info"; diff --git a/common/cosmwasm-smart-contracts/coconut-dkg/src/types.rs b/common/cosmwasm-smart-contracts/coconut-dkg/src/types.rs index b01f1101ab..29e7c52d67 100644 --- a/common/cosmwasm-smart-contracts/coconut-dkg/src/types.rs +++ b/common/cosmwasm-smart-contracts/coconut-dkg/src/types.rs @@ -174,17 +174,19 @@ impl Display for EpochState { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { EpochState::PublicKeySubmission { resharing } => { - write!(f, "PublicKeySubmission with resharing {resharing}") + write!(f, "PublicKeySubmission (resharing: {resharing})") + } + EpochState::DealingExchange { resharing } => { + write!(f, "DealingExchange (resharing: {resharing})") } - EpochState::DealingExchange { resharing } => write!(f, "DealingExchange {resharing}"), EpochState::VerificationKeySubmission { resharing } => { - write!(f, "VerificationKeySubmission with resharing {resharing}") + write!(f, "VerificationKeySubmission (resharing: {resharing})") } EpochState::VerificationKeyValidation { resharing } => { - write!(f, "VerificationKeyValidation with resharing {resharing}") + write!(f, "VerificationKeyValidation (resharing: {resharing})") } EpochState::VerificationKeyFinalization { resharing } => { - write!(f, "VerificationKeyFinalization with resharing {resharing}") + write!(f, "VerificationKeyFinalization (resharing: {resharing})") } EpochState::InProgress => write!(f, "InProgress"), } diff --git a/common/credentials/Cargo.toml b/common/credentials/Cargo.toml index aff9cf01ab..a50898f518 100644 --- a/common/credentials/Cargo.toml +++ b/common/credentials/Cargo.toml @@ -6,14 +6,15 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] } +bls12_381 = { workspace = true, default-features = false, features = ["pairings", "alloc", "experimental"] } cosmrs = { workspace = true } thiserror = { workspace = true } log = { workspace = true } +zeroize = { workspace = true } # I guess temporarily until we get serde support in coconut up and running nym-coconut-interface = { path = "../coconut-interface" } -nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] } +nym-crypto = { path = "../crypto", features = ["rand", "asymmetric"] } nym-api-requests = { path = "../../nym-api/nym-api-requests" } nym-validator-client = { path = "../client-libs/validator-client", default-features = false } diff --git a/common/credentials/src/coconut/bandwidth.rs b/common/credentials/src/coconut/bandwidth.rs index 7e458456df..9646860a74 100644 --- a/common/credentials/src/coconut/bandwidth.rs +++ b/common/credentials/src/coconut/bandwidth.rs @@ -13,38 +13,60 @@ use nym_coconut_interface::{ PrivateAttribute, PublicAttribute, Signature, VerificationKey, }; use nym_crypto::asymmetric::{encryption, identity}; +use zeroize::{Zeroize, ZeroizeOnDrop}; use super::utils::prepare_credential_for_spending; use crate::error::Error; -pub const PUBLIC_ATTRIBUTES: u32 = 2; -pub const PRIVATE_ATTRIBUTES: u32 = 2; -pub const TOTAL_ATTRIBUTES: u32 = PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES; - +#[derive(Zeroize, ZeroizeOnDrop)] pub struct BandwidthVoucher { - // a random secret value generated by the client used for double-spending detection + // private attributes + /// a random secret value generated by the client used for double-spending detection serial_number: PrivateAttribute, - // a random secret value generated by the client used to bind multiple credentials together + + /// a random secret value generated by the client used to bind multiple credentials together binding_number: PrivateAttribute, - // the value (e.g., bandwidth) encoded in this voucher - voucher_value: PublicAttribute, - // the plain text value (e.g., bandwidth) encoded in this voucher + + // public atttributes: + /// the plain text value (e.g., bandwidth) encoded in this voucher + // TODO: in another PR change the value from `"1000"` to `"1000unym"` voucher_value_plain: String, - // a field with public information, e.g., type of voucher, interval etc. - voucher_info: PublicAttribute, - // the plain text information + + /// the plain text information voucher_info_plain: String, - // the hash of the deposit transaction + + /// the precomputed value (e.g., bandwidth) encoded in this voucher + _voucher_value_prehashed: PublicAttribute, + + /// the precomputed field with public information, e.g., type of voucher, interval etc. + _voucher_info_prehashed: PublicAttribute, + + /// the hash of the deposit transaction + #[zeroize(skip)] tx_hash: Hash, - // base58 encoded private key ensuring the depositer requested these attributes + + /// base58 encoded private key ensuring the depositer requested these attributes signing_key: identity::PrivateKey, - // base58 encoded private key ensuring only this client receives the signature share - encryption_key: encryption::PrivateKey, + + /// base58 encoded private key ensuring only this client receives the signature share + unused_ed25519: encryption::PrivateKey, + pedersen_commitments_openings: Vec, + + #[zeroize(skip)] blind_sign_request: BlindSignRequest, } impl BandwidthVoucher { + pub const PUBLIC_ATTRIBUTES: u32 = 2; + pub const PRIVATE_ATTRIBUTES: u32 = 2; + pub const ENCODED_ATTRIBUTES: u32 = 4; + + pub fn default_parameters() -> Parameters { + // safety: the unwrap is fine here as Self::ENCODED_ATTRIBUTES is non-zero + Parameters::new(Self::ENCODED_ATTRIBUTES).unwrap() + } + pub fn new( params: &Parameters, voucher_value: String, @@ -57,24 +79,26 @@ impl BandwidthVoucher { let binding_number = params.random_scalar(); let voucher_value_plain = voucher_value.clone(); let voucher_info_plain = voucher_info.clone(); - let voucher_value = hash_to_scalar(voucher_value.as_bytes()); - let voucher_info = hash_to_scalar(voucher_info.as_bytes()); + + let _voucher_value_prehashed = hash_to_scalar(voucher_value); + let _voucher_info_prehashed = hash_to_scalar(voucher_info); + let (pedersen_commitments_openings, blind_sign_request) = prepare_blind_sign( params, - &[serial_number, binding_number], - &[voucher_value, voucher_info], + &[&serial_number, &binding_number], + &[&_voucher_value_prehashed, &_voucher_info_prehashed], ) .unwrap(); BandwidthVoucher { serial_number, binding_number, - voucher_value, + _voucher_value_prehashed, voucher_value_plain, - voucher_info, + _voucher_info_prehashed, voucher_info_plain, tx_hash, signing_key, - encryption_key, + unused_ed25519: encryption_key, pedersen_commitments_openings, blind_sign_request, } @@ -87,7 +111,7 @@ impl BandwidthVoucher { let voucher_info_plain_b = self.voucher_info_plain.as_bytes(); let tx_hash_b = self.tx_hash.as_bytes(); let signing_key_b = self.signing_key.to_bytes(); - let encryption_key_b = self.encryption_key.to_bytes(); + let encryption_key_b = self.unused_ed25519.to_bytes(); let blind_sign_request_b = self.blind_sign_request.to_bytes(); let mut ret = Vec::new(); @@ -171,13 +195,13 @@ impl BandwidthVoucher { bytes[var_length_pointer..var_length_pointer + voucher_value_plain_no].to_vec(), ) .or_else(utf_err)?; - let voucher_value = hash_to_scalar(&voucher_value_plain); + let _voucher_value_prehashed = hash_to_scalar(&voucher_value_plain); var_length_pointer += voucher_value_plain_no; let voucher_info_plain = String::from_utf8( bytes[var_length_pointer..var_length_pointer + voucher_info_plain_no].to_vec(), ) .or_else(utf_err)?; - let voucher_info = hash_to_scalar(&voucher_info_plain); + let _voucher_info_prehashed = hash_to_scalar(&voucher_info_plain); var_length_pointer += voucher_info_plain_no; let blind_sign_request = BlindSignRequest::from_bytes( &bytes[var_length_pointer..var_length_pointer + blind_sign_request_no], @@ -196,36 +220,43 @@ impl BandwidthVoucher { Ok(Self { serial_number, binding_number, - voucher_value, + _voucher_value_prehashed, voucher_value_plain, - voucher_info, + _voucher_info_prehashed, voucher_info_plain, tx_hash, signing_key, - encryption_key, + unused_ed25519: encryption_key, pedersen_commitments_openings, blind_sign_request, }) } /// Check if the plain values correspond to the PublicAttributes - pub fn verify_against_plain(values: &[PublicAttribute], plain_values: &[String]) -> bool { + pub fn verify_against_plain(values: &[&PublicAttribute], plain_values: &[String]) -> bool { values.len() == 2 && plain_values.len() == 2 - && values[0] == hash_to_scalar(&plain_values[0]) - && values[1] == hash_to_scalar(&plain_values[1]) + && values[0] == &hash_to_scalar(&plain_values[0]) + && values[1] == &hash_to_scalar(&plain_values[1]) } - pub fn tx_hash(&self) -> &Hash { - &self.tx_hash + pub fn tx_hash(&self) -> Hash { + self.tx_hash } - pub fn get_public_attributes(&self) -> Vec { - vec![self.voucher_value, self.voucher_info] + pub fn get_public_attributes(&self) -> Vec<&PublicAttribute> { + vec![ + &self._voucher_value_prehashed, + &self._voucher_info_prehashed, + ] + } + + pub fn identity_key(&self) -> &identity::PrivateKey { + &self.signing_key } pub fn encryption_key(&self) -> &encryption::PrivateKey { - &self.encryption_key + &self.unused_ed25519 } pub fn pedersen_commitments_openings(&self) -> &Vec { @@ -247,27 +278,32 @@ impl BandwidthVoucher { ] } - pub fn get_private_attributes(&self) -> Vec { - vec![self.serial_number, self.binding_number] + pub fn get_private_attributes(&self) -> Vec<&PrivateAttribute> { + vec![&self.serial_number, &self.binding_number] } - pub fn sign(&self, request: &BlindSignRequest) -> identity::Signature { + pub fn signable_plaintext(request: &BlindSignRequest, tx_hash: Hash) -> Vec { let mut message = request.to_bytes(); - message.extend_from_slice(self.tx_hash.to_string().as_bytes()); - self.signing_key.sign(&message) + message.extend_from_slice(tx_hash.as_bytes()); + message + } + + pub fn sign(&self) -> identity::Signature { + let message = Self::signable_plaintext(&self.blind_sign_request, self.tx_hash); + self.signing_key.sign(message) } } pub fn prepare_for_spending( voucher_value: u64, voucher_info: String, - serial_number: PrivateAttribute, - binding_number: PrivateAttribute, + serial_number: &PrivateAttribute, + binding_number: &PrivateAttribute, epoch_id: u64, signature: &Signature, verification_key: &VerificationKey, ) -> Result { - let params = Parameters::new(TOTAL_ATTRIBUTES)?; + let params = Parameters::new(BandwidthVoucher::ENCODED_ATTRIBUTES)?; prepare_credential_for_spending( ¶ms, @@ -316,24 +352,30 @@ mod test { let deserialized_voucher = BandwidthVoucher::try_from_bytes(&bytes).unwrap(); assert_eq!(voucher.serial_number, deserialized_voucher.serial_number); assert_eq!(voucher.binding_number, deserialized_voucher.binding_number); - assert_eq!(voucher.voucher_value, deserialized_voucher.voucher_value); assert_eq!( voucher.voucher_value_plain, deserialized_voucher.voucher_value_plain ); - assert_eq!(voucher.voucher_info, deserialized_voucher.voucher_info); assert_eq!( voucher.voucher_info_plain, deserialized_voucher.voucher_info_plain ); + assert_eq!( + voucher._voucher_value_prehashed, + deserialized_voucher._voucher_value_prehashed + ); + assert_eq!( + voucher._voucher_info_prehashed, + deserialized_voucher._voucher_info_prehashed + ); assert_eq!(voucher.tx_hash, deserialized_voucher.tx_hash); assert_eq!( voucher.signing_key.to_string(), deserialized_voucher.signing_key.to_string() ); assert_eq!( - voucher.encryption_key.to_string(), - deserialized_voucher.encryption_key.to_string() + voucher.unused_ed25519.to_string(), + deserialized_voucher.unused_ed25519.to_string() ); assert_eq!( voucher.pedersen_commitments_openings, @@ -371,11 +413,11 @@ mod test { ] )); assert!(!BandwidthVoucher::verify_against_plain( - &[voucher.get_public_attributes()[0], Attribute::one()], + &[voucher.get_public_attributes()[0], &Attribute::one()], &voucher.get_public_attributes_plain() )); assert!(!BandwidthVoucher::verify_against_plain( - &[Attribute::one(), voucher.get_public_attributes()[1]], + &[&Attribute::one(), voucher.get_public_attributes()[1]], &voucher.get_public_attributes_plain() )); assert!(BandwidthVoucher::verify_against_plain( diff --git a/common/credentials/src/coconut/mod.rs b/common/credentials/src/coconut/mod.rs index c1d900689a..bf480ad58a 100644 --- a/common/credentials/src/coconut/mod.rs +++ b/common/credentials/src/coconut/mod.rs @@ -2,5 +2,4 @@ // SPDX-License-Identifier: Apache-2.0 pub mod bandwidth; -pub mod params; pub mod utils; diff --git a/common/credentials/src/coconut/params.rs b/common/credentials/src/coconut/params.rs deleted file mode 100644 index 906ef7cae0..0000000000 --- a/common/credentials/src/coconut/params.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use nym_crypto::aes::Aes128; -use nym_crypto::blake3; -use nym_crypto::ctr; - -type Aes128Ctr = ctr::Ctr64LE; - -/// Hashing algorithm used during hkdf for ephemeral shared key generation per blinded signature -/// response encryption. -pub type NymApiCredentialHkdfAlgorithm = blake3::Hasher; - -/// Encryption algorithm used for end-to-end encryption of blinded signature response -pub type NymApiCredentialEncryptionAlgorithm = Aes128Ctr; diff --git a/common/credentials/src/coconut/utils.rs b/common/credentials/src/coconut/utils.rs index b7fda42f73..367f62e2c3 100644 --- a/common/credentials/src/coconut/utils.rs +++ b/common/credentials/src/coconut/utils.rs @@ -1,18 +1,14 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES}; -use crate::coconut::params::{NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm}; +use crate::coconut::bandwidth::BandwidthVoucher; use crate::error::Error; use log::{debug, warn}; use nym_api_requests::coconut::BlindSignRequestBody; use nym_coconut_interface::{ aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute, - BlindedSignature, Credential, Parameters, Signature, SignatureShare, VerificationKey, + Credential, Parameters, Signature, SignatureShare, VerificationKey, }; -use nym_crypto::asymmetric::encryption::PublicKey; -use nym_crypto::shared_key::recompute_shared_key; -use nym_crypto::symmetric::stream_cipher; use nym_validator_client::client::CoconutApiClient; pub async fn obtain_aggregate_verification_key( @@ -36,47 +32,34 @@ pub async fn obtain_aggregate_verification_key( async fn obtain_partial_credential( params: &Parameters, - attributes: &BandwidthVoucher, + voucher: &BandwidthVoucher, client: &nym_validator_client::client::NymApiClient, validator_vk: &VerificationKey, ) -> Result { - let public_attributes = attributes.get_public_attributes(); - let public_attributes_plain = attributes.get_public_attributes_plain(); - let private_attributes = attributes.get_private_attributes(); - let blind_sign_request = attributes.blind_sign_request(); + let public_attributes_plain = voucher.get_public_attributes_plain(); + let blind_sign_request = voucher.blind_sign_request(); + let request_signature = voucher.sign(); let blind_sign_request_body = BlindSignRequestBody::new( - blind_sign_request, - attributes.tx_hash().to_string(), - attributes.sign(blind_sign_request).to_base58_string(), - &public_attributes, + blind_sign_request.clone(), + voucher.tx_hash(), + request_signature, public_attributes_plain, - (public_attributes.len() + private_attributes.len()) as u32, ); let response = client.blind_sign(&blind_sign_request_body).await?; - let encrypted_signature = response.encrypted_signature; - let remote_key = PublicKey::from_bytes(&response.remote_key)?; - let encryption_key = recompute_shared_key::< - NymApiCredentialEncryptionAlgorithm, - NymApiCredentialHkdfAlgorithm, - >(&remote_key, attributes.encryption_key()); - let zero_iv = stream_cipher::zero_iv::(); - let blinded_signature_bytes = stream_cipher::decrypt::( - &encryption_key, - &zero_iv, - &encrypted_signature, - ); + let blinded_signature = response.blinded_signature; - let blinded_signature = BlindedSignature::from_bytes(&blinded_signature_bytes)?; + let public_attributes = voucher.get_public_attributes(); + let private_attributes = voucher.get_private_attributes(); - let unblinded_signature = blinded_signature.unblind( + let unblinded_signature = blinded_signature.unblind_and_verify( params, validator_vk, &private_attributes, &public_attributes, &blind_sign_request.get_commitment_hash(), - attributes.pedersen_commitments_openings(), + voucher.pedersen_commitments_openings(), )?; Ok(unblinded_signature) @@ -84,16 +67,13 @@ async fn obtain_partial_credential( pub async fn obtain_aggregate_signature( params: &Parameters, - attributes: &BandwidthVoucher, + voucher: &BandwidthVoucher, coconut_api_clients: &[CoconutApiClient], threshold: u64, ) -> Result { if coconut_api_clients.is_empty() { return Err(Error::NoValidatorsAvailable); } - let public_attributes = attributes.get_public_attributes(); - let private_attributes = attributes.get_private_attributes(); - let mut shares = Vec::with_capacity(coconut_api_clients.len()); let validators_partial_vks: Vec<_> = coconut_api_clients .iter() @@ -114,7 +94,7 @@ pub async fn obtain_aggregate_signature( match obtain_partial_credential( params, - attributes, + voucher, &coconut_api_client.api_client, &coconut_api_client.verification_key, ) @@ -136,6 +116,9 @@ pub async fn obtain_aggregate_signature( return Err(Error::NotEnoughShares); } + let public_attributes = voucher.get_public_attributes(); + let private_attributes = voucher.get_private_attributes(); + let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len()); attributes.extend_from_slice(&private_attributes); attributes.extend_from_slice(&public_attributes); @@ -150,8 +133,8 @@ pub fn prepare_credential_for_spending( params: &Parameters, voucher_value: u64, voucher_info: String, - serial_number: Attribute, - binding_number: Attribute, + serial_number: &Attribute, + binding_number: &Attribute, epoch_id: u64, signature: &Signature, verification_key: &VerificationKey, @@ -165,7 +148,7 @@ pub fn prepare_credential_for_spending( )?; Ok(Credential::new( - PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES, + BandwidthVoucher::ENCODED_ATTRIBUTES, theta, voucher_value, voucher_info, diff --git a/common/crypto/src/asymmetric/encryption/mod.rs b/common/crypto/src/asymmetric/encryption/mod.rs index 6c45d41d60..bc97f67df4 100644 --- a/common/crypto/src/asymmetric/encryption/mod.rs +++ b/common/crypto/src/asymmetric/encryption/mod.rs @@ -201,6 +201,17 @@ impl<'a> From<&'a PrivateKey> for PublicKey { } impl PrivateKey { + #[cfg(feature = "rand")] + pub fn new(rng: &mut R) -> Self { + let x25519_secret = x25519_dalek::StaticSecret::new(rng); + + PrivateKey(x25519_secret) + } + + pub fn public_key(&self) -> PublicKey { + self.into() + } + pub fn to_bytes(&self) -> [u8; PRIVATE_KEY_SIZE] { self.0.to_bytes() } diff --git a/common/crypto/src/asymmetric/identity/mod.rs b/common/crypto/src/asymmetric/identity/mod.rs index a56abdee32..ffbcac88ac 100644 --- a/common/crypto/src/asymmetric/identity/mod.rs +++ b/common/crypto/src/asymmetric/identity/mod.rs @@ -5,13 +5,14 @@ pub use ed25519_dalek::ed25519::signature::Signature as SignatureTrait; pub use ed25519_dalek::SignatureError; pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH}; use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair}; -#[cfg(feature = "sphinx")] -use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH}; use std::fmt::{self, Display, Formatter}; use std::str::FromStr; use thiserror::Error; use zeroize::{Zeroize, ZeroizeOnDrop}; +#[cfg(feature = "sphinx")] +use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH}; + #[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; #[cfg(feature = "serde")] @@ -224,6 +225,17 @@ impl<'a> From<&'a PrivateKey> for PublicKey { } impl PrivateKey { + #[cfg(feature = "rand")] + pub fn new(rng: &mut R) -> Self { + let ed25519_secret = ed25519_dalek::SecretKey::generate(rng); + + PrivateKey(ed25519_secret) + } + + pub fn public_key(&self) -> PublicKey { + self.into() + } + pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { self.0.to_bytes() } @@ -295,7 +307,7 @@ impl PemStorableKey for PrivateKey { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Signature(ed25519_dalek::Signature); impl Signature { @@ -319,6 +331,14 @@ impl Signature { } } +impl FromStr for Signature { + type Err = Ed25519RecoveryError; + + fn from_str(s: &str) -> Result { + Signature::from_base58_string(s) + } +} + #[cfg(feature = "serde")] impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result diff --git a/common/dkg/Cargo.toml b/common/dkg/Cargo.toml index 26808724bf..b85805218e 100644 --- a/common/dkg/Cargo.toml +++ b/common/dkg/Cargo.toml @@ -11,7 +11,7 @@ bitvec = "1.0.0" # unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork # as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm -bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] } +bls12_381 = { workspace = true, default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] } nym-contracts-common = { path = "../cosmwasm-smart-contracts/contracts-common", optional = true } bs58 = "0.4" @@ -29,11 +29,11 @@ zeroize = { workspace = true, features = ["zeroize_derive"] } nym-pemstore = { path = "../pemstore" } [dependencies.group] -version = "0.11" +workspace = true default-features = false [dependencies.ff] -version = "0.11" +workspace = true default-features = false [dev-dependencies] diff --git a/common/mixnode-common/Cargo.toml b/common/mixnode-common/Cargo.toml index b2fcf6e2a3..b48707eddf 100644 --- a/common/mixnode-common/Cargo.toml +++ b/common/mixnode-common/Cargo.toml @@ -20,7 +20,7 @@ tokio = { version = "1.24.1", features = [ "net", "io-util", ] } -tokio-util = { version = "0.7.4", features = ["codec"] } +tokio-util = { workspace = true, features = ["codec"] } url = { workspace = true } thiserror = { workspace = true } diff --git a/common/nymcoconut/Cargo.toml b/common/nymcoconut/Cargo.toml index 7aed2bb595..e5a98a92b0 100644 --- a/common/nymcoconut/Cargo.toml +++ b/common/nymcoconut/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="gt-serialisation", default-features = false, features = ["pairings", "alloc", "experimental"] } +bls12_381 = { workspace = true, default-features = false, features = ["pairings", "alloc", "experimental"] } itertools = "0.10" digest = "0.9" rand = "0.8" @@ -16,16 +16,17 @@ serde = { workspace = true } serde_derive = "1.0" bs58 = "0.4.0" sha2 = "0.9" +zeroize = { workspace = true, optional = true } nym-dkg = { path = "../dkg" } nym-pemstore = { path = "../pemstore" } [dependencies.ff] -version = "0.11" +workspace = true default-features = false [dependencies.group] -version = "0.11" +workspace = true default-features = false [dev-dependencies] @@ -38,7 +39,9 @@ name = "benchmarks" harness = false [features] +key-zeroize = ["zeroize", "bls12_381/zeroize"] default = [] + [target.'cfg(target_env = "wasm32-unknown-unknown")'.dependencies] getrandom = { version="0.2", features=["js"] } diff --git a/common/nymcoconut/benches/benchmarks.rs b/common/nymcoconut/benches/benchmarks.rs index 6627b437e1..6bf582a244 100644 --- a/common/nymcoconut/benches/benchmarks.rs +++ b/common/nymcoconut/benches/benchmarks.rs @@ -7,7 +7,7 @@ use ff::Field; use group::{Curve, Group}; use nym_coconut::{ aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign, - prove_bandwidth_credential, setup, ttp_keygen, verify_credential, + prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen, verify_credential, verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature, SignatureShare, VerificationKey, }; @@ -66,8 +66,8 @@ fn unblind_and_aggregate( params: &Parameters, blinded_signatures: &[BlindedSignature], partial_verification_keys: &[VerificationKey], - private_attributes: &[Attribute], - public_attributes: &[Attribute], + private_attributes: &[&Attribute], + public_attributes: &[&Attribute], commitment_hash: &G1Projective, pedersen_commitments_openings: &[Scalar], verification_key: &VerificationKey, @@ -78,7 +78,7 @@ fn unblind_and_aggregate( .zip(partial_verification_keys.iter()) .map(|(signature, partial_verification_key)| { signature - .unblind( + .unblind_and_verify( params, partial_verification_key, private_attributes, @@ -171,10 +171,10 @@ fn bench_coconut(c: &mut Criterion) { let params = setup(case.num_public_attrs + case.num_private_attrs).unwrap(); - let public_attributes = params.n_random_scalars(case.num_public_attrs as usize); + random_scalars_refs!(public_attributes, params, case.num_public_attrs as usize); let serial_number = params.random_scalar(); let binding_number = params.random_scalar(); - let private_attributes = vec![serial_number, binding_number]; + let private_attributes = vec![&serial_number, &binding_number]; // The prepare blind sign is performed by the user let (pedersen_commitments_openings, blind_sign_request) = @@ -213,7 +213,7 @@ fn bench_coconut(c: &mut Criterion) { b.iter(|| { blind_sign( ¶ms, - &keypair.secret_key(), + keypair.secret_key(), &blind_sign_request, &public_attributes, ) @@ -228,7 +228,7 @@ fn bench_coconut(c: &mut Criterion) { for keypair in coconut_keypairs.iter() { let blinded_signature = blind_sign( ¶ms, - &keypair.secret_key(), + keypair.secret_key(), &blind_sign_request, &public_attributes, ) @@ -238,7 +238,7 @@ fn bench_coconut(c: &mut Criterion) { let verification_keys: Vec = coconut_keypairs .iter() - .map(|keypair| keypair.verification_key()) + .map(|keypair| keypair.verification_key().clone()) .collect(); // verify a random partial blind signature @@ -310,8 +310,8 @@ fn bench_coconut(c: &mut Criterion) { ¶ms, &aggr_verification_key, &aggregated_signature, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap(); @@ -329,8 +329,8 @@ fn bench_coconut(c: &mut Criterion) { ¶ms, &aggr_verification_key, &aggregated_signature, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap() }) diff --git a/common/nymcoconut/src/elgamal.rs b/common/nymcoconut/src/elgamal.rs index bf3895861e..3a1d473b2e 100644 --- a/common/nymcoconut/src/elgamal.rs +++ b/common/nymcoconut/src/elgamal.rs @@ -34,7 +34,10 @@ impl TryFrom<&[u8]> for Ciphertext { ))); } + // safety: we just checked for the length so the unwraps are fine + #[allow(clippy::unwrap_used)] let c1_bytes: &[u8; 48] = &bytes[..48].try_into().unwrap(); + #[allow(clippy::unwrap_used)] let c2_bytes: &[u8; 48] = &bytes[48..].try_into().unwrap(); let c1 = try_deserialize_g1_projective( @@ -112,7 +115,16 @@ impl Bytable for PrivateKey { } fn try_from_byte_slice(slice: &[u8]) -> Result { - PrivateKey::from_bytes(slice.try_into().unwrap()) + let received = slice.len(); + let Ok(arr) = slice.try_into() else { + return Err(CoconutError::UnexpectedArrayLength { + typ: "elgamal::PrivateKey".to_string(), + received, + expected: 32, + }); + }; + + PrivateKey::from_bytes(arr) } } @@ -145,21 +157,36 @@ impl PublicKey { } pub fn to_bytes(&self) -> [u8; 48] { - self.to_byte_vec().try_into().unwrap() + self.0.to_affine().to_compressed() } pub fn from_bytes(bytes: &[u8; 48]) -> Result { - Ok(PublicKey::try_from(bytes.to_vec().as_slice()).unwrap()) + try_deserialize_g1_projective( + bytes, + CoconutError::Deserialization( + "Failed to deserialize compressed ElGamal public key".to_string(), + ), + ) + .map(PublicKey) } } impl Bytable for PublicKey { fn to_byte_vec(&self) -> Vec { - self.0.to_affine().to_compressed().into() + self.to_bytes().into() } fn try_from_byte_slice(slice: &[u8]) -> Result { - Ok(PublicKey::from_bytes(slice.try_into().unwrap()).unwrap()) + let received = slice.len(); + let Ok(arr) = slice.try_into() else { + return Err(CoconutError::UnexpectedArrayLength { + typ: "elgamal::PublicKey".to_string(), + received, + expected: 48, + }); + }; + + PublicKey::from_bytes(arr) } } @@ -167,13 +194,7 @@ impl TryFrom<&[u8]> for PublicKey { type Error = CoconutError; fn try_from(slice: &[u8]) -> Result { - try_deserialize_g1_projective( - slice.try_into().unwrap(), - CoconutError::Deserialization( - "Failed to deserialize compressed ElGamal public key".to_string(), - ), - ) - .map(PublicKey) + PublicKey::try_from_byte_slice(slice) } } @@ -225,7 +246,7 @@ pub fn elgamal_keygen(params: &Parameters) -> ElGamalKeyPair { pub fn compute_attribute_encryption( params: &Parameters, - private_attributes: &[Attribute], + private_attributes: &[&Attribute], pub_key: &PublicKey, commitment_hash: G1Projective, ) -> (Vec, Vec) { diff --git a/common/nymcoconut/src/error.rs b/common/nymcoconut/src/error.rs index 7faf11c86e..d502c76c95 100644 --- a/common/nymcoconut/src/error.rs +++ b/common/nymcoconut/src/error.rs @@ -50,4 +50,20 @@ pub enum CoconutError { modulus: usize, object: String, }, + + #[error("received an array of unexpected size for deserialization of {typ}. got {received} but expected {expected}")] + UnexpectedArrayLength { + typ: String, + received: usize, + expected: usize, + }, + + #[error("failed to decode the base58 representation: {0}")] + Base58DecodingFailure(#[from] bs58::decode::Error), + + #[error("failed to deserialize scalar from the received bytes - it might not have been canonically encoded")] + ScalarDeserializationFailure, + + #[error("failed to deserialize G1Projective point from the received bytes - it might not have been canonically encoded")] + G1ProjectiveDeserializationFailure, } diff --git a/common/nymcoconut/src/lib.rs b/common/nymcoconut/src/lib.rs index 821b1b3b29..4f0db30a15 100644 --- a/common/nymcoconut/src/lib.rs +++ b/common/nymcoconut/src/lib.rs @@ -1,11 +1,9 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use std::convert::TryInto; +#![warn(clippy::expect_used)] +#![warn(clippy::unwrap_used)] -use bls12_381::Scalar; - -pub use crate::traits::Bytable; pub use elgamal::elgamal_keygen; pub use elgamal::ElGamalKeyPair; pub use elgamal::PublicKey; @@ -30,6 +28,7 @@ pub use scheme::BlindedSignature; pub use scheme::Signature; pub use scheme::SignatureShare; pub use traits::Base58; +pub use traits::Bytable; pub use utils::hash_to_scalar; pub mod elgamal; @@ -41,18 +40,6 @@ pub mod tests; mod traits; mod utils; -pub type Attribute = Scalar; +pub type Attribute = bls12_381::Scalar; pub type PrivateAttribute = Attribute; pub type PublicAttribute = Attribute; - -impl Bytable for Attribute { - fn to_byte_vec(&self) -> Vec { - self.to_bytes().to_vec() - } - - fn try_from_byte_slice(slice: &[u8]) -> Result { - Ok(Attribute::from_bytes(slice.try_into().unwrap()).unwrap()) - } -} - -impl Base58 for Attribute {} diff --git a/common/nymcoconut/src/proofs/mod.rs b/common/nymcoconut/src/proofs/mod.rs index 42f923466d..a7a5a97f79 100644 --- a/common/nymcoconut/src/proofs/mod.rs +++ b/common/nymcoconut/src/proofs/mod.rs @@ -91,8 +91,8 @@ impl ProofCmCs { commitment_opening: &Scalar, commitments: &[G1Projective], pedersen_commitments_openings: &[Scalar], - private_attributes: &[Attribute], - public_attributes: &[Attribute], + private_attributes: &[&Attribute], + public_attributes: &[&Attribute], ) -> Self { // note: this is only called from `prepare_blind_sign` that already checks // whether private attributes are non-empty and whether we don't have too many @@ -162,11 +162,8 @@ impl ProofCmCs { &challenge, &pedersen_commitments_openings.iter().collect::>(), ); - let response_attributes = produce_responses( - &witness_attributes, - &challenge, - &private_attributes.iter().collect::>(), - ); + let response_attributes = + produce_responses(&witness_attributes, &challenge, private_attributes); ProofCmCs { challenge, @@ -181,7 +178,7 @@ impl ProofCmCs { params: &Parameters, commitment: &G1Projective, commitments: &[G1Projective], - public_attributes: &[Attribute], + public_attributes: &[&Attribute], ) -> bool { if self.response_attributes.len() != commitments.len() { return false; @@ -203,7 +200,7 @@ impl ProofCmCs { - public_attributes .iter() .zip(params.gen_hs().iter().skip(self.response_attributes.len())) - .map(|(pub_attr, hs)| hs * pub_attr) + .map(|(&pub_attr, hs)| hs * pub_attr) .sum::()) * self.challenge + g1 * self.response_opening @@ -280,8 +277,12 @@ impl ProofCmCs { } let mut idx = 0; + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let challenge_bytes = bytes[idx..idx + 32].try_into().unwrap(); idx += 32; + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let response_opening_bytes = bytes[idx..idx + 32].try_into().unwrap(); idx += 32; @@ -297,6 +298,8 @@ impl ProofCmCs { ), )?; + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let ro_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap()); idx += 8; if bytes[idx..].len() < ro_len as usize * 32 + 8 { @@ -313,6 +316,8 @@ impl ProofCmCs { CoconutError::Deserialization("Failed to deserialize openings response".to_string()), )?; + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let rm_len = u64::from_le_bytes(bytes[ro_end..ro_end + 8].try_into().unwrap()); let response_attributes = try_deserialize_scalar_vec( rm_len, @@ -462,7 +467,7 @@ impl ProofKappaZeta { pub(crate) fn from_bytes(bytes: &[u8]) -> Result { // at the very minimum there must be a single attribute being proven - if bytes.len() < 32 * 4 || (bytes.len()) % 32 != 0 { + if bytes.len() != 128 { return Err(CoconutError::DeserializationInvalidLength { actual: bytes.len(), modulus_target: bytes.len(), @@ -472,24 +477,32 @@ impl ProofKappaZeta { }); } + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let challenge_bytes = bytes[..32].try_into().unwrap(); let challenge = try_deserialize_scalar( &challenge_bytes, CoconutError::Deserialization("Failed to deserialize challenge".to_string()), )?; + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let serial_number_bytes = &bytes[32..64].try_into().unwrap(); let response_serial_number = try_deserialize_scalar( serial_number_bytes, CoconutError::Deserialization("failed to deserialize the serial number".to_string()), )?; + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let binding_number_bytes = &bytes[64..96].try_into().unwrap(); let response_binding_number = try_deserialize_scalar( binding_number_bytes, CoconutError::Deserialization("failed to deserialize the binding number".to_string()), )?; + // safety: bound checked + constant offset + #[allow(clippy::unwrap_used)] let blinder_bytes = bytes[96..].try_into().unwrap(); let response_blinder = try_deserialize_scalar( &blinder_bytes, @@ -512,14 +525,13 @@ impl ProofKappaZeta { #[cfg(test)] mod tests { - use group::Group; - use rand::thread_rng; - + use super::*; use crate::scheme::keygen::keygen; use crate::scheme::setup::setup; use crate::scheme::verification::{compute_kappa, compute_zeta}; - - use super::*; + use crate::tests::helpers::random_scalars_refs; + use group::Group; + use rand::thread_rng; #[test] fn proof_cm_cs_bytes_roundtrip() { @@ -530,7 +542,7 @@ mod tests { let r = params.random_scalar(); let cms: [G1Projective; 1] = [G1Projective::random(&mut rng)]; let rs = params.n_random_scalars(1); - let private_attributes = params.n_random_scalars(1); + random_scalars_refs!(private_attributes, params, 1); // 0 public 1 private let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]); @@ -546,7 +558,7 @@ mod tests { G1Projective::random(&mut rng), ]; let rs = params.n_random_scalars(2); - let private_attributes = params.n_random_scalars(2); + random_scalars_refs!(private_attributes, params, 2); // 0 public 2 privates let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]); @@ -562,20 +574,20 @@ mod tests { let keypair = keygen(¶ms); // we don't care about 'correctness' of the proof. only whether we can correctly recover it from bytes - let serial_number = params.random_scalar(); - let binding_number = params.random_scalar(); + let serial_number = ¶ms.random_scalar(); + let binding_number = ¶ms.random_scalar(); let private_attributes = vec![serial_number, binding_number]; let r = params.random_scalar(); - let kappa = compute_kappa(¶ms, &keypair.verification_key(), &private_attributes, r); + let kappa = compute_kappa(¶ms, keypair.verification_key(), &private_attributes, r); let zeta = compute_zeta(¶ms, serial_number); // 0 public 2 private let pi_v = ProofKappaZeta::construct( ¶ms, - &keypair.verification_key(), - &serial_number, - &binding_number, + keypair.verification_key(), + serial_number, + binding_number, &r, &kappa, &zeta, @@ -592,9 +604,9 @@ mod tests { let pi_v = ProofKappaZeta::construct( ¶ms, - &keypair.verification_key(), - &serial_number, - &binding_number, + keypair.verification_key(), + serial_number, + binding_number, &r, &kappa, &zeta, diff --git a/common/nymcoconut/src/scheme/aggregation.rs b/common/nymcoconut/src/scheme/aggregation.rs index e41beb8d36..3ff5f93bc2 100644 --- a/common/nymcoconut/src/scheme/aggregation.rs +++ b/common/nymcoconut/src/scheme/aggregation.rs @@ -83,7 +83,7 @@ pub fn aggregate_verification_keys( pub fn aggregate_signatures( params: &Parameters, verification_key: &VerificationKey, - attributes: &[Attribute], + attributes: &[&Attribute], signatures: &[PartialSignature], indices: Option<&[SignerIndex]>, ) -> Result { @@ -100,7 +100,7 @@ pub fn aggregate_signatures( let tmp = attributes .iter() .zip(verification_key.beta_g2.iter()) - .map(|(attr, beta_i)| beta_i * attr) + .map(|(&attr, beta_i)| beta_i * attr) .sum::(); if !check_bilinear_pairing( @@ -119,7 +119,7 @@ pub fn aggregate_signatures( pub fn aggregate_signature_shares( params: &Parameters, verification_key: &VerificationKey, - attributes: &[Attribute], + attributes: &[&Attribute], shares: &[SignatureShare], ) -> Result { let (signatures, indices): (Vec<_>, Vec<_>) = shares @@ -138,13 +138,13 @@ pub fn aggregate_signature_shares( #[cfg(test)] mod tests { - use bls12_381::G1Projective; - use group::Group; - use crate::scheme::issuance::sign; use crate::scheme::keygen::ttp_keygen; use crate::scheme::setup::Parameters; use crate::scheme::verification::verify; + use crate::tests::helpers::random_scalars_refs; + use bls12_381::G1Projective; + use group::Group; use super::*; @@ -155,7 +155,7 @@ mod tests { let vks = keypairs .into_iter() - .map(|keypair| keypair.verification_key()) + .map(|keypair| keypair.verification_key().clone()) .collect::>(); let aggr_vk1 = aggregate_verification_keys(&vks[..3], Some(&[1, 2, 3])).unwrap(); @@ -212,13 +212,18 @@ mod tests { #[test] fn signature_aggregation_works_for_any_subset_of_signatures() { let mut params = Parameters::new(2).unwrap(); - let attributes = params.n_random_scalars(2); + random_scalars_refs!(attributes, params, 2); let keypairs = ttp_keygen(¶ms, 3, 5).unwrap(); let (sks, vks): (Vec<_>, Vec<_>) = keypairs .into_iter() - .map(|keypair| (keypair.secret_key(), keypair.verification_key())) + .map(|keypair| { + ( + keypair.secret_key().clone(), + keypair.verification_key().clone(), + ) + }) .unzip(); let sigs = sks @@ -312,12 +317,17 @@ mod tests { fn signature_aggregation_doesnt_work_for_empty_set_of_signatures() { let signatures: Vec = vec![]; let params = Parameters::new(2).unwrap(); - let attributes = params.n_random_scalars(2); + random_scalars_refs!(attributes, params, 2); let keypairs = ttp_keygen(¶ms, 3, 5).unwrap(); let (_, vks): (Vec<_>, Vec<_>) = keypairs .into_iter() - .map(|keypair| (keypair.secret_key(), keypair.verification_key())) + .map(|keypair| { + ( + keypair.secret_key().clone(), + keypair.verification_key().clone(), + ) + }) .unzip(); let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap(); @@ -330,11 +340,16 @@ mod tests { fn signature_aggregation_doesnt_work_if_indices_have_invalid_length() { let signatures = vec![random_signature()]; let params = Parameters::new(2).unwrap(); - let attributes = params.n_random_scalars(2); + random_scalars_refs!(attributes, params, 2); let keypairs = ttp_keygen(¶ms, 3, 5).unwrap(); let (_, vks): (Vec<_>, Vec<_>) = keypairs .into_iter() - .map(|keypair| (keypair.secret_key(), keypair.verification_key())) + .map(|keypair| { + ( + keypair.secret_key().clone(), + keypair.verification_key().clone(), + ) + }) .unzip(); let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap(); @@ -356,11 +371,16 @@ mod tests { fn signature_aggregation_doesnt_work_for_non_unique_indices() { let signatures = vec![random_signature(), random_signature()]; let params = Parameters::new(2).unwrap(); - let attributes = params.n_random_scalars(2); + random_scalars_refs!(attributes, params, 2); let keypairs = ttp_keygen(¶ms, 3, 5).unwrap(); let (_, vks): (Vec<_>, Vec<_>) = keypairs .into_iter() - .map(|keypair| (keypair.secret_key(), keypair.verification_key())) + .map(|keypair| { + ( + keypair.secret_key().clone(), + keypair.verification_key().clone(), + ) + }) .unzip(); let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap(); diff --git a/common/nymcoconut/src/scheme/double_use.rs b/common/nymcoconut/src/scheme/double_use.rs index f952938a72..ce3cf58d67 100644 --- a/common/nymcoconut/src/scheme/double_use.rs +++ b/common/nymcoconut/src/scheme/double_use.rs @@ -25,6 +25,8 @@ impl TryFrom<&[u8]> for BlindedSerialNumber { )); } + // safety: we've just made a check for 96 bytes + #[allow(clippy::unwrap_used)] let inner = try_deserialize_g2_projective( &bytes.try_into().unwrap(), CoconutError::Deserialization( diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index 1109dfe890..11d0dcb35b 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -54,6 +54,8 @@ impl TryFrom<&[u8]> for BlindSignRequest { let commitment_bytes_len = 48; let commitment_hash_bytes_len = 48; + // safety: we made bound check and we're using constant offest + #[allow(clippy::unwrap_used)] let cm_bytes = bytes[..j + commitment_bytes_len].try_into().unwrap(); let commitment = try_deserialize_g1_projective( &cm_bytes, @@ -63,6 +65,8 @@ impl TryFrom<&[u8]> for BlindSignRequest { )?; j += commitment_bytes_len; + // safety: we made bound check and we're using constant offest + #[allow(clippy::unwrap_used)] let cm_hash_bytes = bytes[j..j + commitment_hash_bytes_len].try_into().unwrap(); let commitment_hash = try_deserialize_g1_projective( &cm_hash_bytes, @@ -72,6 +76,8 @@ impl TryFrom<&[u8]> for BlindSignRequest { )?; j += commitment_hash_bytes_len; + // safety: we made bound check and we're using constant offest + #[allow(clippy::unwrap_used)] let c_len = u64::from_le_bytes(bytes[j..j + 8].try_into().unwrap()); j += 8; if bytes[j..].len() < c_len as usize * 48 { @@ -86,6 +92,14 @@ impl TryFrom<&[u8]> for BlindSignRequest { let start = j + i * 48; let end = start + 48; + if bytes.len() < end { + return Err(CoconutError::Deserialization( + "Failed to deserialize compressed commitment".to_string(), + )); + } + + // safety: we made bound check and we're using constant offest + #[allow(clippy::unwrap_used)] let private_attributes_commitment_bytes = bytes[start..end].try_into().unwrap(); let private_attributes_commitment = try_deserialize_g1_projective( &private_attributes_commitment_bytes, @@ -137,7 +151,7 @@ impl Bytable for BlindSignRequest { impl Base58 for BlindSignRequest {} impl BlindSignRequest { - fn verify_proof(&self, params: &Parameters, public_attributes: &[Attribute]) -> bool { + fn verify_proof(&self, params: &Parameters, public_attributes: &[&Attribute]) -> bool { self.pi_s.verify( params, &self.commitment, @@ -150,8 +164,8 @@ impl BlindSignRequest { self.commitment_hash } - pub fn get_private_attributes_pedersen_commitments(&self) -> Vec { - self.private_attributes_commitments.clone() + pub fn get_private_attributes_pedersen_commitments(&self) -> &[G1Projective] { + &self.private_attributes_commitments } pub fn to_bytes(&self) -> Vec { @@ -161,12 +175,16 @@ impl BlindSignRequest { pub fn from_bytes(bytes: &[u8]) -> Result { BlindSignRequest::try_from(bytes) } + + pub fn num_private_attributes(&self) -> usize { + self.private_attributes_commitments.len() + } } pub fn compute_attributes_commitment( params: &Parameters, - private_attributes: &[Attribute], - public_attributes: &[Attribute], + private_attributes: &[&Attribute], + public_attributes: &[&Attribute], hs: &[G1Affine], ) -> (Scalar, G1Projective) { let commitment_opening = params.random_scalar(); @@ -187,7 +205,7 @@ pub fn compute_attributes_commitment( pub fn compute_pedersen_commitments_for_private_attributes( params: &Parameters, - private_attributes: &[Attribute], + private_attributes: &[&Attribute], h: &G1Projective, ) -> (Vec, Vec) { // Generate openings for Pedersen commitment for each private attribute @@ -197,13 +215,13 @@ pub fn compute_pedersen_commitments_for_private_attributes( let pedersen_commitments = commitments_openings .iter() .zip(private_attributes.iter()) - .map(|(o_j, m_j)| params.gen1() * o_j + h * m_j) + .map(|(o_j, &m_j)| params.gen1() * o_j + h * m_j) .collect::>(); (commitments_openings, pedersen_commitments) } -pub fn compute_hash(commitment: G1Projective, public_attributes: &[Attribute]) -> G1Projective { +pub fn compute_hash(commitment: G1Projective, public_attributes: &[&Attribute]) -> G1Projective { let mut buff = Vec::new(); buff.extend_from_slice(commitment.to_bytes().as_ref()); for attr in public_attributes { @@ -215,8 +233,8 @@ pub fn compute_hash(commitment: G1Projective, public_attributes: &[Attribute]) - /// Builds cryptographic material required for blind sign. pub fn prepare_blind_sign( params: &Parameters, - private_attributes: &[Attribute], - public_attributes: &[Attribute], + private_attributes: &[&Attribute], + public_attributes: &[&Attribute], ) -> Result<(Vec, BlindSignRequest)> { if private_attributes.is_empty() { return Err(CoconutError::Issuance( @@ -271,7 +289,7 @@ pub fn blind_sign( params: &Parameters, signing_secret_key: &SecretKey, blind_sign_request: &BlindSignRequest, - public_attributes: &[Attribute], + public_attributes: &[&Attribute], ) -> Result { let num_private = blind_sign_request.private_attributes_commitments.len(); let hs = params.gen_hs(); @@ -304,7 +322,7 @@ pub fn blind_sign( let signed_public = h * public_attributes .iter() .zip(signing_secret_key.ys.iter().skip(num_private)) - .map(|(attr, yi)| attr * yi) + .map(|(&attr, yi)| attr * yi) .sum::(); // h ^ x + c[0] ^ y[0] + ... c[m] ^ y[m] + h ^ (pub_m[0] * y[m + 1] + ... + pub_m[n] * y[m + n]) @@ -345,7 +363,7 @@ pub fn blind_sign( pub fn verify_partial_blind_signature( params: &Parameters, blind_sign_request: &BlindSignRequest, - public_attributes: &[Attribute], + public_attributes: &[&Attribute], blind_sig: &BlindedSignature, partial_verification_key: &VerificationKey, ) -> bool { @@ -383,7 +401,7 @@ pub fn verify_partial_blind_signature( } // for each public attribute, add (s^pub_j, beta_{priv + j}) to the miller terms - for (pub_attr, beta_g2) in public_attributes.iter().zip( + for (&pub_attr, beta_g2) in public_attributes.iter().zip( partial_verification_key .beta_g2 .iter() @@ -415,7 +433,7 @@ pub fn verify_partial_blind_signature( pub fn sign( params: &mut Parameters, secret_key: &SecretKey, - public_attributes: &[Attribute], + public_attributes: &[&Attribute], ) -> Result { if public_attributes.len() > secret_key.ys.len() { return Err(CoconutError::IssuanceMaxAttributes { @@ -429,7 +447,7 @@ pub fn sign( // (the python implementation hashes string representation of all attributes onto the curve, // but I think the same can be achieved by just summing the attributes thus avoiding the unnecessary // transformation. If I'm wrong, please correct me.) - let attributes_sum = public_attributes.iter().sum::(); + let attributes_sum = public_attributes.iter().copied().sum::(); let h = hash_g1((params.gen1() * attributes_sum).to_bytes()); // x + m0 * y0 + m1 * y1 + ... mn * yn @@ -437,7 +455,7 @@ pub fn sign( + public_attributes .iter() .zip(secret_key.ys.iter()) - .map(|(m_i, y_i)| m_i * y_i) + .map(|(&m_i, y_i)| m_i * y_i) .sum::(); let sig2 = h * exponent; @@ -448,13 +466,14 @@ pub fn sign( mod tests { use super::*; use crate::scheme::keygen::keygen; + use crate::tests::helpers::random_scalars_refs; #[test] fn blind_sign_request_bytes_roundtrip() { // 0 public and 1 private attribute let params = Parameters::new(1).unwrap(); - let private_attributes = params.n_random_scalars(1); - let public_attributes = params.n_random_scalars(0); + random_scalars_refs!(private_attributes, params, 1); + random_scalars_refs!(public_attributes, params, 0); let (_commitments_openings, lambda) = prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); @@ -467,8 +486,8 @@ mod tests { // 2 public and 2 private attributes let params = Parameters::new(4).unwrap(); - let private_attributes = params.n_random_scalars(2); - let public_attributes = params.n_random_scalars(2); + random_scalars_refs!(private_attributes, params, 2); + random_scalars_refs!(public_attributes, params, 2); let (_commitments_openings, lambda) = prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); @@ -483,8 +502,8 @@ mod tests { #[test] fn successful_verify_partial_blind_signature() { let params = Parameters::new(4).unwrap(); - let private_attributes = params.n_random_scalars(2); - let public_attributes = params.n_random_scalars(2); + random_scalars_refs!(private_attributes, params, 2); + random_scalars_refs!(public_attributes, params, 2); let (_commitments_openings, request) = prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); @@ -492,7 +511,7 @@ mod tests { let validator_keypair = keygen(¶ms); let blind_sig = blind_sign( ¶ms, - &validator_keypair.secret_key(), + validator_keypair.secret_key(), &request, &public_attributes, ) @@ -503,36 +522,35 @@ mod tests { &request, &public_attributes, &blind_sig, - &validator_keypair.verification_key() + validator_keypair.verification_key() )); } #[test] fn successful_verify_partial_blind_signature_no_public_attributes() { let params = Parameters::new(4).unwrap(); - let private_attributes = params.n_random_scalars(2); + random_scalars_refs!(private_attributes, params, 2); let (_commitments_openings, request) = prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); let validator_keypair = keygen(¶ms); - let blind_sig = - blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); + let blind_sig = blind_sign(¶ms, validator_keypair.secret_key(), &request, &[]).unwrap(); assert!(verify_partial_blind_signature( ¶ms, &request, &[], &blind_sig, - &validator_keypair.verification_key() + validator_keypair.verification_key() )); } #[test] fn fail_verify_partial_blind_signature_with_wrong_key() { let params = Parameters::new(4).unwrap(); - let private_attributes = params.n_random_scalars(2); - let public_attributes = params.n_random_scalars(2); + random_scalars_refs!(private_attributes, params, 2); + random_scalars_refs!(public_attributes, params, 2); let (_commitments_openings, request) = prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); @@ -541,7 +559,7 @@ mod tests { let validator2_keypair = keygen(¶ms); let blind_sig = blind_sign( ¶ms, - &validator_keypair.secret_key(), + validator_keypair.secret_key(), &request, &public_attributes, ) @@ -553,7 +571,7 @@ mod tests { &request, &public_attributes, &blind_sig, - &validator2_keypair.verification_key() + validator2_keypair.verification_key() ),); } } diff --git a/common/nymcoconut/src/scheme/keygen.rs b/common/nymcoconut/src/scheme/keygen.rs index 352d704193..d033d8f0be 100644 --- a/common/nymcoconut/src/scheme/keygen.rs +++ b/common/nymcoconut/src/scheme/keygen.rs @@ -23,8 +23,12 @@ use crate::utils::{ }; use crate::Base58; -#[derive(Debug, Clone)] -#[cfg_attr(test, derive(PartialEq, Eq))] +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq, Eq, Clone))] +#[cfg_attr( + feature = "key-zeroize", + derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop) +)] pub struct SecretKey { pub(crate) x: Scalar, pub(crate) ys: Vec, @@ -62,7 +66,9 @@ impl TryFrom<&[u8]> for SecretKey { } // this conversion will not fail as we are taking the same length of data + #[allow(clippy::unwrap_used)] let x_bytes: [u8; 32] = bytes[..32].try_into().unwrap(); + #[allow(clippy::unwrap_used)] let ys_len = u64::from_le_bytes(bytes[32..40].try_into().unwrap()); let actual_ys_len = (bytes.len() - 40) / 32; @@ -97,6 +103,10 @@ impl SecretKey { (self.x, self.ys.clone()) } + pub fn size(&self) -> usize { + self.ys.len() + } + /// Derive verification key using this secret key. pub fn verification_key(&self, params: &Parameters) -> VerificationKey { let g1 = params.gen1(); @@ -141,6 +151,10 @@ impl Base58 for SecretKey {} // TODO: perhaps change points to affine representation // to make verification slightly more efficient? #[derive(Debug, PartialEq, Eq, Clone)] +#[cfg_attr( + feature = "key-zeroize", + derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop) +)] pub struct VerificationKey { // TODO add gen2 as per the paper or imply it from the fact library is using bls381? pub(crate) alpha: G2Projective, @@ -180,7 +194,9 @@ impl TryFrom<&[u8]> for VerificationKey { } // this conversion will not fail as we are taking the same length of data + #[allow(clippy::unwrap_used)] let alpha_bytes: [u8; 96] = bytes[..96].try_into().unwrap(); + #[allow(clippy::unwrap_used)] let betas_len = u64::from_le_bytes(bytes[96..104].try_into().unwrap()); let actual_betas_len = (bytes.len() - 104) / (96 + 48); @@ -204,6 +220,8 @@ impl TryFrom<&[u8]> for VerificationKey { for i in 0..betas_len { let start = (104 + i * 48) as usize; let end = start + 48; + // we're using a constant 48 byte offset (which is the size of G1 compressed) so unwrap is fine + #[allow(clippy::unwrap_used)] let beta_i_bytes = bytes[start..end].try_into().unwrap(); let beta_i = try_deserialize_g1_projective( &beta_i_bytes, @@ -220,6 +238,8 @@ impl TryFrom<&[u8]> for VerificationKey { for i in 0..betas_len { let start = (beta_g1_end + i * 96) as usize; let end = start + 96; + // we're using a constant 96 byte offset (which is the size of G2 compressed) so unwrap is fine + #[allow(clippy::unwrap_used)] let beta_i_bytes = bytes[start..end].try_into().unwrap(); let beta_i = try_deserialize_g2_projective( &beta_i_bytes, @@ -392,7 +412,11 @@ impl Bytable for VerificationKey { impl Base58 for VerificationKey {} #[derive(Debug, Serialize, Deserialize)] -#[cfg_attr(test, derive(PartialEq, Eq))] +#[cfg_attr(test, derive(PartialEq, Eq, Clone))] +#[cfg_attr( + feature = "key-zeroize", + derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop) +)] pub struct KeyPair { secret_key: SecretKey, verification_key: VerificationKey, @@ -429,12 +453,12 @@ impl KeyPair { } } - pub fn secret_key(&self) -> SecretKey { - self.secret_key.clone() + pub fn secret_key(&self) -> &SecretKey { + &self.secret_key } - pub fn verification_key(&self) -> VerificationKey { - self.verification_key.clone() + pub fn verification_key(&self) -> &VerificationKey { + &self.verification_key } pub fn to_bytes(&self) -> Vec { @@ -488,6 +512,8 @@ impl TryFrom<&[u8]> for KeyPair { }); } + // safety: we made bound check and we're using constant offest + #[allow(clippy::unwrap_used)] let secret_key_len = u64::from_le_bytes(bytes[header_len..header_len + 8].try_into().unwrap()) as usize; let secret_key_start = header_len + 8; @@ -503,6 +529,8 @@ impl TryFrom<&[u8]> for KeyPair { }); } + // safety: we made bound check + #[allow(clippy::unwrap_used)] let verification_key_len = u64::from_le_bytes( bytes[secret_key_start + secret_key_len..secret_key_start + secret_key_len + 8] .try_into() @@ -515,6 +543,7 @@ impl TryFrom<&[u8]> for KeyPair { )?; let consumed_bytes = verification_key_start + verification_key_len; let index = if consumed_bytes < bytes.len() && [consumed_bytes..].len() == 8 { + #[allow(clippy::unwrap_used)] Some(u64::from_le_bytes( bytes[consumed_bytes..consumed_bytes + 8] .try_into() diff --git a/common/nymcoconut/src/scheme/mod.rs b/common/nymcoconut/src/scheme/mod.rs index 9e642716ca..68dd0d2b9a 100644 --- a/common/nymcoconut/src/scheme/mod.rs +++ b/common/nymcoconut/src/scheme/mod.rs @@ -44,7 +44,10 @@ impl TryFrom<&[u8]> for Signature { ))); } + // safety: we just checked for the length so the unwraps are fine + #[allow(clippy::expect_used)] let sig1_bytes: &[u8; 48] = &bytes[..48].try_into().expect("Slice size != 48"); + #[allow(clippy::expect_used)] let sig2_bytes: &[u8; 48] = &bytes[48..].try_into().expect("Slice size != 48"); let sig1 = try_deserialize_g1_projective( @@ -88,6 +91,45 @@ impl Signature { pub fn from_bytes(bytes: &[u8]) -> Result { Signature::try_from(bytes) } + + pub fn verify( + &self, + params: &Parameters, + partial_verification_key: &VerificationKey, + private_attributes: &[&Attribute], + public_attributes: &[&Attribute], + commitment_hash: &G1Projective, + ) -> Result<()> { + // Verify the commitment hash + if !(commitment_hash == &self.0) { + return Err(CoconutError::Verification( + "Verification of commitment hash from signature failed".to_string(), + )); + } + + let alpha = partial_verification_key.alpha; + + let signed_attributes = private_attributes + .iter() + .chain(public_attributes.iter()) + .zip(partial_verification_key.beta_g2.iter()) + .map(|(&attr, beta_i)| beta_i * attr) + .sum::(); + + // Verify the signature share + if !check_bilinear_pairing( + &self.0.to_affine(), + &G2Prepared::from((alpha + signed_attributes).to_affine()), + &self.1.to_affine(), + params.prepared_miller_g2(), + ) { + return Err(CoconutError::Unblind( + "Verification of signature share failed".to_string(), + )); + } + + Ok(()) + } } impl Bytable for Signature { @@ -102,8 +144,7 @@ impl Bytable for Signature { impl Base58 for Signature {} -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq, Eq))] +#[derive(Debug, PartialEq, Eq)] pub struct BlindedSignature(G1Projective, G1Projective); impl Bytable for BlindedSignature { @@ -129,7 +170,10 @@ impl TryFrom<&[u8]> for BlindedSignature { ))); } + // safety: we just checked for the length so the unwraps are fine + #[allow(clippy::expect_used)] let h_bytes: &[u8; 48] = &bytes[..48].try_into().expect("Slice size != 48"); + #[allow(clippy::expect_used)] let sig_bytes: &[u8; 48] = &bytes[48..].try_into().expect("Slice size != 48"); let h = try_deserialize_g1_projective( @@ -148,24 +192,12 @@ impl TryFrom<&[u8]> for BlindedSignature { impl BlindedSignature { pub fn unblind( &self, - params: &Parameters, partial_verification_key: &VerificationKey, - private_attributes: &[Attribute], - public_attributes: &[Attribute], - commitment_hash: &G1Projective, pedersen_commitments_openings: &[Scalar], ) -> Result { // parse the signature let h = &self.0; let c = &self.1; - - // Verify the commitment hash - if !(commitment_hash == h) { - return Err(CoconutError::Unblind( - "Verification of commitment hash from signature failed".to_string(), - )); - } - let blinding_removers = partial_verification_key .beta_g1 .iter() @@ -175,30 +207,29 @@ impl BlindedSignature { let unblinded_c = c - blinding_removers; - let alpha = partial_verification_key.alpha; - - let signed_attributes = private_attributes - .iter() - .chain(public_attributes.iter()) - .zip(partial_verification_key.beta_g2.iter()) - .map(|(attr, beta_i)| beta_i * attr) - .sum::(); - - // Verify the signature share - if !check_bilinear_pairing( - &h.to_affine(), - &G2Prepared::from((alpha + signed_attributes).to_affine()), - &unblinded_c.to_affine(), - params.prepared_miller_g2(), - ) { - return Err(CoconutError::Unblind( - "Verification of signature share failed".to_string(), - )); - } - Ok(Signature(*h, unblinded_c)) } + pub fn unblind_and_verify( + &self, + params: &Parameters, + partial_verification_key: &VerificationKey, + private_attributes: &[&Attribute], + public_attributes: &[&Attribute], + commitment_hash: &G1Projective, + pedersen_commitments_openings: &[Scalar], + ) -> Result { + let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings)?; + unblinded.verify( + params, + partial_verification_key, + private_attributes, + public_attributes, + commitment_hash, + )?; + Ok(unblinded) + } + pub fn to_bytes(&self) -> [u8; 96] { let mut bytes = [0u8; 96]; bytes[..48].copy_from_slice(&self.0.to_affine().to_compressed()); @@ -237,25 +268,25 @@ impl SignatureShare { #[cfg(test)] mod tests { + use super::*; use crate::hash_to_scalar; use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys}; use crate::scheme::issuance::{blind_sign, compute_hash, prepare_blind_sign, sign}; use crate::scheme::keygen::{keygen, ttp_keygen}; use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential}; - - use super::*; + use crate::tests::helpers::random_scalars_refs; #[test] fn unblind_returns_error_if_integrity_check_on_commitment_hash_fails() { let params = Parameters::new(2).unwrap(); - let private_attributes = params.n_random_scalars(2_usize); + random_scalars_refs!(private_attributes, params, 2); let (_commitments_openings, lambda) = prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); let keypair1 = keygen(¶ms); - let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &[]).unwrap(); + let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &[]).unwrap(); let wrong_commitment_opening = params.random_scalar(); let wrong_commitment = params.gen1() * wrong_commitment_opening; @@ -263,9 +294,9 @@ mod tests { let wrong_commitments_openings = params.n_random_scalars(private_attributes.len()); assert!(sig1 - .unblind( + .unblind_and_verify( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &private_attributes, &[], &fake_commitment_hash, @@ -277,20 +308,23 @@ mod tests { #[test] fn unblind_returns_error_if_signature_verification_fails() { let params = Parameters::new(2).unwrap(); - let private_attributes = vec![hash_to_scalar("Attribute1"), hash_to_scalar("Attribute2")]; - let private_attributes2 = vec![hash_to_scalar("Attribute3"), hash_to_scalar("Attribute4")]; + let p = [hash_to_scalar("Attribute1"), hash_to_scalar("Attribute2")]; + let private_attributes = vec![&p[0], &p[1]]; + + let p2 = [hash_to_scalar("Attribute3"), hash_to_scalar("Attribute4")]; + let private_attributes2 = vec![&p2[0], &p2[1]]; let (commitments_openings, lambda) = prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); let keypair1 = keygen(¶ms); - let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &[]).unwrap(); + let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &[]).unwrap(); assert!(sig1 - .unblind( + .unblind_and_verify( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &private_attributes2, &[], &lambda.get_commitment_hash(), @@ -304,7 +338,7 @@ mod tests { let params = Parameters::new(2).unwrap(); let serial_number = params.random_scalar(); let binding_number = params.random_scalar(); - let private_attributes = vec![serial_number, binding_number]; + let private_attributes = vec![&serial_number, &binding_number]; let keypair1 = keygen(¶ms); let keypair2 = keygen(¶ms); @@ -312,11 +346,11 @@ mod tests { let (commitments_openings, lambda) = prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); - let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &[]) + let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &[]) .unwrap() - .unblind( + .unblind_and_verify( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &private_attributes, &[], &lambda.get_commitment_hash(), @@ -324,11 +358,11 @@ mod tests { ) .unwrap(); - let sig2 = blind_sign(¶ms, &keypair2.secret_key(), &lambda, &[]) + let sig2 = blind_sign(¶ms, keypair2.secret_key(), &lambda, &[]) .unwrap() - .unblind( + .unblind_and_verify( ¶ms, - &keypair2.verification_key(), + keypair2.verification_key(), &private_attributes, &[], &lambda.get_commitment_hash(), @@ -338,39 +372,39 @@ mod tests { let theta1 = prove_bandwidth_credential( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &sig1, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap(); let theta2 = prove_bandwidth_credential( ¶ms, - &keypair2.verification_key(), + keypair2.verification_key(), &sig2, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap(); assert!(verify_credential( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &theta1, &[], )); assert!(verify_credential( ¶ms, - &keypair2.verification_key(), + keypair2.verification_key(), &theta2, &[], )); assert!(!verify_credential( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &theta2, &[], )); @@ -379,30 +413,30 @@ mod tests { #[test] fn verification_on_two_public_attributes() { let mut params = Parameters::new(2).unwrap(); - let attributes = params.n_random_scalars(2); + random_scalars_refs!(attributes, params, 2); let keypair1 = keygen(¶ms); let keypair2 = keygen(¶ms); - let sig1 = sign(&mut params, &keypair1.secret_key(), &attributes).unwrap(); - let sig2 = sign(&mut params, &keypair2.secret_key(), &attributes).unwrap(); + let sig1 = sign(&mut params, keypair1.secret_key(), &attributes).unwrap(); + let sig2 = sign(&mut params, keypair2.secret_key(), &attributes).unwrap(); assert!(verify( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &attributes, &sig1, )); assert!(!verify( ¶ms, - &keypair2.verification_key(), + keypair2.verification_key(), &attributes, &sig1, )); assert!(!verify( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &attributes, &sig2, )); @@ -411,10 +445,11 @@ mod tests { #[test] fn verification_on_two_public_and_two_private_attributes() { let params = Parameters::new(4).unwrap(); - let public_attributes = params.n_random_scalars(2); + random_scalars_refs!(public_attributes, params, 2); + let serial_number = params.random_scalar(); let binding_number = params.random_scalar(); - let private_attributes = vec![serial_number, binding_number]; + let private_attributes = vec![&serial_number, &binding_number]; let keypair1 = keygen(¶ms); let keypair2 = keygen(¶ms); @@ -422,11 +457,11 @@ mod tests { let (commitments_openings, lambda) = prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); - let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &public_attributes) + let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &public_attributes) .unwrap() - .unblind( + .unblind_and_verify( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &private_attributes, &public_attributes, &lambda.get_commitment_hash(), @@ -434,11 +469,11 @@ mod tests { ) .unwrap(); - let sig2 = blind_sign(¶ms, &keypair2.secret_key(), &lambda, &public_attributes) + let sig2 = blind_sign(¶ms, keypair2.secret_key(), &lambda, &public_attributes) .unwrap() - .unblind( + .unblind_and_verify( ¶ms, - &keypair2.verification_key(), + keypair2.verification_key(), &private_attributes, &public_attributes, &lambda.get_commitment_hash(), @@ -448,39 +483,39 @@ mod tests { let theta1 = prove_bandwidth_credential( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &sig1, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap(); let theta2 = prove_bandwidth_credential( ¶ms, - &keypair2.verification_key(), + keypair2.verification_key(), &sig2, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap(); assert!(verify_credential( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &theta1, &public_attributes, )); assert!(verify_credential( ¶ms, - &keypair2.verification_key(), + keypair2.verification_key(), &theta2, &public_attributes, )); assert!(!verify_credential( ¶ms, - &keypair1.verification_key(), + keypair1.verification_key(), &theta2, &public_attributes, )); @@ -489,10 +524,11 @@ mod tests { #[test] fn verification_on_two_public_and_two_private_attributes_from_two_signers() { let params = Parameters::new(4).unwrap(); - let public_attributes = params.n_random_scalars(2); + random_scalars_refs!(public_attributes, params, 2); + let serial_number = params.random_scalar(); let binding_number = params.random_scalar(); - let private_attributes = vec![serial_number, binding_number]; + let private_attributes = vec![&serial_number, &binding_number]; let keypairs = ttp_keygen(¶ms, 2, 3).unwrap(); @@ -502,11 +538,11 @@ mod tests { let sigs = keypairs .iter() .map(|keypair| { - blind_sign(¶ms, &keypair.secret_key(), &lambda, &public_attributes) + blind_sign(¶ms, keypair.secret_key(), &lambda, &public_attributes) .unwrap() - .unblind( + .unblind_and_verify( ¶ms, - &keypair.verification_key(), + keypair.verification_key(), &private_attributes, &public_attributes, &lambda.get_commitment_hash(), @@ -518,7 +554,7 @@ mod tests { let vks = keypairs .into_iter() - .map(|keypair| keypair.verification_key()) + .map(|keypair| keypair.verification_key().clone()) .collect::>(); let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len()); @@ -530,9 +566,14 @@ mod tests { aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[..2], Some(&[1, 2])) .unwrap(); - let theta = - prove_bandwidth_credential(¶ms, &aggr_vk, &aggr_sig, serial_number, binding_number) - .unwrap(); + let theta = prove_bandwidth_credential( + ¶ms, + &aggr_vk, + &aggr_sig, + &serial_number, + &binding_number, + ) + .unwrap(); assert!(verify_credential( ¶ms, @@ -547,9 +588,14 @@ mod tests { aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[1..], Some(&[2, 3])) .unwrap(); - let theta = - prove_bandwidth_credential(¶ms, &aggr_vk, &aggr_sig, serial_number, binding_number) - .unwrap(); + let theta = prove_bandwidth_credential( + ¶ms, + &aggr_vk, + &aggr_sig, + &serial_number, + &binding_number, + ) + .unwrap(); assert!(verify_credential( ¶ms, diff --git a/common/nymcoconut/src/scheme/verification.rs b/common/nymcoconut/src/scheme/verification.rs index 96ef28e9ca..0addda985a 100644 --- a/common/nymcoconut/src/scheme/verification.rs +++ b/common/nymcoconut/src/scheme/verification.rs @@ -43,6 +43,8 @@ impl TryFrom<&[u8]> for Theta { )); } + // safety: we just checked for the length so the unwraps are fine + #[allow(clippy::unwrap_used)] let blinded_message_bytes = bytes[..96].try_into().unwrap(); let blinded_message = try_deserialize_g2_projective( &blinded_message_bytes, @@ -51,6 +53,8 @@ impl TryFrom<&[u8]> for Theta { ), )?; + // safety: we just checked for the length so the unwraps are fine + #[allow(clippy::unwrap_used)] let blinded_serial_number_bytes = bytes[96..192].try_into().unwrap(); let blinded_serial_number = try_deserialize_g2_projective( &blinded_serial_number_bytes, @@ -130,7 +134,7 @@ impl Base58 for Theta {} pub fn compute_kappa( params: &Parameters, verification_key: &VerificationKey, - private_attributes: &[Attribute], + private_attributes: &[&Attribute], blinding_factor: Scalar, ) -> G2Projective { params.gen2() * blinding_factor @@ -138,11 +142,11 @@ pub fn compute_kappa( + private_attributes .iter() .zip(verification_key.beta_g2.iter()) - .map(|(priv_attr, beta_i)| beta_i * priv_attr) + .map(|(&priv_attr, beta_i)| beta_i * priv_attr) .sum::() } -pub fn compute_zeta(params: &Parameters, serial_number: Attribute) -> G2Projective { +pub fn compute_zeta(params: &Parameters, serial_number: &Attribute) -> G2Projective { params.gen2() * serial_number } @@ -150,8 +154,8 @@ pub fn prove_bandwidth_credential( params: &Parameters, verification_key: &VerificationKey, signature: &Signature, - serial_number: Attribute, - binding_number: Attribute, + serial_number: &Attribute, + binding_number: &Attribute, ) -> Result { if verification_key.beta_g2.len() < 2 { return Err( @@ -171,7 +175,7 @@ pub fn prove_bandwidth_credential( // Thus, we need kappa which allows us to verify sigma'. In particular, // kappa is computed on m as input, but thanks to the use or random value r, // it does not reveal any information about m. - let private_attributes = vec![serial_number, binding_number]; + let private_attributes = [serial_number, binding_number]; let blinded_message = compute_kappa( params, verification_key, @@ -185,8 +189,8 @@ pub fn prove_bandwidth_credential( let pi_v = ProofKappaZeta::construct( params, verification_key, - &serial_number, - &binding_number, + serial_number, + binding_number, &sign_blinding_factor, &blinded_message, &blinded_serial_number, @@ -221,7 +225,10 @@ pub fn check_vk_pairing( if values_len == 0 || values_len - 1 != vk.beta_g1.len() || values_len - 1 != vk.beta_g2.len() { return false; } - if vk.alpha != *dkg_values.last().unwrap() { + + // safety: we made an explicit check for if the length of the slice is 0, thus unwrap here is fine + #[allow(clippy::unwrap_used)] + if &vk.alpha != *dkg_values.last().as_ref().unwrap() { return false; } if dkg_values @@ -249,7 +256,7 @@ pub fn verify_credential( params: &Parameters, verification_key: &VerificationKey, theta: &Theta, - public_attributes: &[Attribute], + public_attributes: &[&Attribute], ) -> bool { if public_attributes.len() + theta.pi_v.private_attributes_len() > verification_key.beta_g2.len() @@ -272,7 +279,7 @@ pub fn verify_credential( .iter() .skip(theta.pi_v.private_attributes_len()), ) - .map(|(pub_attr, beta_i)| beta_i * pub_attr) + .map(|(&pub_attr, beta_i)| beta_i * pub_attr) .sum::(); theta.blinded_message + signed_public_attributes @@ -291,14 +298,14 @@ pub fn verify_credential( pub fn verify( params: &Parameters, verification_key: &VerificationKey, - public_attributes: &[Attribute], + public_attributes: &[&Attribute], sig: &Signature, ) -> bool { let kappa = (verification_key.alpha + public_attributes .iter() .zip(verification_key.beta_g2.iter()) - .map(|(m_i, b_i)| b_i * m_i) + .map(|(&m_i, b_i)| b_i * m_i) .sum::()) .to_affine(); @@ -320,10 +327,11 @@ mod tests { #[test] fn vk_pairing() { let params = setup(2).unwrap(); - let vk = keygen(¶ms).verification_key(); + let keypair = keygen(¶ms); + let vk = keypair.verification_key(); let mut dkg_values = vk.beta_g2.clone(); dkg_values.push(vk.alpha); - assert!(check_vk_pairing(¶ms, &dkg_values, &vk)); + assert!(check_vk_pairing(¶ms, &dkg_values, vk)); } #[test] @@ -340,10 +348,10 @@ mod tests { let theta = prove_bandwidth_credential( ¶ms, - &keypair.verification_key(), + keypair.verification_key(), &signature, - serial_number, - binding_number, + &serial_number, + &binding_number, ) .unwrap(); diff --git a/common/nymcoconut/src/tests/e2e.rs b/common/nymcoconut/src/tests/e2e.rs index db950d0c3f..b9cc397845 100644 --- a/common/nymcoconut/src/tests/e2e.rs +++ b/common/nymcoconut/src/tests/e2e.rs @@ -1,6 +1,7 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::random_scalars_refs; use crate::tests::helpers::tests::generate_dkg_keys; use crate::{ aggregate_verification_keys, setup, tests::helpers::*, ttp_keygen, verify_credential, @@ -12,14 +13,14 @@ fn keygen() -> Result<(), CoconutError> { let params = setup(5)?; let node_indices = vec![15u64, 248, 33521]; - let public_attributes = params.n_random_scalars(2); + random_scalars_refs!(public_attributes, params, 2); // generate_keys let coconut_keypairs = ttp_keygen(¶ms, 2, 3)?; let verification_keys: Vec = coconut_keypairs .iter() - .map(|keypair| keypair.verification_key()) + .map(|keypair| keypair.verification_key().clone()) .collect(); // aggregate verification keys @@ -50,14 +51,14 @@ fn dkg() -> Result<(), CoconutError> { let params = setup(5)?; let node_indices = vec![15u64, 248, 33521]; - let public_attributes = params.n_random_scalars(2); + random_scalars_refs!(public_attributes, params, 2); // generate_keys let coconut_keypairs = generate_dkg_keys(5, &node_indices); let verification_keys: Vec = coconut_keypairs .iter() - .map(|keypair| keypair.verification_key()) + .map(|keypair| keypair.verification_key().clone()) .collect(); // aggregate verification keys diff --git a/common/nymcoconut/src/tests/helpers.rs b/common/nymcoconut/src/tests/helpers.rs index a432cecd60..61c4531903 100644 --- a/common/nymcoconut/src/tests/helpers.rs +++ b/common/nymcoconut/src/tests/helpers.rs @@ -5,15 +5,17 @@ use crate::*; use itertools::izip; use std::fmt::Debug; +// unwraps are fine in the test code +#[allow(clippy::unwrap_used)] pub fn theta_from_keys_and_attributes( params: &Parameters, coconut_keypairs: &Vec, indices: &[scheme::SignerIndex], - public_attributes: &Vec, + public_attributes: &[&PublicAttribute], ) -> Result { let serial_number = params.random_scalar(); let binding_number = params.random_scalar(); - let private_attributes = vec![serial_number, binding_number]; + let private_attributes = vec![&serial_number, &binding_number]; // generate commitment let (commitments_openings, blind_sign_request) = @@ -21,7 +23,7 @@ pub fn theta_from_keys_and_attributes( let verification_keys: Vec = coconut_keypairs .iter() - .map(|keypair| keypair.verification_key()) + .map(|keypair| keypair.verification_key().clone()) .collect(); // aggregate verification keys @@ -33,7 +35,7 @@ pub fn theta_from_keys_and_attributes( for keypair in coconut_keypairs { let blinded_signature = blind_sign( params, - &keypair.secret_key(), + keypair.secret_key(), &blind_sign_request, public_attributes, )?; @@ -49,7 +51,7 @@ pub fn theta_from_keys_and_attributes( .map(|(idx, s, vk)| { ( *idx, - s.unblind( + s.unblind_and_verify( params, vk, &private_attributes, @@ -81,13 +83,15 @@ pub fn theta_from_keys_and_attributes( params, &verification_key, &signature, - serial_number, - binding_number, + &serial_number, + &binding_number, )?; Ok(theta) } +// unwraps are fine in the test code +#[allow(clippy::unwrap_used)] pub fn transpose_matrix(matrix: Vec>) -> Vec> { if matrix.is_empty() { return vec![]; @@ -166,3 +170,14 @@ pub mod tests { .collect() } } + +#[macro_export] +macro_rules! random_scalars_refs { + ( $x: ident, $params: expr, $n: expr ) => { + let _vec = $params.n_random_scalars($n); + #[allow(clippy::map_identity)] + let $x = _vec.iter().collect::>(); + }; +} + +pub use random_scalars_refs; diff --git a/common/nymcoconut/src/traits.rs b/common/nymcoconut/src/traits.rs index a800388f88..d521b133ac 100644 --- a/common/nymcoconut/src/traits.rs +++ b/common/nymcoconut/src/traits.rs @@ -1,4 +1,13 @@ +// Copyright 2021-2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +#![warn(clippy::expect_used)] +#![warn(clippy::unwrap_used)] + use crate::CoconutError; +use bls12_381::{G1Affine, G1Projective, Scalar}; +use group::GroupEncoding; +use std::convert::TryInto; pub trait Bytable where @@ -14,9 +23,67 @@ where Self: Bytable, { fn try_from_bs58>(x: S) -> Result { - Self::try_from_byte_slice(&bs58::decode(x.as_ref()).into_vec().unwrap()) + let bs58_decoded = &bs58::decode(x.as_ref()).into_vec()?; + Self::try_from_byte_slice(bs58_decoded) } fn to_bs58(&self) -> String { bs58::encode(self.to_byte_vec()).into_string() } } + +impl Bytable for Scalar { + fn to_byte_vec(&self) -> Vec { + self.to_bytes().to_vec() + } + + fn try_from_byte_slice(slice: &[u8]) -> Result { + let received = slice.len(); + let Ok(arr) = slice.try_into() else { + return Err(CoconutError::UnexpectedArrayLength { + typ: "Scalar".to_string(), + received, + expected: 32, + }); + }; + + let maybe_scalar = Scalar::from_bytes(arr); + if maybe_scalar.is_none().into() { + Err(CoconutError::ScalarDeserializationFailure) + } else { + // safety: this unwrap is fine as we've just checked the element is not none + #[allow(clippy::unwrap_used)] + Ok(maybe_scalar.unwrap()) + } + } +} + +impl Base58 for Scalar {} + +impl Bytable for G1Projective { + fn to_byte_vec(&self) -> Vec { + self.to_bytes().as_ref().to_vec() + } + + fn try_from_byte_slice(slice: &[u8]) -> Result { + let received = slice.len(); + let arr: Result<[u8; 48], _> = slice.try_into(); + let Ok(bytes) = arr else { + return Err(CoconutError::UnexpectedArrayLength { + typ: "G1Projective".to_string(), + received, + expected: 48, + }); + }; + + let maybe_g1 = G1Affine::from_compressed(&bytes); + if maybe_g1.is_none().into() { + Err(CoconutError::G1ProjectiveDeserializationFailure) + } else { + // safety: this unwrap is fine as we've just checked the element is not none + #[allow(clippy::unwrap_used)] + Ok(maybe_g1.unwrap().into()) + } + } +} + +impl Base58 for G1Projective {} diff --git a/common/nymcoconut/src/utils.rs b/common/nymcoconut/src/utils.rs index 9fec3b334c..c2fcd4da3f 100644 --- a/common/nymcoconut/src/utils.rs +++ b/common/nymcoconut/src/utils.rs @@ -34,6 +34,7 @@ impl Polynomial { // just return the last term of the polynomial } else if x.is_zero().into() { // we checked that coefficients are not empty so unwrap here is fine + #[allow(clippy::unwrap_used)] *self.coefficients.first().unwrap() } else { self.coefficients @@ -148,6 +149,8 @@ pub(crate) fn try_deserialize_scalar_vec( let mut out = Vec::with_capacity(expected_len as usize); for i in 0..expected_len as usize { + // we just checked we have exactly the amount of bytes we need and thus the unwrap is fine + #[allow(clippy::unwrap_used)] let s_bytes = bytes[i * 32..(i + 1) * 32].try_into().unwrap(); let s = match Into::>::into(Scalar::from_bytes(&s_bytes)) { None => return Err(err), diff --git a/common/nymsphinx/framing/Cargo.toml b/common/nymsphinx/framing/Cargo.toml index bf2c030e2e..b62de91f53 100644 --- a/common/nymsphinx/framing/Cargo.toml +++ b/common/nymsphinx/framing/Cargo.toml @@ -9,7 +9,7 @@ repository = { workspace = true } [dependencies] bytes = "1.0" -tokio-util = { version = "0.7.4", features = ["codec"] } +tokio-util = { workspace = true, features = ["codec"] } thiserror = { workspace = true } nym-sphinx-types = { path = "../types", features = ["sphinx", "outfox"] } diff --git a/common/socks5/proxy-helpers/Cargo.toml b/common/socks5/proxy-helpers/Cargo.toml index 6ebaaa03c9..3043d88efd 100644 --- a/common/socks5/proxy-helpers/Cargo.toml +++ b/common/socks5/proxy-helpers/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] bytes = "1.0" -tokio = { version = "1.24.1", features = [ "net", "io-util", "sync", "macros", "time", "rt-multi-thread" ] } -tokio-util = { version = "0.7.4", features = [ "io" ] } # reason for getting this guy is to to able to port to tokio 1.X more quickly by being able to use +tokio = { workspace = true, features = [ "net", "io-util", "sync", "macros", "time", "rt-multi-thread" ] } +tokio-util = { workspace = true, features = [ "io" ] } # reason for getting this guy is to to able to port to tokio 1.X more quickly by being able to use # their `read_buf` [from the util crate] replacement rather than having to rethink/reimplement `AvailableReader` with the new AsyncRead trait definition. # In the long run, the dependency should probably get removed in favour of pure-tokio implementation, but for time being it's fine. futures = { workspace = true } diff --git a/ephemera/Cargo.toml b/ephemera/Cargo.toml index f0af6af3a9..e32fec2746 100644 --- a/ephemera/Cargo.toml +++ b/ephemera/Cargo.toml @@ -47,7 +47,7 @@ serde_json = "1.0.91" thiserror = { workspace = true } tokio = { version = "1", features = ["macros", "net","rt-multi-thread"] } tokio-tungstenite = { workspace = true } -tokio-util = { version = "0.7.4", features = ["full"] } +tokio-util = { workspace = true, features = ["full"] } toml = "0.7.0" unsigned-varint = "0.7.1" utoipa = { workspace = true, features = ["actix_extras"] } diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 285864be20..b2c36ee33c 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -53,7 +53,7 @@ tokio = { workspace = true, features = [ ] } tokio-stream = { version = "0.1.11", features = ["fs"] } tokio-tungstenite = { version = "0.20.1" } -tokio-util = { version = "0.7.4", features = ["codec"] } +tokio-util = { workspace = true, features = ["codec"] } url = { workspace = true, features = ["serde"] } zeroize = { workspace = true } diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index bdcb0b3a9b..1c7997ea92 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -33,8 +33,8 @@ rand = "0.7.3" serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } sysinfo = "0.27.7" -tokio = { version = "1.21.2", features = ["rt-multi-thread", "net", "signal"] } -tokio-util = { version = "0.7.3", features = ["codec"] } +tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } +tokio-util = { workspace = true, features = ["codec"] } toml = "0.5.8" url = { workspace = true, features = ["serde"] } cfg-if = "1.0.0" diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index 243e152d52..cc3b679ef8 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -24,6 +24,7 @@ clap = { workspace = true, features = ["cargo", "derive"] } console-subscriber = { version = "0.1.1", optional = true } # validator-api needs to be built with RUSTFLAGS="--cfg tokio_unstable" dirs = "4.0" futures = { workspace = true } +itertools = "0.12.0" humantime-serde = "1.0" lazy_static = "1.4.0" log = { workspace = true } @@ -97,7 +98,7 @@ nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-co nym-multisig-contract-common = { path = "../common/cosmwasm-smart-contracts/multisig-contract" } nym-service-provider-directory-common = { path = "../common/cosmwasm-smart-contracts/service-provider-directory" } nym-name-service-common = { path = "../common/cosmwasm-smart-contracts/name-service" } -nym-coconut = { path = "../common/nymcoconut" } +nym-coconut = { path = "../common/nymcoconut", features = ["key-zeroize"] } nym-sphinx = { path = "../common/nymsphinx" } nym-pemstore = { path = "../common/pemstore" } nym-task = { path = "../common/task" } diff --git a/nym-api/migrations/20231127120000_partial_credentials_info.sql b/nym-api/migrations/20231127120000_partial_credentials_info.sql new file mode 100644 index 0000000000..1c01a3f30d --- /dev/null +++ b/nym-api/migrations/20231127120000_partial_credentials_info.sql @@ -0,0 +1,28 @@ +/* + * Copyright 2023 - Nym Technologies SA + * SPDX-License-Identifier: GPL-3.0-only + */ + + +DROP TABLE signed_deposit; + +-- represents information about credentials issued in that epoch so that the other parties could make their appropriate queries +-- note: before this information can be returned to a client (of the API), it needs to be signed first +CREATE TABLE epoch_credentials +( + epoch_id INTEGER NOT NULL PRIMARY KEY UNIQUE, + start_id INTEGER NOT NULL, + total_issued INTEGER NOT NULL +); + +-- particular credential issued in this epoch +CREATE TABLE issued_credential +( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + epoch_id INTEGER NOT NULL, + tx_hash VARCHAR NOT NULL UNIQUE, + bs58_partial_credential VARCHAR NOT NULL, + bs58_signature VARCHAR NOT NULL, + joined_private_commitments VARCHAR NOT NULL, + joined_public_attributes VARCHAR NOT NULL +); \ No newline at end of file diff --git a/nym-api/nym-api-requests/Cargo.toml b/nym-api/nym-api-requests/Cargo.toml index d9869bd7ae..edbd00dad3 100644 --- a/nym-api/nym-api-requests/Cargo.toml +++ b/nym-api/nym-api-requests/Cargo.toml @@ -13,8 +13,11 @@ getset = "0.1.1" schemars = { workspace = true, features = ["preserve_order"] } serde = { workspace = true, features = ["derive"] } ts-rs = { workspace = true, optional = true } +tendermint = { workspace = true } nym-coconut-interface = { path = "../../common/coconut-interface" } +nym-crypto = { path = "../../common/crypto", features = ["serde", "asymmetric"]} + nym-mixnet-contract-common = { path= "../../common/cosmwasm-smart-contracts/mixnet-contract" } nym-node-requests = { path = "../../nym-node/nym-node-requests", default-features = false } diff --git a/nym-api/nym-api-requests/src/coconut.rs b/nym-api/nym-api-requests/src/coconut.rs deleted file mode 100644 index 6f79bc2f21..0000000000 --- a/nym-api/nym-api-requests/src/coconut.rs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2022 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use cosmrs::AccountId; -use getset::{CopyGetters, Getters}; -use serde::{Deserialize, Serialize}; - -use nym_coconut_interface::{ - error::CoconutInterfaceError, Attribute, Base58, BlindSignRequest, Credential, VerificationKey, -}; - -#[derive(Serialize, Deserialize, Getters, CopyGetters)] -pub struct VerifyCredentialBody { - #[getset(get = "pub")] - credential: Credential, - #[getset(get = "pub")] - proposal_id: u64, - #[getset(get = "pub")] - gateway_cosmos_addr: AccountId, -} - -impl VerifyCredentialBody { - pub fn new( - credential: Credential, - proposal_id: u64, - gateway_cosmos_addr: AccountId, - ) -> VerifyCredentialBody { - VerifyCredentialBody { - credential, - proposal_id, - gateway_cosmos_addr, - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct VerifyCredentialResponse { - pub verification_result: bool, -} - -impl VerifyCredentialResponse { - pub fn new(verification_result: bool) -> Self { - VerifyCredentialResponse { - verification_result, - } - } -} - -// All strings are base58 encoded representations of structs -#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)] -pub struct BlindSignRequestBody { - #[getset(get = "pub")] - blind_sign_request: BlindSignRequest, - #[getset(get = "pub")] - tx_hash: String, - #[getset(get = "pub")] - signature: String, - public_attributes: Vec, - #[getset(get = "pub")] - public_attributes_plain: Vec, - #[getset(get = "pub")] - total_params: u32, -} - -impl BlindSignRequestBody { - pub fn new( - blind_sign_request: &BlindSignRequest, - tx_hash: String, - signature: String, - public_attributes: &[Attribute], - public_attributes_plain: Vec, - total_params: u32, - ) -> BlindSignRequestBody { - BlindSignRequestBody { - blind_sign_request: blind_sign_request.clone(), - tx_hash, - signature, - public_attributes: public_attributes - .iter() - .map(|attr| attr.to_bs58()) - .collect(), - public_attributes_plain, - total_params, - } - } - - pub fn public_attributes(&self) -> Vec { - self.public_attributes - .iter() - .map(|x| Attribute::try_from_bs58(x).unwrap()) - .collect() - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct BlindedSignatureResponse { - pub remote_key: [u8; 32], - pub encrypted_signature: Vec, -} - -impl BlindedSignatureResponse { - pub fn new(encrypted_signature: Vec, remote_key: [u8; 32]) -> BlindedSignatureResponse { - BlindedSignatureResponse { - encrypted_signature, - remote_key, - } - } - - pub fn to_base58_string(&self) -> String { - bs58::encode(&self.to_bytes()).into_string() - } - - pub fn from_base58_string>(val: I) -> Result { - let bytes = bs58::decode(val).into_vec()?; - Self::from_bytes(&bytes) - } - - pub fn to_bytes(&self) -> Vec { - let mut bytes = self.remote_key.to_vec(); - bytes.extend_from_slice(&self.encrypted_signature); - bytes - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() < 32 { - return Err(CoconutInterfaceError::InvalidByteLength(bytes.len(), 32)); - } - let mut remote_key = [0u8; 32]; - remote_key.copy_from_slice(&bytes[..32]); - let encrypted_signature = bytes[32..].to_vec(); - Ok(BlindedSignatureResponse { - remote_key, - encrypted_signature, - }) - } -} - -#[derive(Serialize, Deserialize)] -pub struct VerificationKeyResponse { - pub key: VerificationKey, -} - -impl VerificationKeyResponse { - pub fn new(key: VerificationKey) -> VerificationKeyResponse { - VerificationKeyResponse { key } - } -} - -#[derive(Serialize, Deserialize)] -pub struct CosmosAddressResponse { - pub addr: AccountId, -} - -impl CosmosAddressResponse { - pub fn new(addr: AccountId) -> CosmosAddressResponse { - CosmosAddressResponse { addr } - } -} diff --git a/nym-api/nym-api-requests/src/coconut/helpers.rs b/nym-api/nym-api-requests/src/coconut/helpers.rs new file mode 100644 index 0000000000..58aec3eca0 --- /dev/null +++ b/nym-api/nym-api-requests/src/coconut/helpers.rs @@ -0,0 +1,33 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use nym_coconut_interface::BlindedSignature; +use tendermint::hash::Hash; + +// recomputes plaintext on the credential nym-api has used for signing +// +// note: this method doesn't have to be reversible so just naively concatenate everything +pub fn issued_credential_plaintext( + epoch_id: u32, + tx_hash: Hash, + blinded_partial_credential: &BlindedSignature, + bs58_encoded_private_attributes_commitments: &[String], + public_attributes: &[String], +) -> Vec { + epoch_id + .to_be_bytes() + .into_iter() + .chain(tx_hash.as_bytes().iter().copied()) + .chain(blinded_partial_credential.to_bytes()) + .chain( + bs58_encoded_private_attributes_commitments + .iter() + .flat_map(|attr| attr.as_bytes().iter().copied()), + ) + .chain( + public_attributes + .iter() + .flat_map(|attr| attr.as_bytes().iter().copied()), + ) + .collect() +} diff --git a/nym-api/nym-api-requests/src/coconut/mod.rs b/nym-api/nym-api-requests/src/coconut/mod.rs new file mode 100644 index 0000000000..fb5740928c --- /dev/null +++ b/nym-api/nym-api-requests/src/coconut/mod.rs @@ -0,0 +1,10 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +pub mod helpers; +pub mod models; + +pub use models::{ + BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody, + VerificationKeyResponse, VerifyCredentialBody, VerifyCredentialResponse, +}; diff --git a/nym-api/nym-api-requests/src/coconut/models.rs b/nym-api/nym-api-requests/src/coconut/models.rs new file mode 100644 index 0000000000..79db872288 --- /dev/null +++ b/nym-api/nym-api-requests/src/coconut/models.rs @@ -0,0 +1,233 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::coconut::helpers::issued_credential_plaintext; +use cosmrs::AccountId; +use nym_coconut_interface::{ + error::CoconutInterfaceError, hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, + Bytable, Credential, VerificationKey, +}; +use nym_crypto::asymmetric::identity; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use tendermint::hash::Hash; + +#[derive(Serialize, Deserialize)] +pub struct VerifyCredentialBody { + pub credential: Credential, + + pub proposal_id: u64, + + pub gateway_cosmos_addr: AccountId, +} + +impl VerifyCredentialBody { + pub fn new( + credential: Credential, + proposal_id: u64, + gateway_cosmos_addr: AccountId, + ) -> VerifyCredentialBody { + VerifyCredentialBody { + credential, + proposal_id, + gateway_cosmos_addr, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct VerifyCredentialResponse { + pub verification_result: bool, +} + +impl VerifyCredentialResponse { + pub fn new(verification_result: bool) -> Self { + VerifyCredentialResponse { + verification_result, + } + } +} + +// All strings are base58 encoded representations of structs +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct BlindSignRequestBody { + pub inner_sign_request: BlindSignRequest, + + /// Hash of the deposit transaction + pub tx_hash: Hash, + + /// Signature on the inner sign request and the tx hash + pub signature: identity::Signature, + + // public_attributes: Vec, + pub public_attributes_plain: Vec, +} + +impl BlindSignRequestBody { + pub fn new( + inner_sign_request: BlindSignRequest, + tx_hash: Hash, + signature: identity::Signature, + public_attributes_plain: Vec, + ) -> BlindSignRequestBody { + BlindSignRequestBody { + inner_sign_request, + tx_hash, + signature, + public_attributes_plain, + } + } + + pub fn attributes(&self) -> u32 { + (self.public_attributes_plain.len() + self.inner_sign_request.num_private_attributes()) + as u32 + } + + pub fn public_attributes_hashed(&self) -> Vec { + self.public_attributes_plain + .iter() + .map(hash_to_scalar) + .collect() + } + + pub fn encode_commitments(&self) -> Vec { + use nym_coconut_interface::Base58; + + self.inner_sign_request + .get_private_attributes_pedersen_commitments() + .iter() + .map(|c| c.to_bs58()) + .collect() + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct BlindedSignatureResponse { + pub blinded_signature: BlindedSignature, +} + +impl BlindedSignatureResponse { + pub fn new(blinded_signature: BlindedSignature) -> BlindedSignatureResponse { + BlindedSignatureResponse { blinded_signature } + } + + pub fn to_base58_string(&self) -> String { + bs58::encode(&self.to_bytes()).into_string() + } + + pub fn from_base58_string>(val: I) -> Result { + let bytes = bs58::decode(val).into_vec()?; + Self::from_bytes(&bytes) + } + + pub fn to_bytes(&self) -> Vec { + self.blinded_signature.to_byte_vec() + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(BlindedSignatureResponse { + blinded_signature: BlindedSignature::from_bytes(bytes)?, + }) + } +} + +#[derive(Serialize, Deserialize)] +pub struct VerificationKeyResponse { + pub key: VerificationKey, +} + +impl VerificationKeyResponse { + pub fn new(key: VerificationKey) -> VerificationKeyResponse { + VerificationKeyResponse { key } + } +} + +#[derive(Serialize, Deserialize)] +pub struct CosmosAddressResponse { + pub addr: AccountId, +} + +impl CosmosAddressResponse { + pub fn new(addr: AccountId) -> CosmosAddressResponse { + CosmosAddressResponse { addr } + } +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct Pagination { + /// last_key is the last value returned in the previous query. + /// it's used to indicate the start of the next (this) page. + /// the value itself is not included in the response. + pub last_key: Option, + + /// limit is the total number of results to be returned in the result page. + /// If left empty it will default to a value to be set by each app. + pub limit: Option, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct CredentialsRequestBody { + /// Explicit ids of the credentials to retrieve. Note: it can't be set alongside pagination. + pub credential_ids: Vec, + + /// Pagination settings for retrieving credentials. Note: it can't be set alongside explicit ids. + pub pagination: Option>, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct EpochCredentialsResponse { + pub epoch_id: u64, + pub first_epoch_credential_id: Option, + pub total_issued: u32, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct IssuedCredentialsResponse { + // note: BTreeMap returns ordered results so it's fine to use it with pagination + pub credentials: BTreeMap, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct IssuedCredentialResponse { + pub credential: Option, +} + +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct IssuedCredentialInner { + pub credential: IssuedCredential, + + pub signature: identity::Signature, +} + +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct IssuedCredential { + pub id: i64, + pub epoch_id: u32, + pub tx_hash: Hash, + + // NOTE: if we find creation of this guy takes too long, + // change `BlindedSignature` to `BlindedSignatureBytes` + // so that nym-api wouldn't need to parse the value out of its storage + pub blinded_partial_credential: BlindedSignature, + pub bs58_encoded_private_attributes_commitments: Vec, + pub public_attributes: Vec, +} + +impl IssuedCredential { + // this method doesn't have to be reversible so just naively concatenate everything + pub fn signable_plaintext(&self) -> Vec { + issued_credential_plaintext( + self.epoch_id, + self.tx_hash, + &self.blinded_partial_credential, + &self.bs58_encoded_private_attributes_commitments, + &self.public_attributes, + ) + } +} diff --git a/nym-api/src/coconut/api_routes/helpers.rs b/nym-api/src/coconut/api_routes/helpers.rs new file mode 100644 index 0000000000..6589499767 --- /dev/null +++ b/nym-api/src/coconut/api_routes/helpers.rs @@ -0,0 +1,28 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::coconut::error::Result; +use crate::coconut::storage::models::IssuedCredential; +use nym_api_requests::coconut::models::IssuedCredentialInner; +use nym_api_requests::coconut::models::IssuedCredentialsResponse; +use std::collections::BTreeMap; + +pub(crate) fn build_credentials_response( + raw: Vec, +) -> Result { + let mut credentials = BTreeMap::new(); + + for raw_credential in raw { + let id = raw_credential.id; + let api_issued = IssuedCredentialInner::try_from(raw_credential)?; + let old = credentials.insert(id, api_issued); + if old.is_some() { + // why do we panic here rather than return an error? because it's a critical failure because + // since the raw values came directly from the database with the PRIMARY KEY constraint + // it should be IMPOSSIBLE to have duplicate values here + panic!("somehow retrieved multiple credentials with id {id} from the database!") + } + } + + Ok(IssuedCredentialsResponse { credentials }) +} diff --git a/nym-api/src/coconut/api_routes/mod.rs b/nym-api/src/coconut/api_routes/mod.rs new file mode 100644 index 0000000000..b783f9c0a2 --- /dev/null +++ b/nym-api/src/coconut/api_routes/mod.rs @@ -0,0 +1,211 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::coconut::api_routes::helpers::build_credentials_response; +use crate::coconut::error::{CoconutError, Result}; +use crate::coconut::helpers::{accepted_vote_err, blind_sign}; +use crate::coconut::state::State; +use crate::coconut::storage::CoconutStorageExt; +use nym_api_requests::coconut::models::{ + CredentialsRequestBody, EpochCredentialsResponse, IssuedCredentialResponse, + IssuedCredentialsResponse, +}; +use nym_api_requests::coconut::{ + BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse, +}; +use nym_coconut_bandwidth_contract_common::spend_credential::{ + funds_from_cosmos_msgs, SpendCredentialStatus, +}; +use nym_coconut_dkg_common::types::EpochId; +use nym_credentials::coconut::bandwidth::BandwidthVoucher; +use nym_validator_client::nyxd::{Coin, Fee}; +use rocket::serde::json::Json; +use rocket::State as RocketState; + +mod helpers; + +#[post("/blind-sign", data = "")] +// Until we have serialization and deserialization traits we'll be using a crutch +pub async fn post_blind_sign( + blind_sign_request_body: Json, + state: &RocketState, +) -> Result> { + debug!("Received blind sign request"); + trace!("body: {:?}", blind_sign_request_body); + + // early check: does the request have the expected number of public attributes? + debug!("performing basic request validation"); + if blind_sign_request_body.public_attributes_plain.len() + != BandwidthVoucher::PUBLIC_ATTRIBUTES as usize + { + return Err(CoconutError::InconsistentPublicAttributes); + } + + // check if we already issued a credential for this tx hash + debug!( + "checking if we have already issued credential for this tx_hash (hash: {})", + blind_sign_request_body.tx_hash + ); + if let Some(blinded_signature) = state + .already_issued(blind_sign_request_body.tx_hash) + .await? + { + return Ok(Json(BlindedSignatureResponse { blinded_signature })); + } + + // check if we have the signing key available + debug!("checking if we actually have coconut keys derived..."); + let keypair_guard = state.coconut_keypair.get().await; + let Some(signing_key) = keypair_guard.as_ref() else { + return Err(CoconutError::KeyPairNotDerivedYet); + }; + + // get the transaction details of the claimed deposit + debug!("getting transaction details from the chain"); + let tx = state + .get_transaction(blind_sign_request_body.tx_hash) + .await?; + + // check validity of the request + debug!("fully validating received request"); + state.validate_request(&blind_sign_request_body, tx).await?; + + // produce the partial signature + debug!("producing the partial credential"); + let blinded_signature = blind_sign(&blind_sign_request_body, signing_key.secret_key())?; + + // store the information locally + debug!("storing the issued credential in the database"); + state + .store_issued_credential(blind_sign_request_body.into_inner(), &blinded_signature) + .await?; + + // finally return the credential to the client + Ok(Json(BlindedSignatureResponse { blinded_signature })) +} + +#[post("/verify-bandwidth-credential", data = "")] +pub async fn verify_bandwidth_credential( + verify_credential_body: Json, + state: &RocketState, +) -> Result> { + let proposal_id = verify_credential_body.proposal_id; + let proposal = state.client.get_proposal(proposal_id).await?; + // Proposal description is the blinded serial number + if !verify_credential_body + .credential + .has_blinded_serial_number(&proposal.description)? + { + return Err(CoconutError::IncorrectProposal { + reason: String::from("incorrect blinded serial number in description"), + }); + } + let proposed_release_funds = + funds_from_cosmos_msgs(proposal.msgs).ok_or(CoconutError::IncorrectProposal { + reason: String::from("action is not to release funds"), + })?; + // Credential has not been spent before, and is on its way of being spent + let credential_status = state + .client + .get_spent_credential(verify_credential_body.credential.blinded_serial_number()) + .await? + .spend_credential + .ok_or(CoconutError::InvalidCredentialStatus { + status: String::from("Inexistent"), + })? + .status(); + if credential_status != SpendCredentialStatus::InProgress { + return Err(CoconutError::InvalidCredentialStatus { + status: format!("{:?}", credential_status), + }); + } + let verification_key = state + .verification_key(*verify_credential_body.credential.epoch_id()) + .await?; + let mut vote_yes = verify_credential_body.credential.verify(&verification_key); + + vote_yes &= Coin::from(proposed_release_funds) + == Coin::new( + verify_credential_body.credential.voucher_value() as u128, + state.mix_denom.clone(), + ); + + // Vote yes or no on the proposal based on the verification result + let ret = state + .client + .vote_proposal( + proposal_id, + vote_yes, + Some(Fee::new_payer_granter_auto( + None, + None, + Some(verify_credential_body.gateway_cosmos_addr.clone()), + )), + ) + .await; + accepted_vote_err(ret)?; + + Ok(Json(VerifyCredentialResponse::new(vote_yes))) +} + +#[get("/epoch-credentials/")] +pub async fn epoch_credentials( + epoch: EpochId, + state: &RocketState, +) -> Result> { + let issued = state.storage.get_epoch_credentials(epoch).await?; + + let response = if let Some(issued) = issued { + issued.into() + } else { + EpochCredentialsResponse { + epoch_id: epoch, + first_epoch_credential_id: None, + total_issued: 0, + } + }; + + Ok(Json(response)) +} + +#[get("/issued-credential/")] +pub async fn issued_credential( + id: i64, + state: &RocketState, +) -> Result> { + let issued = state.storage.get_issued_credential(id).await?; + + let credential = if let Some(issued) = issued { + Some(issued.try_into()?) + } else { + None + }; + + Ok(Json(IssuedCredentialResponse { credential })) +} + +#[post("/issued-credentials", data = "")] +pub async fn issued_credentials( + params: Json, + state: &RocketState, +) -> Result> { + let params = params.into_inner(); + + if params.pagination.is_some() && !params.credential_ids.is_empty() { + return Err(CoconutError::InvalidQueryArguments); + } + + let credentials = if let Some(pagination) = params.pagination { + state + .storage + .get_issued_credentials_paged(pagination) + .await? + } else { + state + .storage + .get_issued_credentials(params.credential_ids) + .await? + }; + + build_credentials_response(credentials).map(Json) +} diff --git a/nym-api/src/coconut/client.rs b/nym-api/src/coconut/client.rs index adb132e1b1..8ff1f5ed79 100644 --- a/nym-api/src/coconut/client.rs +++ b/nym-api/src/coconut/client.rs @@ -13,12 +13,12 @@ use nym_coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyS use nym_contracts_common::dealings::ContractSafeBytes; use nym_dkg::Threshold; use nym_validator_client::nyxd::cosmwasm_client::types::ExecuteResult; -use nym_validator_client::nyxd::{AccountId, Fee, TxResponse}; +use nym_validator_client::nyxd::{AccountId, Fee, Hash, TxResponse}; #[async_trait] pub trait Client { async fn address(&self) -> AccountId; - async fn get_tx(&self, tx_hash: &str) -> Result; + async fn get_tx(&self, tx_hash: Hash) -> Result; async fn get_proposal(&self, proposal_id: u64) -> Result; async fn list_proposals(&self) -> Result>; async fn get_spent_credential( diff --git a/nym-api/src/coconut/comm.rs b/nym-api/src/coconut/comm.rs index 9358af95be..a18d10588e 100644 --- a/nym-api/src/coconut/comm.rs +++ b/nym-api/src/coconut/comm.rs @@ -7,29 +7,101 @@ use nym_coconut_dkg_common::types::EpochId; use nym_coconut_interface::VerificationKey; use nym_credentials::coconut::utils::obtain_aggregate_verification_key; use nym_validator_client::coconut::all_coconut_api_clients; +use nym_validator_client::nyxd::contract_traits::DkgQueryClient; +use nym_validator_client::DirectSigningHttpRpcNyxdClient; +use std::cmp::min; +use std::collections::HashMap; use std::ops::Deref; +use time::OffsetDateTime; +use tokio::sync::RwLock; #[async_trait] pub trait APICommunicationChannel { + async fn current_epoch(&self) -> Result; async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result; } +struct CachedEpoch { + valid_until: OffsetDateTime, + current_epoch_id: EpochId, +} + +impl Default for CachedEpoch { + fn default() -> Self { + CachedEpoch { + valid_until: OffsetDateTime::UNIX_EPOCH, + current_epoch_id: 0, + } + } +} + +impl CachedEpoch { + fn is_valid(&self) -> bool { + self.valid_until > OffsetDateTime::now_utc() + } + + async fn update(&mut self, client: &DirectSigningHttpRpcNyxdClient) -> Result<()> { + let epoch = client.get_current_epoch().await?; + + let now = OffsetDateTime::now_utc(); + let state_end = + OffsetDateTime::from_unix_timestamp(epoch.finish_timestamp.seconds() as i64).unwrap(); + let until_epoch_state_end = state_end - now; + + // make it valid until the next epoch transition or next 5min, whichever is smaller + self.valid_until = now + min(until_epoch_state_end, 5 * time::Duration::MINUTE); + self.current_epoch_id = epoch.epoch_id; + + Ok(()) + } +} + pub(crate) struct QueryCommunicationChannel { nyxd_client: nyxd::Client, + + epoch_keys: RwLock>, + cached_epoch: RwLock, } impl QueryCommunicationChannel { pub fn new(nyxd_client: nyxd::Client) -> Self { - QueryCommunicationChannel { nyxd_client } + QueryCommunicationChannel { + nyxd_client, + epoch_keys: Default::default(), + cached_epoch: Default::default(), + } } } #[async_trait] impl APICommunicationChannel for QueryCommunicationChannel { + async fn current_epoch(&self) -> Result { + let guard = self.cached_epoch.read().await; + if guard.is_valid() { + return Ok(guard.current_epoch_id); + } + + // update cache + drop(guard); + let mut guard = self.cached_epoch.write().await; + let client = self.nyxd_client.0.read().await; + guard.update(&client).await?; + + return Ok(guard.current_epoch_id); + } + async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result { + if let Some(vk) = self.epoch_keys.read().await.get(&epoch_id) { + return Ok(vk.clone()); + } + + let mut guard = self.epoch_keys.write().await; let client = self.nyxd_client.0.read().await; let coconut_api_clients = all_coconut_api_clients(client.deref(), epoch_id).await?; let vk = obtain_aggregate_verification_key(&coconut_api_clients).await?; + + guard.insert(epoch_id, vk.clone()); + Ok(vk) } } diff --git a/nym-api/src/coconut/deposit.rs b/nym-api/src/coconut/deposit.rs index d7db423d60..22f59fc969 100644 --- a/nym-api/src/coconut/deposit.rs +++ b/nym-api/src/coconut/deposit.rs @@ -1,189 +1,112 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use crate::coconut::error::{CoconutError, Result}; use nym_api_requests::coconut::BlindSignRequestBody; use nym_coconut_bandwidth_contract_common::events::{ - DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO, - DEPOSIT_VALUE, + COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, + DEPOSIT_INFO, DEPOSIT_VALUE, }; use nym_credentials::coconut::bandwidth::BandwidthVoucher; -use nym_crypto::asymmetric::encryption; -use nym_crypto::asymmetric::identity::{self, Signature}; +use nym_crypto::asymmetric::identity; +use nym_validator_client::nyxd::helpers::find_tx_attribute; use nym_validator_client::nyxd::TxResponse; -use super::error::{CoconutError, Result}; - -pub async fn extract_encryption_key( - blind_sign_request_body: &BlindSignRequestBody, - tx: TxResponse, -) -> Result { - let blind_sign_request = blind_sign_request_body.blind_sign_request(); - let public_attributes = blind_sign_request_body.public_attributes(); - let public_attributes_plain = blind_sign_request_body.public_attributes_plain(); - - if !BandwidthVoucher::verify_against_plain(&public_attributes, public_attributes_plain) { +pub async fn validate_deposit_tx(request: &BlindSignRequestBody, tx: TxResponse) -> Result<()> { + if request.public_attributes_plain.len() != BandwidthVoucher::PUBLIC_ATTRIBUTES as usize { return Err(CoconutError::InconsistentPublicAttributes); } - let tx_hash_str = blind_sign_request_body.tx_hash(); - let mut message = blind_sign_request.to_bytes(); - message.extend_from_slice(tx_hash_str.as_bytes()); + // extract actual public attributes + associated x25519 public key + let deposit_value = find_tx_attribute(&tx, COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_VALUE) + .ok_or(CoconutError::DepositValueNotFound)?; - let signature = Signature::from_base58_string(blind_sign_request_body.signature())?; + let deposit_info = find_tx_attribute(&tx, COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_INFO) + .ok_or(CoconutError::DepositInfoNotFound)?; - let attributes: &Vec<_> = tx - .tx_result - .events - .iter() - .find(|event| event.kind == format!("wasm-{}", DEPOSITED_FUNDS_EVENT_TYPE)) - .ok_or(CoconutError::DepositEventNotFound)? - .attributes - .as_ref(); + let x25519_raw = find_tx_attribute( + &tx, + COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE, + DEPOSIT_IDENTITY_KEY, + ) + .ok_or(CoconutError::DepositVerifKeyNotFound)?; - let deposit_value: &str = attributes - .iter() - .find(|tag| tag.key == DEPOSIT_VALUE) - .ok_or(CoconutError::DepositValueNotFound)? - .value - .as_ref(); - let deposit_value_plain = public_attributes_plain.first().cloned().unwrap_or_default(); - if deposit_value != deposit_value_plain { - return Err(CoconutError::DifferentPublicAttributes( - deposit_value.to_string(), - deposit_value_plain, - )); + // we're not using it anymore, but for legacy reasons it must be present + let _ed25519_raw = find_tx_attribute( + &tx, + COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE, + DEPOSIT_ENCRYPTION_KEY, + ) + .ok_or(CoconutError::DepositEncrKeyNotFound)?; + + // check public attributes against request data + // (thinking about it attaching that data might be redundant since we have the source of truth on the chain) + // safety: we won't read data out of bounds since we just checked we have BandwidthVoucher::PUBLIC_ATTRIBUTES values in the vec + if deposit_value != request.public_attributes_plain[0] { + return Err(CoconutError::InconsistentDepositValue { + request: request.public_attributes_plain[0].clone(), + on_chain: deposit_value, + }); } - let deposit_info: &str = attributes - .iter() - .find(|tag| tag.key == DEPOSIT_INFO) - .ok_or(CoconutError::DepositInfoNotFound)? - .value - .as_ref(); - let deposit_info_plain = public_attributes_plain.get(1).cloned().unwrap_or_default(); - if deposit_info != deposit_info_plain { - return Err(CoconutError::DifferentPublicAttributes( - deposit_info.to_string(), - deposit_info_plain, - )); + if deposit_info != request.public_attributes_plain[1] { + return Err(CoconutError::InconsistentDepositInfo { + request: request.public_attributes_plain[1].clone(), + on_chain: deposit_info, + }); } - let verification_key = identity::PublicKey::from_base58_string( - &attributes - .iter() - .find(|tag| tag.key == DEPOSIT_IDENTITY_KEY) - .ok_or(CoconutError::DepositVerifKeyNotFound)? - .value, - )?; + // verify signature + let x25519 = identity::PublicKey::from_base58_string(x25519_raw)?; + let plaintext = + BandwidthVoucher::signable_plaintext(&request.inner_sign_request, request.tx_hash); + x25519.verify(plaintext, &request.signature)?; - let encryption_key = encryption::PublicKey::from_base58_string( - &attributes - .iter() - .find(|tag| tag.key == DEPOSIT_ENCRYPTION_KEY) - .ok_or(CoconutError::DepositEncrKeyNotFound)? - .value, - )?; - - verification_key.verify(&message, &signature)?; - - Ok(encryption_key) + Ok(()) } #[cfg(test)] mod test { use super::*; - use crate::coconut::tests::tx_entry_fixture; - use nym_coconut::{prepare_blind_sign, BlindSignRequest, Parameters}; + use crate::coconut::tests::{tx_entry_fixture, voucher_request_fixture}; + use cosmwasm_std::coin; + use nym_api_requests::coconut::BlindSignRequestBody; + use nym_coconut::BlindSignRequest; + use nym_coconut_bandwidth_contract_common::events::DEPOSITED_FUNDS_EVENT_TYPE; use nym_config::defaults::VOUCHER_INFO; - use nym_validator_client::nyxd::Hash; use nym_validator_client::nyxd::{Event, EventAttribute}; - use rand_07::rngs::OsRng; - use std::str::FromStr; #[tokio::test] - async fn extract_encryption_key_test() { - let tx_hash = - Hash::from_str("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E") - .unwrap(); - let mut tx_entry = tx_entry_fixture(&tx_hash.to_string()); - let params = Parameters::new(4).unwrap(); - let mut rng = OsRng; - let voucher = BandwidthVoucher::new( - ¶ms, - "1234".to_string(), - VOUCHER_INFO.to_string(), - tx_hash, - identity::PrivateKey::from_base58_string( - identity::KeyPair::new(&mut rng) - .private_key() - .to_base58_string(), - ) - .unwrap(), - encryption::PrivateKey::from_bytes( - &encryption::KeyPair::new(&mut rng).private_key().to_bytes(), - ) - .unwrap(), - ); - let (_, blind_sign_req) = prepare_blind_sign( - ¶ms, - &voucher.get_private_attributes(), - &voucher.get_public_attributes(), - ) - .unwrap(); - let signature = "2DHbEZ6pzToGpsAXJrqJi7Wj1pAXeT18283q2YEEyNH5gTymwRozWBdja6SMAVt1dyYmUnM4ZNhsJ4wxZyGh4Z6J".to_string(); + async fn validate_deposit_tx_test() { + let (voucher, correct_request) = voucher_request_fixture(coin(1234, "unym"), None); - let req = BlindSignRequestBody::new( - &blind_sign_req, - tx_hash.to_string(), - signature.clone(), - &voucher.get_public_attributes(), - vec![ - String::from("First wrong plain"), - String::from("Second wrong plain"), - ], - 4, - ); - let err = extract_encryption_key(&req, tx_entry.clone()) - .await - .unwrap_err(); - assert_eq!( - err.to_string(), - CoconutError::InconsistentPublicAttributes.to_string() - ); - - let req = BlindSignRequestBody::new( - &blind_sign_req, - tx_hash.to_string(), - String::from("Invalid signature"), - &voucher.get_public_attributes(), - voucher.get_public_attributes_plain(), - 4, - ); - let err = extract_encryption_key(&req, tx_entry.clone()) - .await - .unwrap_err(); - - assert!(matches!( - err, - CoconutError::Ed25519ParseError( - nym_crypto::asymmetric::identity::Ed25519RecoveryError::MalformedSignatureString { .. } - ) - )); - - let correct_request = BlindSignRequestBody::new( - &blind_sign_req, - tx_hash.to_string(), - signature.clone(), - &voucher.get_public_attributes(), - voucher.get_public_attributes_plain(), - 4, - ); + let mut tx_entry = tx_entry_fixture(correct_request.tx_hash); + let good_deposit_attribute = EventAttribute { + key: DEPOSIT_VALUE.to_string(), + value: correct_request.public_attributes_plain[0].clone(), + index: false, + }; + let good_info_attribute = EventAttribute { + key: DEPOSIT_INFO.to_string(), + value: correct_request.public_attributes_plain[1].clone(), + index: false, + }; + let good_identity_key_attribute = EventAttribute { + key: DEPOSIT_IDENTITY_KEY.to_string(), + value: "2eSxwquNJb2nZTEW5p4rbqjHfBaz9UaNhjHHiexPN4He".to_string(), + index: false, + }; + let good_encryption_key_attribute = EventAttribute { + key: DEPOSIT_ENCRYPTION_KEY.to_string(), + value: "2eSxwquNJb2nZTEW5p4rbqjHfBaz9UaNhjHHiexPN4He".to_string(), + index: false, + }; tx_entry.tx_result.events.push(Event { kind: format!("wasm-{}", DEPOSITED_FUNDS_EVENT_TYPE), attributes: vec![], }); - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); assert_eq!( @@ -191,26 +114,34 @@ mod test { CoconutError::DepositValueNotFound.to_string(), ); - tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "10".parse().unwrap(), - index: false, - }]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + EventAttribute { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "10".parse().unwrap(), + index: false, + }, + good_info_attribute.clone(), + good_identity_key_attribute.clone(), + good_encryption_key_attribute.clone(), + ]; + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); assert_eq!( err.to_string(), - CoconutError::DifferentPublicAttributes("10".to_string(), "1234".to_string()) - .to_string(), + CoconutError::InconsistentDepositValue { + request: "1234".to_string(), + on_chain: "10".to_string() + } + .to_string() ); - tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + good_deposit_attribute.clone(), + good_identity_key_attribute.clone(), + good_encryption_key_attribute.clone(), + ]; + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); assert_eq!( @@ -219,42 +150,33 @@ mod test { ); tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, + good_deposit_attribute.clone(), EventAttribute { key: DEPOSIT_INFO.parse().unwrap(), value: "bandwidth deposit info".parse().unwrap(), index: false, }, + good_identity_key_attribute.clone(), + good_encryption_key_attribute.clone(), ]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); assert_eq!( err.to_string(), - CoconutError::DifferentPublicAttributes( - "bandwidth deposit info".to_string(), - VOUCHER_INFO.to_string(), - ) + CoconutError::InconsistentDepositInfo { + on_chain: "bandwidth deposit info".to_string(), + request: VOUCHER_INFO.to_string(), + } .to_string(), ); tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_INFO.parse().unwrap(), - value: VOUCHER_INFO.parse().unwrap(), - index: false, - }, + good_deposit_attribute.clone(), + good_info_attribute.clone(), + good_encryption_key_attribute.clone(), ]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); assert_eq!( @@ -263,23 +185,16 @@ mod test { ); tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_INFO.parse().unwrap(), - value: VOUCHER_INFO.parse().unwrap(), - index: false, - }, + good_deposit_attribute.clone(), + good_info_attribute.clone(), EventAttribute { key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), value: "verification key".parse().unwrap(), index: false, }, + good_encryption_key_attribute.clone(), ]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); @@ -291,16 +206,8 @@ mod test { )); tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_INFO.parse().unwrap(), - value: VOUCHER_INFO.parse().unwrap(), - index: false, - }, + good_deposit_attribute.clone(), + good_info_attribute.clone(), EventAttribute { key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), value: "2eSxwquNJb2nZTEW5p4rbqjHfBaz9UaNhjHHiexPN4He" @@ -309,7 +216,7 @@ mod test { index: false, }, ]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); assert_eq!( @@ -318,16 +225,8 @@ mod test { ); tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_INFO.parse().unwrap(), - value: VOUCHER_INFO.parse().unwrap(), - index: false, - }, + good_deposit_attribute.clone(), + good_info_attribute.clone(), EventAttribute { key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), value: "6EJGMdEq7t8Npz54uPkftGsdmj7DKntLVputAnDfVZB2" @@ -341,29 +240,16 @@ mod test { index: false, }, ]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); - assert!(matches!( - err, - CoconutError::X25519ParseError( - nym_crypto::asymmetric::encryption::KeyRecoveryError::MalformedPublicKeyString { .. } - ) - )); + assert!(matches!(err, CoconutError::SignatureVerificationError(..))); let expected_encryption_key = "HxnTpWTkgigSTAysVKLE8pEiUULHdTT1BxFfzfJvQRi6"; tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_INFO.parse().unwrap(), - value: VOUCHER_INFO.parse().unwrap(), - index: false, - }, + good_deposit_attribute.clone(), + good_info_attribute.clone(), EventAttribute { key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), value: "6EJGMdEq7t8Npz54uPkftGsdmj7DKntLVputAnDfVZB2" @@ -377,7 +263,7 @@ mod test { index: false, }, ]; - let err = extract_encryption_key(&correct_request, tx_entry.clone()) + let err = validate_deposit_tx(&correct_request, tx_entry.clone()) .await .unwrap_err(); assert_eq!( @@ -414,28 +300,21 @@ mod test { 66, 137, 17, 32, ]) .unwrap(); + let correct_request = BlindSignRequestBody::new( - &blind_sign_req, - "7C41AF8266D91DE55E1C8F4712E6A952A165ED3D8C27C7B00428CBD0DE00A52B".to_string(), - "gSFgpma5GAVMcsmZwKieqGNHNd3dPzcfa8eT2Qn2LoBccSeyiJdphREbNrkuh5XWxMe2hUsranaYzLro48L9Qhd".to_string(), - &voucher.get_public_attributes(), + blind_sign_req, + "7C41AF8266D91DE55E1C8F4712E6A952A165ED3D8C27C7B00428CBD0DE00A52B" + .parse() + .unwrap(), + "3vUCc6MCN5AC2LNgDYjRB1QeErZSN1S8f6K14JHjpUcKWXbjGYFExA8DbwQQBki9gyUqrpBF94Drttb4eMcGQXkp".parse().unwrap(), voucher.get_public_attributes_plain(), - 4, ); tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_INFO.parse().unwrap(), - value: VOUCHER_INFO.parse().unwrap(), - index: false, - }, + good_deposit_attribute.clone(), + good_info_attribute.clone(), EventAttribute { key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), - value: "64auwDkWan7R8yH1Mwe9dS4qXgrDBCUNDg3Q4KFnd2P5" + value: "3xoM5GmUSq7YW4YNQrax1fEFLw1GbZozxe6UUoJcrqLG" .parse() .unwrap(), index: false, @@ -448,9 +327,7 @@ mod test { index: false, }, ]; - let encryption_key = extract_encryption_key(&correct_request, tx_entry.clone()) - .await - .unwrap(); - assert_eq!(encryption_key.to_base58_string(), expected_encryption_key); + let res = validate_deposit_tx(&correct_request, tx_entry.clone()).await; + assert!(res.is_ok()) } } diff --git a/nym-api/src/coconut/dkg/dealing.rs b/nym-api/src/coconut/dkg/dealing.rs index 5a05915b0a..266c6db66e 100644 --- a/nym-api/src/coconut/dkg/dealing.rs +++ b/nym-api/src/coconut/dkg/dealing.rs @@ -11,6 +11,7 @@ use nym_dkg::bte::setup; use nym_dkg::Dealing; use rand::RngCore; use std::collections::VecDeque; +use zeroize::Zeroize; pub(crate) async fn dealing_exchange( dkg_client: &DkgClient, @@ -39,16 +40,19 @@ pub(crate) async fn dealing_exchange( .keys() .position(|node_index| *node_index == dealer_index); - let prior_resharing_secrets = if let Some(sk) = state.coconut_secret_key().await { + let prior_resharing_secrets = if let Some(mut keypair) = state.take_coconut_keypair().await { // Double check that we are in resharing mode if resharing { - let (x, mut scalars) = sk.into_raw(); - if scalars.len() + 1 != TOTAL_DEALINGS { + let sk = keypair.secret_key(); + if sk.size() + 1 != TOTAL_DEALINGS { return Err(CoconutError::CorruptedCoconutKeyPair); } + + let (x, mut scalars) = sk.into_raw(); + // We can now erase the keypair from memory debug!("Removing coconut keypair from memory"); - state.set_coconut_keypair(None).await; + keypair.zeroize(); scalars.push(x); scalars } else { diff --git a/nym-api/src/coconut/dkg/state.rs b/nym-api/src/coconut/dkg/state.rs index 59aaec6416..b22cd81f50 100644 --- a/nym-api/src/coconut/dkg/state.rs +++ b/nym-api/src/coconut/dkg/state.rs @@ -6,7 +6,6 @@ use crate::coconut::error::CoconutError; use crate::coconut::keypair::KeyPair as CoconutKeyPair; use cosmwasm_std::Addr; use log::debug; -use nym_coconut::SecretKey; use nym_coconut_dkg_common::dealer::DealerDetails; use nym_coconut_dkg_common::types::EpochState; use nym_dkg::bte::{keys::KeyPair as DkgKeyPair, PublicKey, PublicKeyWithProof}; @@ -274,12 +273,15 @@ impl State { self.coconut_keypair.get().await.is_some() } - pub async fn coconut_secret_key(&self) -> Option { - self.coconut_keypair - .get() - .await - .as_ref() - .map(|kp| kp.secret_key()) + pub async fn take_coconut_keypair(&self) -> Option { + self.coconut_keypair.take().await + } + + #[cfg(test)] + pub async fn coconut_keypair( + &self, + ) -> tokio::sync::RwLockReadGuard<'_, Option> { + self.coconut_keypair.get().await } pub fn node_index(&self) -> Option { diff --git a/nym-api/src/coconut/dkg/verification_key.rs b/nym-api/src/coconut/dkg/verification_key.rs index 4a59b5fa65..78e490af73 100644 --- a/nym-api/src/coconut/dkg/verification_key.rs +++ b/nym-api/src/coconut/dkg/verification_key.rs @@ -6,16 +6,16 @@ use crate::coconut::dkg::complaints::ComplaintReason; use crate::coconut::dkg::state::{ConsistentState, State}; use crate::coconut::error::CoconutError; use crate::coconut::helpers::accepted_vote_err; +use crate::coconut::state::BANDWIDTH_CREDENTIAL_PARAMS; use cosmwasm_std::Addr; use cw3::{ProposalResponse, Status}; use log::debug; use nym_coconut::tests::helpers::transpose_matrix; -use nym_coconut::{check_vk_pairing, Base58, KeyPair, Parameters, SecretKey, VerificationKey}; +use nym_coconut::{check_vk_pairing, Base58, KeyPair, SecretKey, VerificationKey}; use nym_coconut_dkg_common::event_attributes::DKG_PROPOSAL_ID; use nym_coconut_dkg_common::types::{NodeIndex, TOTAL_DEALINGS}; use nym_coconut_dkg_common::verification_key::owner_from_cosmos_msgs; use nym_coconut_interface::KeyPair as CoconutKeyPair; -use nym_credentials::coconut::bandwidth::{PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES}; use nym_dkg::bte::{decrypt_share, setup}; use nym_dkg::error::DkgError; use nym_dkg::{combine_shares, try_recover_verification_keys, Dealing, Threshold}; @@ -140,7 +140,6 @@ fn derive_partial_keypair( } state.set_recovered_vks(recovered_vks); - let params = Parameters::new(PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES)?; let x = scalars.pop().ok_or(CoconutError::DkgError( DkgError::NotEnoughDealingsAvailable { available: 0, @@ -148,7 +147,7 @@ fn derive_partial_keypair( }, ))?; let sk = SecretKey::create_from_raw(x, scalars); - let vk = sk.verification_key(¶ms); + let vk = sk.verification_key(&BANDWIDTH_CREDENTIAL_PARAMS); Ok(CoconutKeyPair::from_keys(sk, vk)) } @@ -234,7 +233,7 @@ pub(crate) async fn verification_key_validation( .map(|recovered_vk| recovered_vk.recovered_partials.clone()) .collect(); let recovered_partials = transpose_matrix(recovered_partials); - let params = Parameters::new(PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES)?; + let params = &BANDWIDTH_CREDENTIAL_PARAMS; for contract_share in vk_shares { if let Some(proposal_id) = proposal_ids.get(&contract_share.owner).copied() { match VerificationKey::try_from_bs58(contract_share.share) { @@ -243,7 +242,7 @@ pub(crate) async fn verification_key_validation( .iter() .position(|node_index| contract_share.node_index == *node_index) { - let ret = if !check_vk_pairing(¶ms, &recovered_partials[idx], &vk) { + let ret = if !check_vk_pairing(params, &recovered_partials[idx], &vk) { debug!( "Voting NO to proposal {} because of failed VK pairing", proposal_id @@ -836,16 +835,17 @@ pub(crate) mod tests { for (_, state) in clients_and_states.iter_mut() { state.set_was_in_progress(); } - let params = Parameters::new(4).unwrap(); let mut vks = vec![]; let mut indices = vec![]; for (_, state) in clients_and_states.iter() { let vk = state - .coconut_secret_key() + .coconut_keypair() .await + .as_ref() .unwrap() - .verification_key(¶ms); + .verification_key() + .clone(); let index = state.node_index().unwrap(); vks.push(vk); indices.push(index); @@ -933,10 +933,12 @@ pub(crate) mod tests { let mut indices = vec![]; for (_, state) in clients_and_states.iter() { let vk = state - .coconut_secret_key() + .coconut_keypair() .await + .as_ref() .unwrap() - .verification_key(¶ms); + .verification_key() + .clone(); let index = state.node_index().unwrap(); vks.push(vk); indices.push(index); @@ -1047,16 +1049,16 @@ pub(crate) mod tests { } // DKG in reshare mode - let params = Parameters::new(4).unwrap(); - let mut vks = vec![]; let mut indices = vec![]; for (_, state) in clients_and_states.iter() { let vk = state - .coconut_secret_key() + .coconut_keypair() .await + .as_ref() .unwrap() - .verification_key(¶ms); + .verification_key() + .clone(); let index = state.node_index().unwrap(); vks.push(vk); indices.push(index); @@ -1124,10 +1126,12 @@ pub(crate) mod tests { let mut indices = vec![]; for (_, state) in clients_and_states.iter() { let vk = state - .coconut_secret_key() + .coconut_keypair() .await + .as_ref() .unwrap() - .verification_key(¶ms); + .verification_key() + .clone(); let index = state.node_index().unwrap(); vks.push(vk); indices.push(index); diff --git a/nym-api/src/coconut/error.rs b/nym-api/src/coconut/error.rs index 14f7b2f933..290f448fb1 100644 --- a/nym-api/src/coconut/error.rs +++ b/nym-api/src/coconut/error.rs @@ -13,7 +13,7 @@ use nym_crypto::asymmetric::{ }; use nym_dkg::error::DkgError; use nym_validator_client::coconut::CoconutApiError; -use nym_validator_client::nyxd::error::NyxdError; +use nym_validator_client::nyxd::error::{NyxdError, TendermintError}; use crate::node_status_api::models::NymApiStorageError; @@ -30,82 +30,100 @@ pub enum CoconutError { #[error(transparent)] SerdeJsonError(#[from] serde_json::Error), - #[error("Could not parse Ed25519 data - {0}")] + #[error("could not parse Ed25519 data: {0}")] Ed25519ParseError(#[from] Ed25519RecoveryError), - #[error("Could not parse X25519 data - {0}")] + #[error("could not parse X25519 data: {0}")] X25519ParseError(#[from] KeyRecoveryError), - #[error("Could not parse tx hash in request body")] - TxHashParseError, + #[error("could not parse tx hash in request body: {source}")] + TxHashParseError { + #[source] + source: TendermintError, + }, - #[error("Nyxd error - {0}")] + #[error("could not get transaction details for '{tx_hash}': {source}")] + TxRetrievalFailure { + tx_hash: String, + #[source] + source: NyxdError, + }, + + #[error("nyxd error: {0}")] NyxdError(#[from] NyxdError), - #[error("Validator client error - {0}")] + #[error("validator client error: {0}")] ValidatorClientError(#[from] nym_validator_client::ValidatorClientError), - #[error("Coconut internal error - {0}")] + #[error("coconut internal error: {0}")] CoconutInternalError(#[from] nym_coconut::CoconutError), - #[error("Could not find a deposit event in the transaction provided")] + #[error("could not find a deposit event in the transaction provided")] DepositEventNotFound, - #[error("Could not find the deposit value in the event")] + #[error("could not find the deposit value in the event")] DepositValueNotFound, - #[error("Could not find the deposit info in the event")] + #[error("could not find the deposit info in the event")] DepositInfoNotFound, - #[error("Could not find the verification key in the event")] + #[error("could not find the verification key in the event")] DepositVerifKeyNotFound, - #[error("Could not find the encryption key in the event")] + #[error("could not find the encryption key in the event")] DepositEncrKeyNotFound, - #[error("Signature didn't verify correctly")] + #[error("signature didn't verify correctly")] SignatureVerificationError(#[from] SignatureError), - #[error("Inconsistent public attributes")] + #[error("inconsistent public attributes")] InconsistentPublicAttributes, - #[error( - "Public attributes in request differ from the ones in deposit - Expected {0}, got {1}" - )] + #[error("the provided deposit value is inconsistent. got '{request}' while the value on chain is '{on_chain}'")] + InconsistentDepositValue { request: String, on_chain: String }, + + #[error("the provided deposit info is inconsistent. got '{request}' while the value on chain is '{on_chain}'")] + InconsistentDepositInfo { request: String, on_chain: String }, + + #[error("public attributes in request differ from the ones in deposit: Expected {0}, got {1}")] DifferentPublicAttributes(String, String), - #[error("Error in coconut interface - {0}")] + #[error("error in coconut interface: {0}")] CoconutInterfaceError(#[from] nym_coconut_interface::error::CoconutInterfaceError), - #[error("Storage error - {0}")] + #[error("storage error: {0}")] StorageError(#[from] NymApiStorageError), - #[error("Credentials error - {0}")] + #[error("credentials error: {0}")] CredentialsError(#[from] nym_credentials::error::Error), - #[error("Incorrect credential proposal description: {reason}")] + #[error("incorrect credential proposal description: {reason}")] IncorrectProposal { reason: String }, - #[error("Invalid status of credential: {status}")] + #[error("invalid status of credential: {status}")] InvalidCredentialStatus { status: String }, #[error("DKG error: {0}")] DkgError(#[from] DkgError), - #[error("Failed to recover assigned node index: {reason}")] + #[error("failed to recover assigned node index: {reason}")] NodeIndexRecoveryError { reason: String }, - #[error("Unrecoverable state: {reason}")] + #[error("unrecoverable state: {reason}")] UnrecoverableState { reason: String }, #[error("DKG has not finished yet in order to derive the coconut key")] KeyPairNotDerivedYet, - #[error("The coconut keypair is corrupted")] + #[error("the coconut keypair is corrupted")] CorruptedCoconutKeyPair, - #[error("There was a problem with the proposal id: {reason}")] + #[error("there was a problem with the proposal id: {reason}")] ProposalIdError { reason: String }, + + // I guess we should make this one a bit more detailed + #[error("the provided query arguments were invalid")] + InvalidQueryArguments, } impl<'r, 'o: 'r> Responder<'r, 'o> for CoconutError { diff --git a/nym-api/src/coconut/helpers.rs b/nym-api/src/coconut/helpers.rs index 50afa84420..a7e25d7b46 100644 --- a/nym-api/src/coconut/helpers.rs +++ b/nym-api/src/coconut/helpers.rs @@ -2,6 +2,9 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::coconut::error::CoconutError; +use crate::coconut::state::BANDWIDTH_CREDENTIAL_PARAMS; +use nym_api_requests::coconut::BlindSignRequestBody; +use nym_coconut::{BlindedSignature, SecretKey}; use nym_validator_client::nyxd::error::NyxdError::AbciError; // If the result is already established, the vote might be redundant and @@ -17,3 +20,18 @@ pub(crate) fn accepted_vote_err(ret: Result<(), CoconutError>) -> Result<(), Coc } Ok(()) } + +pub(crate) fn blind_sign( + request: &BlindSignRequestBody, + signing_key: &SecretKey, +) -> Result { + let public_attributes = request.public_attributes_hashed(); + let attributes_ref = public_attributes.iter().collect::>(); + + Ok(nym_coconut_interface::blind_sign( + &BANDWIDTH_CREDENTIAL_PARAMS, + signing_key, + &request.inner_sign_request, + &attributes_ref, + )?) +} diff --git a/nym-api/src/coconut/keypair.rs b/nym-api/src/coconut/keypair.rs index ef27856c83..57b7872971 100644 --- a/nym-api/src/coconut/keypair.rs +++ b/nym-api/src/coconut/keypair.rs @@ -16,6 +16,10 @@ impl KeyPair { } } + pub async fn take(&self) -> Option { + self.inner.write().await.take() + } + pub async fn get(&self) -> RwLockReadGuard<'_, Option> { self.inner.read().await } diff --git a/nym-api/src/coconut/mod.rs b/nym-api/src/coconut/mod.rs index 7059e95160..51c4199018 100644 --- a/nym-api/src/coconut/mod.rs +++ b/nym-api/src/coconut/mod.rs @@ -3,39 +3,15 @@ use self::comm::APICommunicationChannel; use crate::coconut::client::Client as LocalClient; -use crate::coconut::deposit::extract_encryption_key; -use crate::coconut::error::{CoconutError, Result}; -use crate::coconut::helpers::accepted_vote_err; +use crate::coconut::state::State; use crate::support::storage::NymApiStorage; -use getset::{CopyGetters, Getters}; use keypair::KeyPair; -use nym_api_requests::coconut::{ - BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse, -}; -use nym_coconut_bandwidth_contract_common::spend_credential::{ - funds_from_cosmos_msgs, SpendCredentialStatus, -}; -use nym_coconut_dkg_common::types::EpochId; -use nym_coconut_interface::KeyPair as CoconutKeyPair; -use nym_coconut_interface::{ - Attribute, BlindSignRequest, BlindedSignature, Parameters, VerificationKey, -}; use nym_config::defaults::NYM_API_VERSION; -use nym_credentials::coconut::params::{ - NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm, -}; -use nym_crypto::asymmetric::encryption; -use nym_crypto::shared_key::new_ephemeral_shared_key; -use nym_crypto::symmetric::stream_cipher; +use nym_crypto::asymmetric::identity; use nym_validator_client::nym_api::routes::{BANDWIDTH, COCONUT_ROUTES}; -use nym_validator_client::nyxd::{Coin, Fee}; -use rand_07::rngs::OsRng; use rocket::fairing::AdHoc; -use rocket::serde::json::Json; -use rocket::State as RocketState; -use std::sync::Arc; -use tokio::sync::Mutex; +pub(crate) mod api_routes; pub(crate) mod client; pub(crate) mod comm; mod deposit; @@ -43,263 +19,42 @@ pub(crate) mod dkg; pub(crate) mod error; pub(crate) mod helpers; pub(crate) mod keypair; +pub(crate) mod state; +pub(crate) mod storage; #[cfg(test)] pub(crate) mod tests; -pub struct State { - client: Arc, +pub fn stage( + client: C, mix_denom: String, + identity_keypair: identity::KeyPair, key_pair: KeyPair, - comm_channel: Arc, + comm_channel: D, storage: NymApiStorage, - rng: Arc>, -} - -impl State { - pub(crate) fn new( - client: C, - mix_denom: String, - key_pair: KeyPair, - comm_channel: D, - storage: NymApiStorage, - ) -> Self - where - C: LocalClient + Send + Sync + 'static, - D: APICommunicationChannel + Send + Sync + 'static, - { - let client = Arc::new(client); - let comm_channel = Arc::new(comm_channel); - let rng = Arc::new(Mutex::new(OsRng)); - Self { - client, - mix_denom, - key_pair, - comm_channel, - storage, - rng, - } - } - - pub async fn signed_before(&self, tx_hash: &str) -> Result> { - let ret = self.storage.get_blinded_signature_response(tx_hash).await?; - if let Some(blinded_signature_reponse) = ret { - Ok(Some(BlindedSignatureResponse::from_base58_string( - blinded_signature_reponse, - )?)) - } else { - Ok(None) - } - } - - pub async fn encrypt_and_store( - &self, - tx_hash: &str, - remote_key: &encryption::PublicKey, - signature: &BlindedSignature, - ) -> Result { - let (keypair, shared_key) = { - let mut rng = *self.rng.lock().await; - new_ephemeral_shared_key::< - NymApiCredentialEncryptionAlgorithm, - NymApiCredentialHkdfAlgorithm, - _, - >(&mut rng, remote_key) - }; - - let chunk_data = signature.to_bytes(); - - let zero_iv = stream_cipher::zero_iv::(); - let encrypted_data = stream_cipher::encrypt::( - &shared_key, - &zero_iv, - &chunk_data, - ); - - let response = - BlindedSignatureResponse::new(encrypted_data, keypair.public_key().to_bytes()); - - // Atomically insert data, only if there is no signature stored in the meantime - // This prevents race conditions on storing two signatures for the same deposit transaction - if self - .storage - .insert_blinded_signature_response(tx_hash, &response.to_base58_string()) - .await - .is_err() - { - Ok(self - .signed_before(tx_hash) - .await? - .expect("The signature was expected to be there")) - } else { - Ok(response) - } - } - - pub async fn verification_key(&self, epoch_id: EpochId) -> Result { - self.comm_channel - .aggregated_verification_key(epoch_id) - .await - } -} - -#[derive(Getters, CopyGetters, Debug)] -pub(crate) struct InternalSignRequest { - // Total number of parameters to generate for - #[getset(get_copy)] - total_params: u32, - #[getset(get)] - public_attributes: Vec, - #[getset(get)] - blind_sign_request: BlindSignRequest, -} - -impl InternalSignRequest { - pub fn new( - total_params: u32, - public_attributes: Vec, - blind_sign_request: BlindSignRequest, - ) -> InternalSignRequest { - InternalSignRequest { - total_params, - public_attributes, - blind_sign_request, - } - } - - pub fn stage( - client: C, - mix_denom: String, - key_pair: KeyPair, - comm_channel: D, - storage: NymApiStorage, - ) -> AdHoc - where - C: LocalClient + Send + Sync + 'static, - D: APICommunicationChannel + Send + Sync + 'static, - { - let state = State::new(client, mix_denom, key_pair, comm_channel, storage); - AdHoc::on_ignite("Internal Sign Request Stage", |rocket| async { - rocket.manage(state).mount( - // this format! is so ugly... - format!("/{}/{}/{}", NYM_API_VERSION, COCONUT_ROUTES, BANDWIDTH), - routes![post_blind_sign, verify_bandwidth_credential], - ) - }) - } -} - -fn blind_sign(request: InternalSignRequest, key_pair: &CoconutKeyPair) -> Result { - let params = Parameters::new(request.total_params())?; - Ok(nym_coconut_interface::blind_sign( - ¶ms, - &key_pair.secret_key(), - request.blind_sign_request(), - request.public_attributes(), - )?) -} - -#[post("/blind-sign", data = "")] -// Until we have serialization and deserialization traits we'll be using a crutch -pub async fn post_blind_sign( - blind_sign_request_body: Json, - state: &RocketState, -) -> Result> { - debug!("{:?}", blind_sign_request_body); - if let Some(response) = state - .signed_before(blind_sign_request_body.tx_hash()) - .await? - { - return Ok(Json(response)); - } - let tx = state - .client - .get_tx(blind_sign_request_body.tx_hash()) - .await?; - let encryption_key = extract_encryption_key(&blind_sign_request_body, tx).await?; - let internal_request = InternalSignRequest::new( - *blind_sign_request_body.total_params(), - blind_sign_request_body.public_attributes(), - blind_sign_request_body.blind_sign_request().clone(), +) -> AdHoc +where + C: LocalClient + Send + Sync + 'static, + D: APICommunicationChannel + Send + Sync + 'static, +{ + let state = State::new( + client, + mix_denom, + identity_keypair, + key_pair, + comm_channel, + storage, ); - let blinded_signature = if let Some(keypair) = state.key_pair.get().await.as_ref() { - blind_sign(internal_request, keypair)? - } else { - return Err(CoconutError::KeyPairNotDerivedYet); - }; - - let response = state - .encrypt_and_store( - blind_sign_request_body.tx_hash(), - &encryption_key, - &blinded_signature, + AdHoc::on_ignite("Internal Sign Request Stage", |rocket| async { + rocket.manage(state).mount( + // this format! is so ugly... + format!("/{NYM_API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}"), + routes![ + api_routes::post_blind_sign, + api_routes::verify_bandwidth_credential, + api_routes::epoch_credentials, + api_routes::issued_credential, + api_routes::issued_credentials, + ], ) - .await?; - - Ok(Json(response)) -} - -#[post("/verify-bandwidth-credential", data = "")] -pub async fn verify_bandwidth_credential( - verify_credential_body: Json, - state: &RocketState, -) -> Result> { - let proposal_id = *verify_credential_body.proposal_id(); - let proposal = state.client.get_proposal(proposal_id).await?; - // Proposal description is the blinded serial number - if !verify_credential_body - .credential() - .has_blinded_serial_number(&proposal.description)? - { - return Err(CoconutError::IncorrectProposal { - reason: String::from("incorrect blinded serial number in description"), - }); - } - let proposed_release_funds = - funds_from_cosmos_msgs(proposal.msgs).ok_or(CoconutError::IncorrectProposal { - reason: String::from("action is not to release funds"), - })?; - // Credential has not been spent before, and is on its way of being spent - let credential_status = state - .client - .get_spent_credential(verify_credential_body.credential().blinded_serial_number()) - .await? - .spend_credential - .ok_or(CoconutError::InvalidCredentialStatus { - status: String::from("Inexistent"), - })? - .status(); - if credential_status != SpendCredentialStatus::InProgress { - return Err(CoconutError::InvalidCredentialStatus { - status: format!("{:?}", credential_status), - }); - } - let verification_key = state - .verification_key(*verify_credential_body.credential().epoch_id()) - .await?; - let mut vote_yes = verify_credential_body - .credential() - .verify(&verification_key); - - vote_yes &= Coin::from(proposed_release_funds) - == Coin::new( - verify_credential_body.credential().voucher_value() as u128, - state.mix_denom.clone(), - ); - - // Vote yes or no on the proposal based on the verification result - let ret = state - .client - .vote_proposal( - proposal_id, - vote_yes, - Some(Fee::new_payer_granter_auto( - None, - None, - Some(verify_credential_body.gateway_cosmos_addr().to_owned()), - )), - ) - .await; - accepted_vote_err(ret)?; - - Ok(Json(VerifyCredentialResponse::new(vote_yes))) + }) } diff --git a/nym-api/src/coconut/state.rs b/nym-api/src/coconut/state.rs new file mode 100644 index 0000000000..0cffc9e752 --- /dev/null +++ b/nym-api/src/coconut/state.rs @@ -0,0 +1,151 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::coconut::client::Client as LocalClient; +use crate::coconut::comm::APICommunicationChannel; +use crate::coconut::deposit::validate_deposit_tx; +use crate::coconut::error::Result; +use crate::coconut::keypair::KeyPair; +use crate::coconut::storage::CoconutStorageExt; +use crate::support::storage::NymApiStorage; +use lazy_static::lazy_static; +use nym_api_requests::coconut::helpers::issued_credential_plaintext; +use nym_api_requests::coconut::BlindSignRequestBody; +use nym_coconut::Parameters; +use nym_coconut_dkg_common::types::EpochId; +use nym_coconut_interface::{BlindedSignature, VerificationKey}; +use nym_credentials::coconut::bandwidth::BandwidthVoucher; +use nym_crypto::asymmetric::identity; +use nym_validator_client::nyxd::{Hash, TxResponse}; +use std::sync::Arc; + +// keep it as a global static due to relatively high cost of computing the curve points; +// plus we expect all clients to use the same set of parameters +// +// future note: once we allow for credentials with variable number of attributes, just create Parameters(max_allowed_attributes) +// and take as many hs elements as required (since they will match for all variants) +lazy_static! { + pub(crate) static ref BANDWIDTH_CREDENTIAL_PARAMS: Parameters = + BandwidthVoucher::default_parameters(); +} + +pub struct State { + pub(crate) client: Arc, + pub(crate) mix_denom: String, + pub(crate) coconut_keypair: KeyPair, + pub(crate) identity_keypair: identity::KeyPair, + pub(crate) comm_channel: Arc, + pub(crate) storage: NymApiStorage, +} + +impl State { + pub(crate) fn new( + client: C, + mix_denom: String, + identity_keypair: identity::KeyPair, + key_pair: KeyPair, + comm_channel: D, + storage: NymApiStorage, + ) -> Self + where + C: LocalClient + Send + Sync + 'static, + D: APICommunicationChannel + Send + Sync + 'static, + { + let client = Arc::new(client); + let comm_channel = Arc::new(comm_channel); + + Self { + client, + mix_denom, + coconut_keypair: key_pair, + identity_keypair, + comm_channel, + storage, + } + } + + /// Check if this nym-api has already issued a credential for the provided deposit hash. + /// If so, return it. + pub async fn already_issued(&self, tx_hash: Hash) -> Result> { + self.storage + .get_issued_bandwidth_credential_by_hash(&tx_hash.to_string()) + .await? + .map(|cred| cred.try_into()) + .transpose() + } + + pub async fn get_transaction(&self, tx_hash: Hash) -> Result { + self.client.get_tx(tx_hash).await + } + + pub async fn validate_request( + &self, + request: &BlindSignRequestBody, + tx: TxResponse, + ) -> Result<()> { + validate_deposit_tx(request, tx).await + } + + pub(crate) async fn sign_and_store_credential( + &self, + current_epoch: EpochId, + request_body: BlindSignRequestBody, + blinded_signature: &BlindedSignature, + ) -> Result { + let encoded_commitments = request_body.encode_commitments(); + + let plaintext = issued_credential_plaintext( + current_epoch as u32, + request_body.tx_hash, + blinded_signature, + &encoded_commitments, + &request_body.public_attributes_plain, + ); + + let signature = self.identity_keypair.private_key().sign(plaintext); + + // note: we have a UNIQUE constraint on the tx_hash column of the credential + // and so if the api is processing request for the same hash at the same time, + // only one of them will be successfully inserted to the database + let credential_id = self + .storage + .store_issued_credential( + current_epoch as u32, + request_body.tx_hash, + blinded_signature, + signature, + encoded_commitments, + request_body.public_attributes_plain, + ) + .await?; + + Ok(credential_id) + } + + pub async fn store_issued_credential( + &self, + request_body: BlindSignRequestBody, + blinded_signature: &BlindedSignature, + ) -> Result<()> { + let current_epoch = self.comm_channel.current_epoch().await?; + + // note: we have a UNIQUE constraint on the tx_hash column of the credential + // and so if the api is processing request for the same hash at the same time, + // only one of them will be successfully inserted to the database + let credential_id = self + .sign_and_store_credential(current_epoch, request_body, blinded_signature) + .await?; + self.storage + .update_epoch_credentials_entry(current_epoch, credential_id) + .await?; + debug!("the stored credential has id {credential_id}"); + + Ok(()) + } + + pub async fn verification_key(&self, epoch_id: EpochId) -> Result { + self.comm_channel + .aggregated_verification_key(epoch_id) + .await + } +} diff --git a/nym-api/src/coconut/storage/manager.rs b/nym-api/src/coconut/storage/manager.rs new file mode 100644 index 0000000000..e40b2a4a96 --- /dev/null +++ b/nym-api/src/coconut/storage/manager.rs @@ -0,0 +1,381 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::coconut::storage::models::{EpochCredentials, IssuedCredential}; +use crate::support::storage::manager::StorageManager; +use nym_coconut_dkg_common::types::EpochId; + +#[async_trait] +pub trait CoconutStorageManagerExt { + /// Creates new encrypted blinded signature response entry for a given deposit tx hash. + /// + /// # Arguments + /// + /// * `tx_hash`: hash of the deposit transaction. + /// * `blinded_signature_response`: the encrypted blinded signature response. + #[deprecated] + async fn insert_blinded_signature_response( + &self, + _tx_hash: &str, + _blinded_signature_response: &str, + ) -> Result<(), sqlx::Error> { + Ok(()) + } + + /// Tries to obtain encrypted blinded signature response for a given transaction hash. + /// + /// # Arguments + /// + /// * `tx_hash`: transaction hash of the deposit. + #[deprecated] + async fn get_blinded_signature_response( + &self, + _tx_hash: &str, + ) -> Result, sqlx::Error> { + Ok(None) + } + + /// Gets the information about all issued partial credentials in this (coconut) epoch. + /// + /// # Arguments + /// + /// * `epoch_id`: Id of the (coconut) epoch in question. + async fn get_epoch_credentials( + &self, + epoch_id: EpochId, + ) -> Result, sqlx::Error>; + + /// Creates new entry for EpochCredentials for this (coconut) epoch. + /// + /// # Arguments + /// + /// * `epoch_id`: Id of the (coconut) epoch in question. + async fn create_epoch_credentials_entry(&self, epoch_id: EpochId) -> Result<(), sqlx::Error>; + + /// Update the EpochCredentials by incrementing the total number of issued credentials, + /// and setting `start_id` if unset (i.e. this is the first credential issued this epoch) + /// + /// # Arguments + /// * `epoch_id`: Id of the (coconut) epoch in question. + /// * `credential_id`: (database) Id of the coconut credential that triggered the update. + async fn update_epoch_credentials_entry( + &self, + epoch_id: EpochId, + credential_id: i64, + ) -> Result<(), sqlx::Error>; + + /// Attempts to retrieve an issued credential from the data store. + /// + /// # Arguments + /// + /// * `credential_id`: (database) id of the issued credential + async fn get_issued_credential( + &self, + credential_id: i64, + ) -> Result, sqlx::Error>; + + /// Attempts to retrieve an issued credential from the data store. + /// + /// # Arguments + /// + /// * `tx_hash`: transaction hash of the deposit used in the issued bandwidth credential + async fn get_issued_bandwidth_credential_by_hash( + &self, + tx_hash: &str, + ) -> Result, sqlx::Error>; + + /// Store the provided issued credential information and return its (database) id. + /// + /// # Arguments + /// + /// * `credential`: partial credential, alongside any data required for verification. + async fn store_issued_credential( + &self, + epoch_id: u32, + tx_hash: String, + bs58_partial_credential: String, + bs58_signature: String, + joined_private_commitments: String, + joined_public_attributes: String, + ) -> Result; + + /// Attempts to retrieve issued credentials from the data store using provided ids. + /// + /// # Arguments + /// + /// * `credential_ids`: (database) ids of the issued credentials + async fn get_issued_credentials( + &self, + credential_ids: Vec, + ) -> Result, sqlx::Error>; + + /// Attempts to retrieve issued credentials from the data store using pagination specification. + /// + /// # Arguments + /// + /// * `start_after`: the value preceding the first retrieved result + /// * `limit`: the maximum number of entries to retrieve + async fn get_issued_credentials_paged( + &self, + start_after: i64, + limit: u32, + ) -> Result, sqlx::Error>; +} + +#[async_trait] +impl CoconutStorageManagerExt for StorageManager { + /// Gets the information about all issued partial credentials in this (coconut) epoch. + /// + /// # Arguments + /// + /// * `epoch_id`: Id of the (coconut) epoch in question. + async fn get_epoch_credentials( + &self, + epoch_id: EpochId, + ) -> Result, sqlx::Error> { + // even if we were changing epochs every second, it's rather impossible to overflow here + // within any sane amount of time + assert!(epoch_id <= u32::MAX as u64); + let epoch_id_downcasted = epoch_id as u32; + + sqlx::query_as!( + EpochCredentials, + r#" + SELECT epoch_id as "epoch_id: u32", start_id, total_issued as "total_issued: u32" + FROM epoch_credentials + WHERE epoch_id = ? + "#, + epoch_id_downcasted + ) + .fetch_optional(&self.connection_pool) + .await + } + + /// Creates new entry for EpochCredentials for this (coconut) epoch. + /// + /// # Arguments + /// + /// * `epoch_id`: Id of the (coconut) epoch in question. + async fn create_epoch_credentials_entry(&self, epoch_id: EpochId) -> Result<(), sqlx::Error> { + // even if we were changing epochs every second, it's rather impossible to overflow here + // within any sane amount of time + assert!(epoch_id <= u32::MAX as u64); + let epoch_id_downcasted = epoch_id as u32; + + sqlx::query!( + r#" + INSERT INTO epoch_credentials + (epoch_id, start_id, total_issued) + VALUES (?, ?, ?); + "#, + epoch_id_downcasted, + -1, + 0 + ) + .execute(&self.connection_pool) + .await?; + Ok(()) + } + + // the logic in this function can be summarised with: + // 1. get the current EpochCredentials for this epoch + // 2. if it exists -> increment `total_issued` + // 3. it has invalid (i.e. -1) `start_id` set it to the provided value + // 4. if it didn't exist, create new entry + /// Update the EpochCredentials by incrementing the total number of issued credentials, + /// and setting `start_id` if unset (i.e. this is the first credential issued this epoch) + /// + /// # Arguments + /// * `epoch_id`: Id of the (coconut) epoch in question. + /// * `credential_id`: (database) Id of the coconut credential that triggered the update. + async fn update_epoch_credentials_entry( + &self, + epoch_id: EpochId, + credential_id: i64, + ) -> Result<(), sqlx::Error> { + // even if we were changing epochs every second, it's rather impossible to overflow here + // within any sane amount of time + assert!(epoch_id <= u32::MAX as u64); + let epoch_id_downcasted = epoch_id as u32; + + // make the atomic transaction in case other tasks are attempting to use the pool + let mut tx = self.connection_pool.begin().await?; + + if let Some(existing) = sqlx::query_as!( + EpochCredentials, + r#" + SELECT epoch_id as "epoch_id: u32", start_id, total_issued as "total_issued: u32" + FROM epoch_credentials + WHERE epoch_id = ? + "#, + epoch_id_downcasted + ) + .fetch_optional(&mut tx) + .await? + { + // the entry has existed before -> update it + if existing.total_issued == 0 { + // no credentials has been issued -> we have to set the `start_id` + sqlx::query!( + r#" + UPDATE epoch_credentials + SET total_issued = 1, start_id = ? + WHERE epoch_id = ? + "#, + credential_id, + epoch_id_downcasted + ) + .execute(&mut tx) + .await?; + } else { + // we have issued credentials in this epoch before -> just increment `total_issued` + sqlx::query!( + r#" + UPDATE epoch_credentials + SET total_issued = total_issued + 1 + WHERE epoch_id = ? + "#, + epoch_id_downcasted + ) + .execute(&mut tx) + .await?; + } + } else { + // the entry has never been created -> probably some race condition; create it instead + sqlx::query!( + r#" + INSERT INTO epoch_credentials + (epoch_id, start_id, total_issued) + VALUES (?, ?, ?); + "#, + epoch_id_downcasted, + credential_id, + 1 + ) + .execute(&mut tx) + .await?; + } + + // finally commit the transaction + tx.commit().await + } + + /// Attempts to retrieve an issued credential from the data store. + /// + /// # Arguments + /// + /// * `credential_id`: (database) id of the issued credential + async fn get_issued_credential( + &self, + credential_id: i64, + ) -> Result, sqlx::Error> { + sqlx::query_as!( + IssuedCredential, + r#" + SELECT id, epoch_id as "epoch_id: u32", tx_hash, bs58_partial_credential, bs58_signature,joined_private_commitments, joined_public_attributes + FROM issued_credential + WHERE id = ? + "#, + credential_id + ) + .fetch_optional(&self.connection_pool) + .await + } + + /// Attempts to retrieve an issued credential from the data store. + /// + /// # Arguments + /// + /// * `tx_hash`: transaction hash of the deposit used in the issued bandwidth credential + async fn get_issued_bandwidth_credential_by_hash( + &self, + tx_hash: &str, + ) -> Result, sqlx::Error> { + sqlx::query_as!( + IssuedCredential, + r#" + SELECT id, epoch_id as "epoch_id: u32", tx_hash, bs58_partial_credential, bs58_signature,joined_private_commitments, joined_public_attributes + FROM issued_credential + WHERE tx_hash = ? + "#, + tx_hash + ) + .fetch_optional(&self.connection_pool) + .await + } + + /// Store the provided issued credential information and return its (database) id. + /// + /// # Arguments + /// + /// * `credential`: partial credential, alongside any data required for verification. + async fn store_issued_credential( + &self, + epoch_id: u32, + tx_hash: String, + bs58_partial_credential: String, + bs58_signature: String, + joined_private_commitments: String, + joined_public_attributes: String, + ) -> Result { + let row_id = sqlx::query!( + r#" + INSERT INTO issued_credential + (epoch_id, tx_hash, bs58_partial_credential, bs58_signature, joined_private_commitments, joined_public_attributes) + VALUES + (?, ?, ?, ?, ?, ?) + "#, + epoch_id, tx_hash, bs58_partial_credential, bs58_signature, joined_private_commitments, joined_public_attributes + ).execute(&self.connection_pool).await?.last_insert_rowid(); + + Ok(row_id) + } + + /// Attempts to retrieve issued credentials from the data store using provided ids. + /// + /// # Arguments + /// + /// * `credential_ids`: (database) ids of the issued credentials + async fn get_issued_credentials( + &self, + credential_ids: Vec, + ) -> Result, sqlx::Error> { + // that sucks : ( + // https://stackoverflow.com/a/70032524 + let params = format!("?{}", ", ?".repeat(credential_ids.len() - 1)); + let query_str = format!("SELECT * FROM issued_credential WHERE id IN ( {params} )"); + let mut query = sqlx::query_as(&query_str); + for id in credential_ids { + query = query.bind(id) + } + + query.fetch_all(&self.connection_pool).await + } + + /// Attempts to retrieve issued credentials from the data store using pagination specification. + /// + /// # Arguments + /// + /// * `start_after`: the value preceding the first retrieved result + /// * `limit`: the maximum number of entries to retrieve + async fn get_issued_credentials_paged( + &self, + start_after: i64, + limit: u32, + ) -> Result, sqlx::Error> { + sqlx::query_as!( + IssuedCredential, + r#" + SELECT id, epoch_id as "epoch_id: u32", tx_hash, bs58_partial_credential, bs58_signature,joined_private_commitments, joined_public_attributes + FROM issued_credential + WHERE id > ? + ORDER BY id + LIMIT ? + "#, + start_after, + limit + ) + .fetch_all(&self.connection_pool) + .await + } +} diff --git a/nym-api/src/coconut/storage/mod.rs b/nym-api/src/coconut/storage/mod.rs new file mode 100644 index 0000000000..5633ba468d --- /dev/null +++ b/nym-api/src/coconut/storage/mod.rs @@ -0,0 +1,166 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::coconut::storage::manager::CoconutStorageManagerExt; +use crate::coconut::storage::models::{join_attributes, EpochCredentials, IssuedCredential}; +use crate::node_status_api::models::NymApiStorageError; +use crate::support::storage::NymApiStorage; +use nym_api_requests::coconut::models::Pagination; +use nym_coconut::{Base58, BlindedSignature}; +use nym_coconut_dkg_common::types::EpochId; +use nym_crypto::asymmetric::identity; +use nym_validator_client::nyxd::Hash; + +pub(crate) mod manager; +pub(crate) mod models; + +const DEFAULT_CREDENTIALS_PAGE_LIMIT: u32 = 100; + +#[async_trait] +pub trait CoconutStorageExt { + async fn get_epoch_credentials( + &self, + epoch_id: EpochId, + ) -> Result, NymApiStorageError>; + + async fn create_epoch_credentials_entry( + &self, + epoch_id: EpochId, + ) -> Result<(), NymApiStorageError>; + + async fn update_epoch_credentials_entry( + &self, + epoch_id: EpochId, + credential_id: i64, + ) -> Result<(), NymApiStorageError>; + + async fn get_issued_credential( + &self, + credential_id: i64, + ) -> Result, NymApiStorageError>; + + async fn get_issued_bandwidth_credential_by_hash( + &self, + tx_hash: &str, + ) -> Result, NymApiStorageError>; + + async fn store_issued_credential( + &self, + epoch_id: u32, + tx_hash: Hash, + partial_credential: &BlindedSignature, + signature: identity::Signature, + private_commitments: Vec, + public_attributes: Vec, + ) -> Result; + + async fn get_issued_credentials( + &self, + credential_ids: Vec, + ) -> Result, NymApiStorageError>; + + async fn get_issued_credentials_paged( + &self, + pagination: Pagination, + ) -> Result, NymApiStorageError>; +} + +#[async_trait] +impl CoconutStorageExt for NymApiStorage { + async fn get_epoch_credentials( + &self, + epoch_id: EpochId, + ) -> Result, NymApiStorageError> { + Ok(self.manager.get_epoch_credentials(epoch_id).await?) + } + + async fn create_epoch_credentials_entry( + &self, + epoch_id: EpochId, + ) -> Result<(), NymApiStorageError> { + Ok(self + .manager + .create_epoch_credentials_entry(epoch_id) + .await?) + } + + async fn update_epoch_credentials_entry( + &self, + epoch_id: EpochId, + credential_id: i64, + ) -> Result<(), NymApiStorageError> { + Ok(self + .manager + .update_epoch_credentials_entry(epoch_id, credential_id) + .await?) + } + + async fn get_issued_credential( + &self, + credential_id: i64, + ) -> Result, NymApiStorageError> { + Ok(self.manager.get_issued_credential(credential_id).await?) + } + + async fn get_issued_bandwidth_credential_by_hash( + &self, + tx_hash: &str, + ) -> Result, NymApiStorageError> { + Ok(self + .manager + .get_issued_bandwidth_credential_by_hash(tx_hash) + .await?) + } + + async fn store_issued_credential( + &self, + epoch_id: u32, + tx_hash: Hash, + partial_credential: &BlindedSignature, + signature: identity::Signature, + private_commitments: Vec, + public_attributes: Vec, + ) -> Result { + Ok(self + .manager + .store_issued_credential( + epoch_id, + tx_hash.to_string(), + partial_credential.to_bs58(), + signature.to_base58_string(), + join_attributes(private_commitments), + join_attributes(public_attributes), + ) + .await?) + } + + async fn get_issued_credentials( + &self, + credential_ids: Vec, + ) -> Result, NymApiStorageError> { + Ok(self.manager.get_issued_credentials(credential_ids).await?) + } + + async fn get_issued_credentials_paged( + &self, + pagination: Pagination, + ) -> Result, NymApiStorageError> { + // rows start at 1 + let start_after = pagination.last_key.unwrap_or(0); + let limit = match pagination.limit { + Some(v) => { + if v == 0 || v > DEFAULT_CREDENTIALS_PAGE_LIMIT { + DEFAULT_CREDENTIALS_PAGE_LIMIT + } else { + v + } + } + None => DEFAULT_CREDENTIALS_PAGE_LIMIT, + }; + + Ok(self + .manager + .get_issued_credentials_paged(start_after, limit) + .await?) + } +} diff --git a/nym-api/src/coconut/storage/models.rs b/nym-api/src/coconut/storage/models.rs new file mode 100644 index 0000000000..fe1afbac22 --- /dev/null +++ b/nym-api/src/coconut/storage/models.rs @@ -0,0 +1,119 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::coconut::error::CoconutError; +use nym_api_requests::coconut::models::{ + EpochCredentialsResponse, IssuedCredential as ApiIssuedCredential, + IssuedCredentialInner as ApiIssuedCredentialInner, +}; +use nym_api_requests::coconut::BlindedSignatureResponse; +use nym_coconut::{Base58, BlindedSignature}; +use sqlx::FromRow; +use std::fmt::Display; + +pub struct EpochCredentials { + pub epoch_id: u32, + pub start_id: i64, + pub total_issued: u32, +} + +impl From for EpochCredentialsResponse { + fn from(value: EpochCredentials) -> Self { + let first_epoch_credential_id = if value.start_id == -1 { + None + } else { + Some(value.start_id) + }; + + EpochCredentialsResponse { + epoch_id: value.epoch_id as u64, + first_epoch_credential_id, + total_issued: value.total_issued, + } + } +} + +#[derive(FromRow)] +pub struct IssuedCredential { + pub id: i64, + pub epoch_id: u32, + pub tx_hash: String, + + /// base58-encoded issued credential + pub bs58_partial_credential: String, + + /// base58-encoded signature on the issued credential (and the attributes) + pub bs58_signature: String, + + // i.e. "'attr1','attr2',..." + pub joined_private_commitments: String, + + // i.e. "'attr1','attr2',..." + pub joined_public_attributes: String, +} + +impl TryFrom for ApiIssuedCredentialInner { + type Error = CoconutError; + + fn try_from(value: IssuedCredential) -> Result { + Ok(ApiIssuedCredentialInner { + credential: ApiIssuedCredential { + id: value.id, + epoch_id: value.epoch_id, + tx_hash: value + .tx_hash + .parse() + .map_err(|source| CoconutError::TxHashParseError { source })?, + blinded_partial_credential: BlindedSignature::try_from_bs58( + value.bs58_partial_credential, + )?, + bs58_encoded_private_attributes_commitments: split_attributes( + &value.joined_private_commitments, + ), + public_attributes: split_attributes(&value.joined_public_attributes), + }, + signature: value.bs58_signature.parse()?, + }) + } +} + +impl TryFrom for BlindedSignatureResponse { + type Error = CoconutError; + + fn try_from(value: IssuedCredential) -> Result { + Ok(BlindedSignatureResponse { + blinded_signature: BlindedSignature::try_from_bs58(value.bs58_partial_credential)?, + }) + } +} + +impl TryFrom for BlindedSignature { + type Error = CoconutError; + + fn try_from(value: IssuedCredential) -> Result { + Ok(BlindedSignature::try_from_bs58( + value.bs58_partial_credential, + )?) + } +} + +impl IssuedCredential { + // safety: this should only ever be called on sanitized data from the database, + // thus the unwraps are fine (if somebody manually entered their db file and modified it, it's on them) + // pub fn private_attribute_commitments(&self) -> Vec + // pub fn public_attributes(&self) +} + +pub fn join_attributes(attrs: I) -> String +where + I: IntoIterator, + M: Display, +{ + // I could have used `attrs.into_iter().join(",")`, + // but my IDE didn't like it (compiler was fine) + itertools::Itertools::join(&mut attrs.into_iter(), ",") +} + +pub fn split_attributes(attrs: &str) -> Vec { + attrs.split(',').map(|s| s.to_string()).collect() +} diff --git a/nym-api/src/coconut/tests/issued_credentials.rs b/nym-api/src/coconut/tests/issued_credentials.rs new file mode 100644 index 0000000000..d753476235 --- /dev/null +++ b/nym-api/src/coconut/tests/issued_credentials.rs @@ -0,0 +1,276 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::coconut::tests::{voucher_request_fixture, TestFixture}; +use cosmwasm_std::coin; +use nym_api_requests::coconut::models::{ + EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse, Pagination, +}; +use nym_api_requests::coconut::CredentialsRequestBody; +use nym_coconut::Base58; +use nym_validator_client::nym_api::routes::{API_VERSION, BANDWIDTH, COCONUT_ROUTES}; +use rocket::http::Status; +use std::collections::BTreeMap; + +#[tokio::test] +async fn epoch_credentials() { + let route_epoch1 = format!("/{API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}/epoch-credentials/1"); + let route_epoch2 = format!("/{API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}/epoch-credentials/2"); + let route_epoch42 = format!("/{API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}/epoch-credentials/42"); + + let test_fixture = TestFixture::new().await; + + // initially we expect 0 issued + let response = test_fixture.rocket.get(&route_epoch1).dispatch().await; + + assert_eq!(response.status(), Status::Ok); + let parsed_response: EpochCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + + assert_eq!(parsed_response.epoch_id, 1); + assert_eq!(parsed_response.total_issued, 0); + assert_eq!(parsed_response.first_epoch_credential_id, None); + + // get credential + test_fixture.issue_dummy_credential().await; + + // now there should be one + let response = test_fixture.rocket.get(&route_epoch1).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: EpochCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + + assert_eq!(parsed_response.epoch_id, 1); + assert_eq!(parsed_response.total_issued, 1); + assert_eq!(parsed_response.first_epoch_credential_id, Some(1)); + + // and another + test_fixture.issue_dummy_credential().await; + + let response = test_fixture.rocket.get(&route_epoch1).dispatch().await; + + assert_eq!(response.status(), Status::Ok); + let parsed_response: EpochCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + + // note that first epoch credential didn't change + assert_eq!(parsed_response.epoch_id, 1); + assert_eq!(parsed_response.total_issued, 2); + assert_eq!(parsed_response.first_epoch_credential_id, Some(1)); + + test_fixture.set_epoch(2); + + let response = test_fixture.rocket.get(&route_epoch2).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: EpochCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + + // note the epoch change + assert_eq!(parsed_response.epoch_id, 2); + assert_eq!(parsed_response.total_issued, 0); + assert_eq!(parsed_response.first_epoch_credential_id, None); + + test_fixture.issue_dummy_credential().await; + + let response = test_fixture.rocket.get(&route_epoch2).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: EpochCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + + // note the epoch change + assert_eq!(parsed_response.epoch_id, 2); + assert_eq!(parsed_response.total_issued, 1); + assert_eq!(parsed_response.first_epoch_credential_id, Some(3)); + + // random epoch in the future + let response = test_fixture.rocket.get(&route_epoch42).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: EpochCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + assert_eq!(parsed_response.epoch_id, 42); + assert_eq!(parsed_response.total_issued, 0); + assert_eq!(parsed_response.first_epoch_credential_id, None); +} + +#[tokio::test] +async fn issued_credential() { + fn route(id: i64) -> String { + format!("/{API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}/issued-credential/{id}") + } + + // let test_fixture = TestFixture::new() + let hash1 = "6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E".to_string(); + let hash2 = "9F4DF28B36189B4410BC23D97FD757FC74B919122E80534CC2CA6F3D646F6518".to_string(); + + let (voucher1, req1) = voucher_request_fixture(coin(1234, "unym"), Some(hash1.clone())); + let (voucher2, req2) = voucher_request_fixture(coin(1234, "unym"), Some(hash2.clone())); + + let test_fixture = TestFixture::new().await; + test_fixture.add_deposit_tx(&voucher1); + test_fixture.add_deposit_tx(&voucher2); + + // random credential that was never issued + let response = test_fixture.rocket.get(route(42)).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: IssuedCredentialResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + assert!(parsed_response.credential.is_none()); + + let cred1 = test_fixture.issue_credential(req1).await; + + test_fixture.set_epoch(3); + let cred2 = test_fixture.issue_credential(req2).await; + + let response = test_fixture.rocket.get(route(1)).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: IssuedCredentialResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + let issued1 = parsed_response.credential.unwrap(); + + let response = test_fixture.rocket.get(route(2)).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: IssuedCredentialResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + let issued2 = parsed_response.credential.unwrap(); + + // TODO: currently we have no signature checks + assert_eq!(1, issued1.credential.id); + assert_eq!(1, issued1.credential.epoch_id); + assert_eq!(voucher1.tx_hash(), issued1.credential.tx_hash); + assert_eq!( + cred1.to_bytes(), + issued1.credential.blinded_partial_credential.to_bytes() + ); + let cms: Vec<_> = voucher1 + .blind_sign_request() + .get_private_attributes_pedersen_commitments() + .iter() + .map(|c| c.to_bs58()) + .collect(); + assert_eq!( + cms, + issued1 + .credential + .bs58_encoded_private_attributes_commitments + ); + assert_eq!( + voucher1.get_public_attributes_plain(), + issued1.credential.public_attributes + ); + + assert_eq!(2, issued2.credential.id); + assert_eq!(3, issued2.credential.epoch_id); + assert_eq!(voucher2.tx_hash(), issued2.credential.tx_hash); + assert_eq!( + cred2.to_bytes(), + issued2.credential.blinded_partial_credential.to_bytes() + ); + let cms: Vec<_> = voucher2 + .blind_sign_request() + .get_private_attributes_pedersen_commitments() + .iter() + .map(|c| c.to_bs58()) + .collect(); + assert_eq!( + cms, + issued2 + .credential + .bs58_encoded_private_attributes_commitments + ); + assert_eq!( + voucher2.get_public_attributes_plain(), + issued2.credential.public_attributes + ); +} + +#[tokio::test] +async fn issued_credentials() { + let route = format!("/{API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}/issued-credentials"); + + let test_fixture = TestFixture::new().await; + + // issue some credentials + for _ in 0..20 { + test_fixture.issue_dummy_credential().await; + } + + let issued1 = test_fixture.issued_unchecked(1).await; + let issued2 = test_fixture.issued_unchecked(2).await; + let issued3 = test_fixture.issued_unchecked(3).await; + let issued4 = test_fixture.issued_unchecked(4).await; + let issued5 = test_fixture.issued_unchecked(5).await; + let issued13 = test_fixture.issued_unchecked(13).await; + + let response = test_fixture + .rocket + .post(&route) + .json(&CredentialsRequestBody { + credential_ids: vec![5], + pagination: None, + }) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: IssuedCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + assert_eq!(parsed_response.credentials[&5], issued5); + assert!(parsed_response.credentials.get(&13).is_none()); + + let response = test_fixture + .rocket + .post(&route) + .json(&CredentialsRequestBody { + credential_ids: vec![5, 13], + pagination: None, + }) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + let parsed_response: IssuedCredentialsResponse = + serde_json::from_str(&response.into_string().await.unwrap()).unwrap(); + assert_eq!(parsed_response.credentials[&5], issued5); + assert_eq!(parsed_response.credentials[&13], issued13); + + let response_paginated = test_fixture + .rocket + .post(&route) + .json(&CredentialsRequestBody { + credential_ids: vec![], + pagination: Some(Pagination { + last_key: None, + limit: Some(2), + }), + }) + .dispatch() + .await; + assert_eq!(response_paginated.status(), Status::Ok); + let parsed_response: IssuedCredentialsResponse = + serde_json::from_str(&response_paginated.into_string().await.unwrap()).unwrap(); + + let mut expected = BTreeMap::new(); + expected.insert(1, issued1); + expected.insert(2, issued2); + assert_eq!(expected, parsed_response.credentials); + + let response_paginated = test_fixture + .rocket + .post(&route) + .json(&CredentialsRequestBody { + credential_ids: vec![], + pagination: Some(Pagination { + last_key: Some(2), + limit: Some(3), + }), + }) + .dispatch() + .await; + assert_eq!(response_paginated.status(), Status::Ok); + let parsed_response: IssuedCredentialsResponse = + serde_json::from_str(&response_paginated.into_string().await.unwrap()).unwrap(); + + let mut expected = BTreeMap::new(); + expected.insert(3, issued3); + expected.insert(4, issued4); + expected.insert(5, issued5); + assert_eq!(expected, parsed_response.credentials); +} diff --git a/nym-api/src/coconut/tests.rs b/nym-api/src/coconut/tests/mod.rs similarity index 75% rename from nym-api/src/coconut/tests.rs rename to nym-api/src/coconut/tests/mod.rs index 54af19dcae..446a85eab6 100644 --- a/nym-api/src/coconut/tests.rs +++ b/nym-api/src/coconut/tests/mod.rs @@ -1,14 +1,20 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use super::InternalSignRequest; use crate::coconut::error::{CoconutError, Result}; -use cosmwasm_std::{to_binary, Addr, CosmosMsg, Decimal, WasmMsg}; +use crate::coconut::storage::CoconutStorageExt; +use crate::coconut::{self, State}; +use crate::support::storage::NymApiStorage; +use async_trait::async_trait; +use cosmwasm_std::{coin, to_binary, Addr, CosmosMsg, Decimal, WasmMsg}; +use cw3::ProposalResponse; +use cw4::MemberResponse; +use nym_api_requests::coconut::models::{IssuedCredentialInner, IssuedCredentialResponse}; use nym_api_requests::coconut::{ BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse, }; use nym_coconut::tests::helpers::theta_from_keys_and_attributes; -use nym_coconut::{prepare_blind_sign, ttp_keygen, Base58, BlindedSignature, Parameters}; +use nym_coconut::{ttp_keygen, Base58, BlindedSignature, Parameters}; use nym_coconut_bandwidth_contract_common::events::{ DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO, DEPOSIT_VALUE, @@ -16,27 +22,6 @@ use nym_coconut_bandwidth_contract_common::events::{ use nym_coconut_bandwidth_contract_common::spend_credential::{ SpendCredential, SpendCredentialResponse, }; -use nym_coconut_interface::{hash_to_scalar, Credential, VerificationKey}; -use nym_config::defaults::VOUCHER_INFO; -use nym_credentials::coconut::bandwidth::BandwidthVoucher; -use nym_credentials::coconut::params::{ - NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm, -}; -use nym_crypto::shared_key::recompute_shared_key; -use nym_crypto::symmetric::stream_cipher; -use nym_validator_client::nym_api::routes::{ - API_VERSION, BANDWIDTH, COCONUT_BLIND_SIGN, COCONUT_ROUTES, COCONUT_VERIFY_BANDWIDTH_CREDENTIAL, -}; -use nym_validator_client::nyxd::Coin; -use nym_validator_client::nyxd::{ - AccountId, Algorithm, Event, EventAttribute, ExecTxResult, Fee, Hash, TxResponse, -}; - -use crate::coconut::State; -use crate::support::storage::NymApiStorage; -use async_trait::async_trait; -use cw3::ProposalResponse; -use cw4::MemberResponse; use nym_coconut_dkg_common::dealer::{ ContractDealing, DealerDetails, DealerDetailsResponse, DealerType, }; @@ -45,26 +30,39 @@ use nym_coconut_dkg_common::types::{ EncodedBTEPublicKeyWithProof, Epoch, EpochId, InitialReplacementData, TOTAL_DEALINGS, }; use nym_coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare}; +use nym_coconut_interface::{hash_to_scalar, Credential, VerificationKey}; +use nym_config::defaults::VOUCHER_INFO; use nym_contracts_common::dealings::ContractSafeBytes; +use nym_credentials::coconut::bandwidth::BandwidthVoucher; use nym_crypto::asymmetric::{encryption, identity}; use nym_dkg::Threshold; +use nym_validator_client::nym_api::routes::{ + API_VERSION, BANDWIDTH, COCONUT_BLIND_SIGN, COCONUT_ROUTES, COCONUT_VERIFY_BANDWIDTH_CREDENTIAL, +}; use nym_validator_client::nyxd::cosmwasm_client::logs::Log; use nym_validator_client::nyxd::cosmwasm_client::types::ExecuteResult; +use nym_validator_client::nyxd::Coin; +use nym_validator_client::nyxd::{ + AccountId, Algorithm, Event, EventAttribute, ExecTxResult, Fee, Hash, TxResponse, +}; use rand_07::rngs::OsRng; -use rand_07::Rng; +use rand_07::{Rng, RngCore}; use rocket::http::Status; use rocket::local::asynchronous::Client; use std::collections::HashMap; use std::str::FromStr; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, RwLock}; +mod issued_credentials; + const TEST_COIN_DENOM: &str = "unym"; const TEST_REWARDING_VALIDATOR_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0"; #[derive(Clone, Debug)] pub(crate) struct DummyClient { validator_address: AccountId, - tx_db: Arc>>, + tx_db: Arc>>, proposal_db: Arc>>, spent_credential_db: Arc>>, @@ -94,7 +92,7 @@ impl DummyClient { } } - pub fn with_tx_db(mut self, tx_db: &Arc>>) -> Self { + pub fn with_tx_db(mut self, tx_db: &Arc>>) -> Self { self.tx_db = Arc::clone(tx_db); self } @@ -172,13 +170,8 @@ impl super::client::Client for DummyClient { self.validator_address.clone() } - async fn get_tx(&self, tx_hash: &str) -> Result { - self.tx_db - .read() - .unwrap() - .get(tx_hash) - .cloned() - .ok_or(CoconutError::TxHashParseError) + async fn get_tx(&self, tx_hash: Hash) -> Result { + Ok(self.tx_db.read().unwrap().get(&tx_hash).cloned().unwrap()) } async fn get_proposal(&self, proposal_id: u64) -> Result { @@ -467,27 +460,38 @@ impl super::client::Client for DummyClient { #[derive(Clone, Debug)] pub struct DummyCommunicationChannel { + current_epoch: Arc, aggregated_verification_key: VerificationKey, } impl DummyCommunicationChannel { pub fn new(aggregated_verification_key: VerificationKey) -> Self { DummyCommunicationChannel { + current_epoch: Arc::new(AtomicU64::new(1)), aggregated_verification_key, } } + + pub fn with_epoch(mut self, current_epoch: Arc) -> Self { + self.current_epoch = current_epoch; + self + } } #[async_trait] impl super::comm::APICommunicationChannel for DummyCommunicationChannel { + async fn current_epoch(&self) -> Result { + Ok(self.current_epoch.load(Ordering::Relaxed)) + } + async fn aggregated_verification_key(&self, _epoch_id: EpochId) -> Result { Ok(self.aggregated_verification_key.clone()) } } -pub fn tx_entry_fixture(tx_hash: &str) -> TxResponse { +pub fn tx_entry_fixture(hash: Hash) -> TxResponse { TxResponse { - hash: Hash::from_str(tx_hash).unwrap(), + hash, height: Default::default(), index: 0, tx_result: ExecTxResult { @@ -505,88 +509,242 @@ pub fn tx_entry_fixture(tx_hash: &str) -> TxResponse { } } -#[tokio::test] -async fn signed_before() { - let tx_hash = - Hash::from_str("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E").unwrap(); - let tx_entry = tx_entry_fixture(&tx_hash.to_string()); - let signature = String::from( - "2DHbEZ6pzToGpsAXJrqJi7Wj1pAXeT18283q2YEEyNH5gTymwRozWBdja6SMAVt1dyYmUnM4ZNhsJ4wxZyGh4Z6J", - ); +pub fn deposit_tx_fixture(voucher: &BandwidthVoucher) -> TxResponse { + TxResponse { + hash: voucher.tx_hash(), + height: Default::default(), + index: 0, + tx_result: ExecTxResult { + code: Default::default(), + data: Default::default(), + log: "".to_string(), + info: "".to_string(), + gas_wanted: 0, + gas_used: 0, + events: vec![Event { + kind: format!("wasm-{}", DEPOSITED_FUNDS_EVENT_TYPE), + attributes: vec![ + EventAttribute { + key: DEPOSIT_VALUE.to_string(), + value: voucher.get_voucher_value(), + index: false, + }, + EventAttribute { + key: DEPOSIT_INFO.to_string(), + value: VOUCHER_INFO.to_string(), + index: false, + }, + EventAttribute { + key: DEPOSIT_IDENTITY_KEY.to_string(), + value: voucher.identity_key().public_key().to_base58_string(), + index: false, + }, + EventAttribute { + key: DEPOSIT_ENCRYPTION_KEY.parse().unwrap(), + value: voucher.encryption_key().public_key().to_base58_string(), + index: false, + }, + ], + }], + codespace: "".to_string(), + }, + tx: vec![], + proof: None, + } +} +pub fn blinded_signature_fixture() -> BlindedSignature { + let gen1_bytes = [ + 151u8, 241, 211, 167, 49, 151, 215, 148, 38, 149, 99, 140, 79, 169, 172, 15, 195, 104, 140, + 79, 151, 116, 185, 5, 161, 78, 58, 63, 23, 27, 172, 88, 108, 85, 232, 63, 249, 122, 26, + 239, 251, 58, 240, 10, 219, 34, 198, 187, + ]; + + let dummy_bytes = gen1_bytes + .iter() + .chain(gen1_bytes.iter()) + .copied() + .collect::>(); + + BlindedSignature::from_bytes(&dummy_bytes).unwrap() +} + +pub fn voucher_request_fixture>( + amount: C, + tx_hash: Option, +) -> (BandwidthVoucher, BlindSignRequestBody) { let params = Parameters::new(4).unwrap(); let mut rng = OsRng; + let tx_hash = if let Some(provided) = &tx_hash { + provided.parse().unwrap() + } else { + Hash::from_str("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E").unwrap() + }; + + let identity_keypair = identity::KeyPair::new(&mut rng); + let encryption_keypair = encryption::KeyPair::new(&mut rng); + let id_priv = + identity::PrivateKey::from_bytes(&identity_keypair.private_key().to_bytes()).unwrap(); + let enc_priv = + encryption::PrivateKey::from_bytes(&encryption_keypair.private_key().to_bytes()).unwrap(); + let voucher = BandwidthVoucher::new( ¶ms, - "1234".to_string(), + amount.into().amount.to_string(), VOUCHER_INFO.to_string(), tx_hash, - identity::PrivateKey::from_base58_string( - identity::KeyPair::new(&mut rng) - .private_key() - .to_base58_string(), - ) - .unwrap(), - encryption::PrivateKey::from_bytes( - &encryption::KeyPair::new(&mut rng).private_key().to_bytes(), - ) - .unwrap(), + id_priv, + enc_priv, ); - let (_, blind_sign_req) = prepare_blind_sign( - ¶ms, - &voucher.get_private_attributes(), - &voucher.get_public_attributes(), - ) - .unwrap(); - let key_pair = ttp_keygen(¶ms, 1, 1).unwrap().remove(0); - let mut db_dir = std::env::temp_dir(); - db_dir.push(&key_pair.verification_key().to_bs58()[..8]); - let storage = NymApiStorage::init(db_dir).await.unwrap(); - let tx_db = Arc::new(RwLock::new(HashMap::new())); - tx_db - .write() - .unwrap() - .insert(tx_hash.to_string(), tx_entry.clone()); - let nyxd_client = - DummyClient::new(AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap()) - .with_tx_db(&tx_db); - let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key()); - let staged_key_pair = crate::coconut::KeyPair::new(); - staged_key_pair.set(Some(key_pair)).await; - - let rocket = rocket::build().attach(InternalSignRequest::stage( - nyxd_client, - TEST_COIN_DENOM.to_string(), - staged_key_pair, - comm_channel, - storage.clone(), - )); - let client = Client::tracked(rocket) - .await - .expect("valid rocket instance"); - - let request_body = BlindSignRequestBody::new( - &blind_sign_req, - tx_hash.to_string(), - signature.clone(), - &voucher.get_public_attributes(), + let request = BlindSignRequestBody::new( + voucher.blind_sign_request().clone(), + tx_hash, + voucher.sign(), voucher.get_public_attributes_plain(), - 4, ); - let encrypted_signature = vec![1, 2, 3, 4]; - let remote_key = [42; 32]; - let expected_response = BlindedSignatureResponse::new(encrypted_signature, remote_key); - storage - .insert_blinded_signature_response( - &tx_hash.to_string(), - &expected_response.to_base58_string(), - ) + (voucher, request) +} + +fn dummy_signature() -> identity::Signature { + "3vUCc6MCN5AC2LNgDYjRB1QeErZSN1S8f6K14JHjpUcKWXbjGYFExA8DbwQQBki9gyUqrpBF94Drttb4eMcGQXkp" + .parse() + .unwrap() +} + +async fn nym_api_storage_fixture(identity: &identity::KeyPair) -> NymApiStorage { + let mut db_dir = std::env::temp_dir(); + db_dir.push(identity.public_key().to_base58_string()); + NymApiStorage::init(db_dir).await.unwrap() +} + +struct TestFixture { + rocket: Client, + storage: NymApiStorage, + tx_db: Arc>>, + epoch: Arc, +} + +impl TestFixture { + async fn new() -> Self { + let mut rng = OsRng; + let params = Parameters::new(4).unwrap(); + let coconut_keypair = ttp_keygen(¶ms, 1, 1).unwrap().remove(0); + let identity = identity::KeyPair::new(&mut rng); + let epoch = Arc::new(AtomicU64::new(1)); + let comm_channel = + DummyCommunicationChannel::new(coconut_keypair.verification_key().clone()) + .with_epoch(epoch.clone()); + let storage = nym_api_storage_fixture(&identity).await; + + let staged_key_pair = crate::coconut::KeyPair::new(); + staged_key_pair.set(Some(coconut_keypair)).await; + + let tx_db = Arc::new(RwLock::new(HashMap::new())); + let nyxd_client = + DummyClient::new(AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap()) + .with_tx_db(&tx_db); + + let rocket = rocket::build().attach(coconut::stage( + nyxd_client, + TEST_COIN_DENOM.to_string(), + identity, + staged_key_pair, + comm_channel, + storage.clone(), + )); + + TestFixture { + rocket: Client::tracked(rocket) + .await + .expect("valid rocket instance"), + storage, + tx_db, + epoch, + } + } + + fn set_epoch(&self, epoch: u64) { + self.epoch.store(epoch, Ordering::Relaxed) + } + + fn add_tx(&self, hash: Hash, tx: TxResponse) { + self.tx_db.write().unwrap().insert(hash, tx); + } + + fn add_deposit_tx(&self, voucher: &BandwidthVoucher) { + let mut guard = self.tx_db.write().unwrap(); + let fixture = deposit_tx_fixture(voucher); + guard.insert(voucher.tx_hash(), fixture); + } + + async fn issue_dummy_credential(&self) { + let mut rng = OsRng; + let mut tx_hash = [0u8; 32]; + rng.fill_bytes(&mut tx_hash); + let tx_hash = Hash::from_bytes(Algorithm::Sha256, &tx_hash).unwrap(); + + let (voucher, req) = voucher_request_fixture(coin(1234, "unym"), Some(tx_hash.to_string())); + self.add_deposit_tx(&voucher); + + self.issue_credential(req).await; + } + + async fn issue_credential(&self, req: BlindSignRequestBody) -> BlindedSignatureResponse { + let response = self + .rocket + .post(format!( + "/{API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}/{COCONUT_BLIND_SIGN}", + )) + .json(&req) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + serde_json::from_str(&response.into_string().await.unwrap()).unwrap() + } + + async fn issued_credential(&self, id: i64) -> Option { + let response = self + .rocket + .get(format!( + "/{API_VERSION}/{COCONUT_ROUTES}/{BANDWIDTH}/issued-credential/{id}" + )) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + serde_json::from_str(&response.into_string().await.unwrap()).unwrap() + } + + async fn issued_unchecked(&self, id: i64) -> IssuedCredentialInner { + self.issued_credential(id) + .await + .unwrap() + .credential + .unwrap() + } +} + +#[tokio::test] +async fn already_issued() { + let (_, request_body) = voucher_request_fixture(coin(1234, TEST_COIN_DENOM), None); + let tx_hash = request_body.tx_hash; + let tx_entry = tx_entry_fixture(tx_hash); + + let test_fixture = TestFixture::new().await; + test_fixture.add_tx(tx_hash, tx_entry); + + let sig = blinded_signature_fixture(); + let commitments = request_body.encode_commitments(); + let public = request_body.public_attributes_plain.clone(); + test_fixture + .storage + .store_issued_credential(42, tx_hash, &sig, dummy_signature(), commitments, public) .await .unwrap(); - let response = client + let response = test_fixture + .rocket .post(format!( "/{}/{}/{}/{}", API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_BLIND_SIGN @@ -595,6 +753,7 @@ async fn signed_before() { .dispatch() .await; assert_eq!(response.status(), Status::Ok); + let expected_response = BlindedSignatureResponse::new(sig); // This is a more direct way, but there's a bug which makes it hang https://github.com/SergioBenitez/Rocket/issues/1893 // let blinded_signature_response = response @@ -612,6 +771,9 @@ async fn signed_before() { #[tokio::test] async fn state_functions() { + let mut rng = OsRng; + let identity = identity::KeyPair::new(&mut rng); + let nyxd_client = DummyClient::new(AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap()); let params = Parameters::new(4).unwrap(); @@ -619,38 +781,49 @@ async fn state_functions() { let mut db_dir = std::env::temp_dir(); db_dir.push(&key_pair.verification_key().to_bs58()[..8]); let storage = NymApiStorage::init(db_dir).await.unwrap(); - let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key()); + let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key().clone()); let staged_key_pair = crate::coconut::KeyPair::new(); staged_key_pair.set(Some(key_pair)).await; let state = State::new( nyxd_client, TEST_COIN_DENOM.to_string(), + identity, staged_key_pair, comm_channel, storage.clone(), ); - let tx_hash = String::from("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E"); - assert!(state.signed_before(&tx_hash).await.unwrap().is_none()); + let tx_hash = "6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E" + .parse() + .unwrap(); + assert!(state.already_issued(tx_hash).await.unwrap().is_none()); - let encrypted_signature = vec![1, 2, 3, 4]; - let remote_key = [42; 32]; - let expected_response = BlindedSignatureResponse::new(encrypted_signature, remote_key); + let (_, request_body) = voucher_request_fixture(coin(1234, TEST_COIN_DENOM), None); + let commitments = request_body.encode_commitments(); + let public = request_body.public_attributes_plain.clone(); + let sig = blinded_signature_fixture(); storage - .insert_blinded_signature_response(&tx_hash, &expected_response.to_base58_string()) + .store_issued_credential( + 42, + tx_hash, + &sig, + dummy_signature(), + commitments.clone(), + public.clone(), + ) .await .unwrap(); + assert_eq!( state - .signed_before(&tx_hash) + .already_issued(tx_hash) .await .unwrap() .unwrap() .to_bytes(), - expected_response.to_bytes() + blinded_signature_fixture().to_bytes() ); - let encryption_keypair = nym_crypto::asymmetric::encryption::KeyPair::new(&mut OsRng); let blinded_signature = BlindedSignature::from_bytes(&[ 183, 217, 166, 113, 40, 123, 74, 25, 72, 31, 136, 19, 125, 95, 217, 228, 96, 113, 25, 240, 12, 102, 125, 11, 174, 20, 216, 82, 192, 71, 27, 194, 48, 20, 17, 95, 243, 179, 82, 21, 57, @@ -659,68 +832,46 @@ async fn state_functions() { 222, 119, 93, 146, 116, 229, 0, 152, 51, 232, 2, 102, 204, 147, 202, 254, 243, ]) .unwrap(); + // Check that the new payload is not stored if there was already something signed for tx_hash - assert_eq!( - state - .encrypt_and_store( - &tx_hash, - encryption_keypair.public_key(), - &blinded_signature, - ) - .await - .unwrap() - .to_bytes(), - expected_response.to_bytes() - ); + let storage_err = storage + .store_issued_credential( + 42, + tx_hash, + &blinded_signature, + dummy_signature(), + commitments.clone(), + public.clone(), + ) + .await; + assert!(storage_err.is_err()); // And use a new hash to store a new signature - let tx_hash = String::from("97D64C38D6601B1F0FD3A82E20D252685CB7A210AFB0261018590659AB82B0BF"); - let response = state - .encrypt_and_store( - &tx_hash, - encryption_keypair.public_key(), + let tx_hash = "97D64C38D6601B1F0FD3A82E20D252685CB7A210AFB0261018590659AB82B0BF" + .parse() + .unwrap(); + + storage + .store_issued_credential( + 42, + tx_hash, &blinded_signature, + dummy_signature(), + commitments.clone(), + public.clone(), ) .await .unwrap(); - let remote_key = - nym_crypto::asymmetric::encryption::PublicKey::from_bytes(&response.remote_key).unwrap(); - - let encryption_key = recompute_shared_key::< - NymApiCredentialEncryptionAlgorithm, - NymApiCredentialHkdfAlgorithm, - >(&remote_key, encryption_keypair.private_key()); - let zero_iv = stream_cipher::zero_iv::(); - let blinded_signature_bytes = stream_cipher::decrypt::( - &encryption_key, - &zero_iv, - &response.encrypted_signature, - ); - - let received_blinded_signature = - BlindedSignature::from_bytes(&blinded_signature_bytes).unwrap(); - assert_eq!( - blinded_signature.to_bytes(), - received_blinded_signature.to_bytes() - ); // Check that the same value for tx_hash is returned - - let other_signature = BlindedSignature::from_bytes(&[ - 183, 217, 166, 113, 40, 123, 74, 25, 72, 31, 136, 19, 125, 95, 217, 228, 96, 113, 25, 240, - 12, 102, 125, 11, 174, 20, 216, 82, 192, 71, 27, 194, 48, 20, 17, 95, 243, 179, 82, 21, 57, - 143, 101, 19, 22, 186, 147, 13, 131, 236, 38, 138, 192, 235, 169, 142, 176, 118, 153, 238, - 141, 91, 94, 139, 168, 214, 17, 250, 96, 206, 139, 89, 139, 87, 31, 8, 106, 171, 8, 140, - 201, 158, 18, 152, 24, 98, 153, 170, 141, 35, 190, 200, 19, 148, 71, 197, - ]) - .unwrap(); assert_eq!( state - .encrypt_and_store(&tx_hash, encryption_keypair.public_key(), &other_signature,) + .already_issued(tx_hash) .await .unwrap() + .unwrap() .to_bytes(), - response.to_bytes() + blinded_signature.to_bytes() ); } @@ -731,6 +882,8 @@ async fn blind_sign_correct() { let params = Parameters::new(4).unwrap(); let mut rng = OsRng; + let nym_api_identity = identity::KeyPair::new(&mut rng); + let identity_keypair = identity::KeyPair::new(&mut rng); let encryption_keypair = encryption::KeyPair::new(&mut rng); let voucher = BandwidthVoucher::new( @@ -749,55 +902,20 @@ async fn blind_sign_correct() { let storage = NymApiStorage::init(db_dir).await.unwrap(); let tx_db = Arc::new(RwLock::new(HashMap::new())); - let mut tx_entry = tx_entry_fixture(&tx_hash.to_string()); - tx_entry.tx_result.events.push(Event { - kind: format!("wasm-{}", DEPOSITED_FUNDS_EVENT_TYPE), - attributes: vec![], - }); - tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ - EventAttribute { - key: DEPOSIT_VALUE.parse().unwrap(), - value: "1234".parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_INFO.parse().unwrap(), - value: VOUCHER_INFO.parse().unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), - value: identity_keypair - .public_key() - .to_base58_string() - .parse() - .unwrap(), - index: false, - }, - EventAttribute { - key: DEPOSIT_ENCRYPTION_KEY.parse().unwrap(), - value: encryption_keypair - .public_key() - .to_base58_string() - .parse() - .unwrap(), - index: false, - }, - ]; - tx_db - .write() - .unwrap() - .insert(tx_hash.to_string(), tx_entry.clone()); + let tx_entry = deposit_tx_fixture(&voucher); + + tx_db.write().unwrap().insert(tx_hash, tx_entry.clone()); let nyxd_client = DummyClient::new(AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap()) .with_tx_db(&tx_db); - let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key()); + let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key().clone()); let staged_key_pair = crate::coconut::KeyPair::new(); staged_key_pair.set(Some(key_pair)).await; - let rocket = rocket::build().attach(InternalSignRequest::stage( + let rocket = rocket::build().attach(coconut::stage( nyxd_client, TEST_COIN_DENOM.to_string(), + nym_api_identity, staged_key_pair, comm_channel, storage.clone(), @@ -806,15 +924,13 @@ async fn blind_sign_correct() { .await .expect("valid rocket instance"); + let request_signature = voucher.sign(); + let request_body = BlindSignRequestBody::new( - voucher.blind_sign_request(), - tx_hash.to_string(), - voucher - .sign(voucher.blind_sign_request()) - .to_base58_string(), - &voucher.get_public_attributes(), + voucher.blind_sign_request().clone(), + tx_hash, + request_signature, voucher.get_public_attributes_plain(), - 4, ); let response = client @@ -825,6 +941,7 @@ async fn blind_sign_correct() { .json(&request_body) .dispatch() .await; + assert_eq!(response.status(), Status::Ok); // This is a more direct way, but there's a bug which makes it hang https://github.com/SergioBenitez/Rocket/issues/1893 // assert!(response.into_json::().is_some()); @@ -847,26 +964,32 @@ async fn verification_of_bandwidth_credential() { let mut key_pairs = ttp_keygen(¶ms, 1, 1).unwrap(); let voucher_value = 1234u64; let voucher_info = "voucher info"; - let public_attributes = vec![ + let public_attributes = [ hash_to_scalar(voucher_value.to_string()), hash_to_scalar(voucher_info), ]; + let public_attributes_ref = vec![&public_attributes[0], &public_attributes[1]]; let indices: Vec = key_pairs .iter() .enumerate() .map(|(idx, _)| (idx + 1) as u64) .collect(); let theta = - theta_from_keys_and_attributes(¶ms, &key_pairs, &indices, &public_attributes).unwrap(); + theta_from_keys_and_attributes(¶ms, &key_pairs, &indices, &public_attributes_ref) + .unwrap(); let key_pair = key_pairs.remove(0); db_dir.push(&key_pair.verification_key().to_bs58()[..8]); let storage1 = NymApiStorage::init(db_dir).await.unwrap(); - let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key()); + let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key().clone()); let staged_key_pair = crate::coconut::KeyPair::new(); staged_key_pair.set(Some(key_pair)).await; - let rocket = rocket::build().attach(InternalSignRequest::stage( + let mut rng = OsRng; + let identity = identity::KeyPair::new(&mut rng); + + let rocket = rocket::build().attach(coconut::stage( nyxd_client.clone(), TEST_COIN_DENOM.to_string(), + identity, staged_key_pair, comm_channel.clone(), storage1.clone(), diff --git a/nym-api/src/main.rs b/nym-api/src/main.rs index 20982ef087..e63e22167f 100644 --- a/nym-api/src/main.rs +++ b/nym-api/src/main.rs @@ -80,12 +80,14 @@ async fn start_nym_api_tasks( let network_details = NetworkDetails::new(connected_nyxd.to_string(), nym_network_details); let coconut_keypair = coconut::keypair::KeyPair::new(); + let identity_keypair = config.base.storage_paths.load_identity()?; // let's build our rocket! let rocket = http::setup_rocket( &config, network_details, nyxd_client.clone(), + identity_keypair, coconut_keypair.clone(), ) .await?; diff --git a/nym-api/src/support/cli/mod.rs b/nym-api/src/support/cli/mod.rs index c339d52668..2427b5e7c8 100644 --- a/nym-api/src/support/cli/mod.rs +++ b/nym-api/src/support/cli/mod.rs @@ -126,7 +126,16 @@ pub(crate) fn build_config(args: run::Args) -> Result { } }; - let config = override_config(config, args); + let mut config = override_config(config, args); + // since we have no proper `init`, we have to do id check here: + let made_new_keys = config + .base + .storage_paths + .generate_identity_if_missing(&config.base.id)?; + + if made_new_keys { + config.save_to_default_location()? + } Ok(config) } diff --git a/nym-api/src/support/config/mod.rs b/nym-api/src/support/config/mod.rs index 6431ef611b..d4052be515 100644 --- a/nym-api/src/support/config/mod.rs +++ b/nym-api/src/support/config/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::support::config::persistence::{ - CoconutSignerPaths, NetworkMonitorPaths, NodeStatusAPIPaths, + CoconutSignerPaths, NetworkMonitorPaths, NodeStatusAPIPaths, NymApiPaths, }; use crate::support::config::template::CONFIG_TEMPLATE; use nym_config::defaults::{mainnet, NymNetworkDetails}; @@ -21,6 +21,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; pub(crate) mod helpers; pub(crate) mod old_config_v1_1_21; pub(crate) mod old_config_v1_1_27; + mod persistence; mod template; @@ -272,22 +273,29 @@ impl Config { #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Zeroize, ZeroizeOnDrop)] pub struct Base { /// ID specifies the human readable ID of this particular nym-api. - id: String, + pub id: String, #[zeroize(skip)] - local_validator: Url, + pub local_validator: Url, /// Address of the validator contract managing the network #[zeroize(skip)] - mixnet_contract_address: nyxd::AccountId, + pub mixnet_contract_address: nyxd::AccountId, /// Address of the vesting contract holding locked tokens #[zeroize(skip)] - vesting_contract_address: nyxd::AccountId, + pub vesting_contract_address: nyxd::AccountId, /// Mnemonic used for rewarding and/or multisig operations // TODO: similarly to the note in gateway, this should get moved to a separate file mnemonic: bip39::Mnemonic, + + /// Storage paths to the common nym-api files + #[zeroize(skip)] + // ideally we wouldn't be using default here, but I really really don't want to be writing + // another big config migration + #[serde(default)] + pub storage_paths: NymApiPaths, } impl Base { @@ -296,8 +304,11 @@ impl Base { .parse() .expect("default local validator is malformed!"); + let id = id.into(); + Base { - id: id.into(), + storage_paths: NymApiPaths::new_default(&id), + id, local_validator: default_validator, mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS.parse().unwrap(), vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS.parse().unwrap(), diff --git a/nym-api/src/support/config/old_config_v1_1_21.rs b/nym-api/src/support/config/old_config_v1_1_21.rs index 3eee079a53..39058c3844 100644 --- a/nym-api/src/support/config/old_config_v1_1_21.rs +++ b/nym-api/src/support/config/old_config_v1_1_21.rs @@ -90,6 +90,7 @@ impl From for Config { mixnet_contract_address: value.base.mixnet_contract_address, vesting_contract_address: value.base.vesting_contract_address, mnemonic: value.base.mnemonic, + storage_paths: Default::default(), }, network_monitor: NetworkMonitor { enabled: value.network_monitor.enabled, diff --git a/nym-api/src/support/config/old_config_v1_1_27.rs b/nym-api/src/support/config/old_config_v1_1_27.rs index 3243147bc4..550c14c1bf 100644 --- a/nym-api/src/support/config/old_config_v1_1_27.rs +++ b/nym-api/src/support/config/old_config_v1_1_27.rs @@ -60,6 +60,7 @@ impl From for Config { mixnet_contract_address: value.base.mixnet_contract_address, vesting_contract_address: value.base.vesting_contract_address, mnemonic: value.base.mnemonic, + storage_paths: Default::default(), }, network_monitor: NetworkMonitor { enabled: value.network_monitor.enabled, diff --git a/nym-api/src/support/config/persistence.rs b/nym-api/src/support/config/persistence.rs index 7d4e58190a..24a16a4bae 100644 --- a/nym-api/src/support/config/persistence.rs +++ b/nym-api/src/support/config/persistence.rs @@ -2,6 +2,10 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::support::config::default_data_directory; +use anyhow::{anyhow, Context}; +use nym_config::serde_helpers::de_maybe_stringified; +use nym_crypto::asymmetric::identity; +use rand_07::rngs::OsRng; use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; @@ -15,6 +19,9 @@ pub const DEFAULT_DKG_PUBLIC_KEY_WITH_PROOF_FILENAME: &str = "dkg_public_key_wit pub const DEFAULT_COCONUT_VERIFICATION_KEY_FILENAME: &str = "coconut_verification_key.pem"; pub const DEFAULT_COCONUT_SECRET_KEY_FILENAME: &str = "coconut_secret_key.pem"; +pub const DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME: &str = "private_identity.pem"; +pub const DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME: &str = "public_identity.pem"; + // #[derive(Debug, Deserialize, PartialEq, Eq, Serialize)] // pub struct NymApiPathfinder { // pub network_monitor: NetworkMonitorPathfinder, @@ -99,3 +106,66 @@ impl CoconutSignerPaths { } } } + +#[derive(Debug, Default, Deserialize, PartialEq, Eq, Serialize)] +#[serde(default)] +pub struct NymApiPaths { + /// Path to file containing private identity key of the nym-api. + #[serde(deserialize_with = "de_maybe_stringified")] + pub private_identity_key_file: Option, + + /// Path to file containing public identity key of the nym-api. + #[serde(deserialize_with = "de_maybe_stringified")] + pub public_identity_key_file: Option, +} + +impl NymApiPaths { + pub fn new_default>(id: P) -> Self { + let data_dir = default_data_directory(id); + + NymApiPaths { + private_identity_key_file: Some(data_dir.join(DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME)), + public_identity_key_file: Some(data_dir.join(DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME)), + } + } + + pub fn generate_identity_if_missing>(&mut self, id: P) -> anyhow::Result { + if self.private_identity_key_file.is_none() { + log::warn!("identity key paths are not set - going to generate a fresh pair!"); + + let data_dir = default_data_directory(id); + self.private_identity_key_file = + Some(data_dir.join(DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME)); + self.public_identity_key_file = + Some(data_dir.join(DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME)); + + let keypaths = nym_pemstore::KeyPairPath::new( + self.private_identity_key_file.as_ref().unwrap(), + self.public_identity_key_file.as_ref().unwrap(), + ); + + let mut rng = OsRng; + let keypair = identity::KeyPair::new(&mut rng); + + nym_pemstore::store_keypair(&keypair, &keypaths) + .context("failed to store identity keys of the nym api")?; + Ok(true) + } else { + Ok(false) + } + } + + pub fn load_identity(&self) -> anyhow::Result { + // if somebody has set their private key but removed public key, the panic is totally on them. + let keypaths = nym_pemstore::KeyPairPath::new( + self.private_identity_key_file + .as_ref() + .ok_or(anyhow!("private key path is not specified"))?, + self.public_identity_key_file + .as_ref() + .ok_or(anyhow!("public key path is not specified"))?, + ); + + nym_pemstore::load_keypair(&keypaths).context("failed to load identity keys of the nym api") + } +} diff --git a/nym-api/src/support/config/template.rs b/nym-api/src/support/config/template.rs index 88b0fb85d7..21d8487762 100644 --- a/nym-api/src/support/config/template.rs +++ b/nym-api/src/support/config/template.rs @@ -24,6 +24,12 @@ vesting_contract_address = '{{ base.vesting_contract_address }}' # Mnemonic used for rewarding and validator interaction mnemonic = '{{ base.mnemonic }}' +[base.storage_paths] +# Path to file containing private identity key of the nym-api. +keys.private_identity_key_file = '{{ base.storage_paths.private_identity_key_file }}' + +# Path to file containing public identity key of the nym-api. +keys.public_identity_key_file = '{{ base.storage_paths.public_identity_key_file }}' ##### network monitor config options ##### diff --git a/nym-api/src/support/http/mod.rs b/nym-api/src/support/http/mod.rs index be46cb73d6..88ded2ca45 100644 --- a/nym-api/src/support/http/mod.rs +++ b/nym-api/src/support/http/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::circulating_supply_api::cache::CirculatingSupplyCache; -use crate::coconut::{self, comm::QueryCommunicationChannel, InternalSignRequest}; +use crate::coconut::{self, comm::QueryCommunicationChannel}; use crate::network::models::NetworkDetails; use crate::network::network_routes; use crate::node_describe_cache::DescribedNodes; @@ -13,6 +13,7 @@ use crate::support::config::Config; use crate::support::{nyxd, storage}; use crate::{circulating_supply_api, nym_contract_cache, nym_nodes::nym_node_routes}; use anyhow::Result; +use nym_crypto::asymmetric::identity; use rocket::http::Method; use rocket::{Ignite, Rocket}; use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors}; @@ -25,6 +26,7 @@ pub(crate) async fn setup_rocket( config: &Config, network_details: NetworkDetails, _nyxd_client: nyxd::Client, + identity_keypair: identity::KeyPair, coconut_keypair: coconut::keypair::KeyPair, ) -> anyhow::Result> { let openapi_settings = rocket_okapi::settings::OpenApiSettings::default(); @@ -66,9 +68,10 @@ pub(crate) async fn setup_rocket( let rocket = if config.coconut_signer.enabled { let comm_channel = QueryCommunicationChannel::new(_nyxd_client.clone()); - rocket.attach(InternalSignRequest::stage( + rocket.attach(coconut::stage( _nyxd_client.clone(), mix_denom, + identity_keypair, coconut_keypair, comm_channel, storage.clone().unwrap(), diff --git a/nym-api/src/support/nyxd/mod.rs b/nym-api/src/support/nyxd/mod.rs index 4c08df3eb9..3c04803226 100644 --- a/nym-api/src/support/nyxd/mod.rs +++ b/nym-api/src/support/nyxd/mod.rs @@ -283,11 +283,13 @@ impl crate::coconut::client::Client for Client { self.client_address().await } - async fn get_tx(&self, tx_hash: &str) -> crate::coconut::error::Result { - let tx_hash: Hash = tx_hash - .parse() - .map_err(|_| CoconutError::TxHashParseError)?; - Ok(self.0.read().await.get_tx(tx_hash).await?) + async fn get_tx(&self, tx_hash: Hash) -> crate::coconut::error::Result { + self.0.read().await.get_tx(tx_hash).await.map_err(|source| { + CoconutError::TxRetrievalFailure { + tx_hash: tx_hash.to_string(), + source, + } + }) } async fn get_proposal( diff --git a/nym-api/src/support/storage/manager.rs b/nym-api/src/support/storage/manager.rs index 2bb3fa5c99..4e3c23c1e9 100644 --- a/nym-api/src/support/storage/manager.rs +++ b/nym-api/src/support/storage/manager.rs @@ -487,15 +487,15 @@ impl StorageManager { // insert the actual status sqlx::query!( - r#" - INSERT INTO mixnode_status (mixnode_details_id, reliability, timestamp) VALUES (?, ?, ?); - "#, - mixnode_id, - mixnode_result.reliability, - timestamp - ) - .execute(&mut tx) - .await?; + r#" + INSERT INTO mixnode_status (mixnode_details_id, reliability, timestamp) VALUES (?, ?, ?); + "#, + mixnode_id, + mixnode_result.reliability, + timestamp + ) + .execute(&mut tx) + .await?; } // finally commit the transaction @@ -972,45 +972,4 @@ impl StorageManager { Ok(active_day_statuses) } - - /// Creates new encrypted blinded signature response entry for a given deposit tx hash. - /// - /// # Arguments - /// - /// * `tx_hash`: hash of the deposit transaction. - /// * `blinded_signature_response`: the encrypted blinded signature response. - pub(crate) async fn insert_blinded_signature_response( - &self, - tx_hash: &str, - blinded_signature_response: &str, - ) -> Result<(), sqlx::Error> { - sqlx::query!( - "INSERT INTO signed_deposit(tx_hash, blinded_signature_response) VALUES (?, ?)", - tx_hash, - blinded_signature_response - ) - .execute(&self.connection_pool) - .await?; - Ok(()) - } - - /// Tries to obtain encrypted blinded signature response for a given transaction hash. - /// - /// # Arguments - /// - /// * `tx_hash`: transaction hash of the deposit. - pub(crate) async fn get_blinded_signature_response( - &self, - tx_hash: &str, - ) -> Result, sqlx::Error> { - let blinded_signature_response = sqlx::query!( - "SELECT blinded_signature_response FROM signed_deposit WHERE tx_hash = ?", - tx_hash - ) - .fetch_optional(&self.connection_pool) - .await? - .map(|row| row.blinded_signature_response); - - Ok(blinded_signature_response) - } } diff --git a/nym-api/src/support/storage/mod.rs b/nym-api/src/support/storage/mod.rs index 4ae899aac1..3cd1e350cd 100644 --- a/nym-api/src/support/storage/mod.rs +++ b/nym-api/src/support/storage/mod.rs @@ -716,25 +716,4 @@ impl NymApiStorage { .await .map_err(|err| err.into()) } - - pub(crate) async fn get_blinded_signature_response( - &self, - tx_hash: &str, - ) -> Result, NymApiStorageError> { - self.manager - .get_blinded_signature_response(tx_hash) - .await - .map_err(|err| err.into()) - } - - pub(crate) async fn insert_blinded_signature_response( - &self, - tx_hash: &str, - blinded_signature_response: &str, - ) -> Result<(), NymApiStorageError> { - self.manager - .insert_blinded_signature_response(tx_hash, blinded_signature_response) - .await - .map_err(|err| err.into()) - } } diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 90510b9aa9..a031a0ad4a 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -569,27 +569,13 @@ dependencies = [ [[package]] name = "bls12_381" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397" +version = "0.8.0" +source = "git+https://github.com/jstuczyn/bls12_381?branch=feature/gt-serialization-0.8.0#c4543fde7d02efea6ecfcf22e14476ddb516b483" dependencies = [ "digest 0.9.0", - "ff 0.10.1", - "group 0.10.0", - "pairing 0.20.0", - "rand_core 0.6.4", - "subtle 2.4.1", -] - -[[package]] -name = "bls12_381" -version = "0.6.0" -source = "git+https://github.com/jstuczyn/bls12_381?branch=gt-serialisation#10fb6f700bfda17c8475af3bfd31e3fec15f2278" -dependencies = [ - "digest 0.9.0", - "ff 0.11.1", - "group 0.11.0", - "pairing 0.21.0", + "ff 0.13.0", + "group 0.13.0", + "pairing", "rand_core 0.6.4", "subtle 2.4.1", "zeroize", @@ -1352,6 +1338,7 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", + "serde", "subtle 2.4.1", "zeroize", ] @@ -1779,6 +1766,7 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ + "serde", "signature 1.6.4", ] @@ -1815,6 +1803,7 @@ dependencies = [ "ed25519 1.5.3", "rand 0.7.3", "serde", + "serde_bytes", "sha2 0.9.9", "zeroize", ] @@ -2038,26 +2027,6 @@ dependencies = [ "log", ] -[[package]] -name = "ff" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" -dependencies = [ - "rand_core 0.6.4", - "subtle 2.4.1", -] - -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.4", - "subtle 2.4.1", -] - [[package]] name = "ff" version = "0.12.1" @@ -2074,6 +2043,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ + "bitvec", "rand_core 0.6.4", "subtle 2.4.1", ] @@ -2663,30 +2633,6 @@ dependencies = [ "system-deps 6.1.1", ] -[[package]] -name = "group" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" -dependencies = [ - "byteorder", - "ff 0.10.1", - "rand_core 0.6.4", - "subtle 2.4.1", -] - -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "byteorder", - "ff 0.11.1", - "rand_core 0.6.4", - "subtle 2.4.1", -] - [[package]] name = "group" version = "0.12.1" @@ -3411,9 +3357,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libgit2-sys" @@ -3656,9 +3602,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -3860,10 +3806,12 @@ dependencies = [ "cosmwasm-std", "getset", "nym-coconut-interface", + "nym-crypto", "nym-mixnet-contract-common", "nym-node-requests", "schemars", "serde", + "tendermint", ] [[package]] @@ -3880,6 +3828,7 @@ dependencies = [ "rand 0.7.3", "thiserror", "url", + "zeroize", ] [[package]] @@ -3950,12 +3899,12 @@ dependencies = [ name = "nym-coconut" version = "0.5.0" dependencies = [ - "bls12_381 0.6.0", + "bls12_381", "bs58 0.4.0", "digest 0.9.0", - "ff 0.11.1", + "ff 0.13.0", "getrandom 0.2.10", - "group 0.11.0", + "group 0.13.0", "itertools", "nym-dkg", "nym-pemstore", @@ -4088,7 +4037,7 @@ dependencies = [ name = "nym-credentials" version = "0.1.0" dependencies = [ - "bls12_381 0.5.0", + "bls12_381", "cosmrs", "log", "nym-api-requests", @@ -4096,6 +4045,7 @@ dependencies = [ "nym-crypto", "nym-validator-client", "thiserror", + "zeroize", ] [[package]] @@ -4115,6 +4065,8 @@ dependencies = [ "nym-pemstore", "nym-sphinx-types", "rand 0.7.3", + "serde", + "serde_bytes", "subtle-encoding", "thiserror", "x25519-dalek 1.1.1", @@ -4126,10 +4078,10 @@ name = "nym-dkg" version = "0.1.0" dependencies = [ "bitvec", - "bls12_381 0.6.0", + "bls12_381", "bs58 0.4.0", - "ff 0.11.1", - "group 0.11.0", + "ff 0.13.0", + "group 0.13.0", "lazy_static", "nym-pemstore", "rand 0.8.5", @@ -4871,20 +4823,11 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pairing" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de9d09263c9966e8196fe0380c9dbbc7ea114b5cf371ba29004bc1f9c6db7f3" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" dependencies = [ - "group 0.10.0", -] - -[[package]] -name = "pairing" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42" -dependencies = [ - "group 0.11.0", + "group 0.13.0", ] [[package]] @@ -6494,9 +6437,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", @@ -7448,9 +7391,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.31.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -7459,16 +7402,16 @@ dependencies = [ "num_cpus", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.5", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", @@ -7557,9 +7500,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -8625,6 +8568,7 @@ checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" dependencies = [ "curve25519-dalek 3.2.0", "rand_core 0.5.1", + "serde", "zeroize", ] diff --git a/sdk/rust/nym-sdk/Cargo.toml b/sdk/rust/nym-sdk/Cargo.toml index fb5cbf4ac8..63e60e281f 100644 --- a/sdk/rust/nym-sdk/Cargo.toml +++ b/sdk/rust/nym-sdk/Cargo.toml @@ -49,7 +49,7 @@ nym-bin-common = { path = "../../../common/bin-common" } # extra dependencies for libp2p examples libp2p = { git = "https://github.com/ChainSafe/rust-libp2p.git", rev = "e3440d25681df380c9f0f8cfdcfd5ecc0a4f2fb6", features = [ "identify", "macros", "ping", "tokio", "tcp", "dns", "websocket", "noise", "mplex", "yamux", "gossipsub" ]} tokio-stream = "0.1.12" -tokio-util = { version = "0.7", features = ["codec"] } +tokio-util = { workspace = true, features = ["codec"] } parking_lot = "0.12" hex = "0.4" From d331e75375485bcabe234e0f64be5f6839ba0acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 18 Dec 2023 12:27:25 +0000 Subject: [PATCH 7/7] reduced log severity when verloc connection fails --- common/mixnode-common/src/verloc/listener.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/mixnode-common/src/verloc/listener.rs b/common/mixnode-common/src/verloc/listener.rs index b91b7f50bc..fada769a76 100644 --- a/common/mixnode-common/src/verloc/listener.rs +++ b/common/mixnode-common/src/verloc/listener.rs @@ -108,13 +108,13 @@ impl ConnectionHandler { let reply_packet = match maybe_echo_packet { Some(Ok(echo_packet)) => self.handle_echo_packet(echo_packet), Some(Err(err)) => { - error!( + debug!( "The socket connection got corrupted with error: {err}. Closing the socket", ); return; } None => { - error!("The socket connection got terminated by the remote!"); + debug!("The socket connection got terminated by the remote!"); return; } }; @@ -125,7 +125,7 @@ impl ConnectionHandler { .write_all(reply_packet.to_bytes().as_ref()) .await { - error!( + debug!( "Failed to write reply packet back to the sender - {}. Closing the socket on our end", err );