From 86c01054ce6fa94f8c2774f96a44f5cd056ef29c Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 18:31:16 -0400 Subject: [PATCH 01/15] refactor!: remove gg20 support --- Cargo.lock | 2 +- Cargo.toml | 4 +- Makefile | 8 +- README.md | 313 ++------ src/config/malicious.rs | 96 --- src/config/mod.rs | 26 +- src/encrypted_sled/mod.rs | 2 +- src/encrypted_sled/tests.rs | 4 +- src/gg20/broadcast.rs | 176 ----- src/gg20/key_presence.rs | 36 - src/gg20/keygen/execute.rs | 77 -- src/gg20/keygen/init.rs | 351 --------- src/gg20/keygen/mod.rs | 154 ---- src/gg20/keygen/result.rs | 200 ------ src/gg20/keygen/types.rs | 105 --- src/gg20/mod.rs | 134 ---- src/gg20/proto_helpers.rs | 98 --- src/gg20/protocol.rs | 188 ----- src/gg20/recover.rs | 170 ----- src/gg20/service/malicious.rs | 10 - src/gg20/service/mod.rs | 20 - src/gg20/sign/execute.rs | 59 -- src/gg20/sign/init.rs | 166 ----- src/gg20/sign/mod.rs | 118 ---- src/gg20/sign/result.rs | 59 -- src/gg20/sign/types.rs | 245 ------- src/kv_manager/kv.rs | 7 +- src/kv_manager/tests.rs | 2 +- src/kv_manager/value.rs | 19 +- src/main.rs | 12 - src/mnemonic/bip39_bindings.rs | 2 +- src/mnemonic/cmd_handler.rs | 10 +- src/mnemonic/file_io.rs | 4 +- src/mnemonic/mod.rs | 2 + src/mnemonic/types.rs | 13 + src/multisig/keypair.rs | 4 +- src/tests/honest_test_cases.rs | 80 --- src/tests/malicious/keygen_test_cases.rs | 190 ----- src/tests/malicious/mod.rs | 48 -- src/tests/malicious/sign_test_cases.rs | 243 ------- src/tests/mnemonic.rs | 11 +- src/tests/mock.rs | 94 --- src/tests/mod.rs | 865 +---------------------- src/tests/tofnd_party.rs | 427 +---------- 44 files changed, 109 insertions(+), 4745 deletions(-) delete mode 100644 src/config/malicious.rs delete mode 100644 src/gg20/broadcast.rs delete mode 100644 src/gg20/key_presence.rs delete mode 100644 src/gg20/keygen/execute.rs delete mode 100644 src/gg20/keygen/init.rs delete mode 100644 src/gg20/keygen/mod.rs delete mode 100644 src/gg20/keygen/result.rs delete mode 100644 src/gg20/keygen/types.rs delete mode 100644 src/gg20/mod.rs delete mode 100644 src/gg20/proto_helpers.rs delete mode 100644 src/gg20/protocol.rs delete mode 100644 src/gg20/recover.rs delete mode 100644 src/gg20/service/malicious.rs delete mode 100644 src/gg20/service/mod.rs delete mode 100644 src/gg20/sign/execute.rs delete mode 100644 src/gg20/sign/init.rs delete mode 100644 src/gg20/sign/mod.rs delete mode 100644 src/gg20/sign/result.rs delete mode 100644 src/gg20/sign/types.rs create mode 100644 src/mnemonic/types.rs delete mode 100644 src/tests/honest_test_cases.rs delete mode 100644 src/tests/malicious/keygen_test_cases.rs delete mode 100644 src/tests/malicious/mod.rs delete mode 100644 src/tests/malicious/sign_test_cases.rs delete mode 100644 src/tests/mock.rs diff --git a/Cargo.lock b/Cargo.lock index 8872bc2a..ca65d873 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2379,7 +2379,7 @@ dependencies = [ [[package]] name = "tofnd" -version = "0.10.2" +version = "0.11.0" dependencies = [ "anyhow", "atty", diff --git a/Cargo.toml b/Cargo.toml index 89a5d566..70b5eeb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tofnd" -version = "0.10.2" +version = "0.11.0" authors = ["Gus Gutoski ", "Stelios Daveas "] edition = "2018" license = "MIT OR Apache-2.0" @@ -63,5 +63,3 @@ panic = "unwind" panic = "unwind" [features] -# when we compile tofnd with malicious build, also use malicious build for tofn -malicious = ["tofn/malicious"] diff --git a/Makefile b/Makefile index 61ac92dd..454c98df 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,6 @@ docker-image: git-submodule-setup @DOCKER_BUILDKIT=1 docker build --ssh default -t axelar/tofnd . -.PHONY: docker-image-malicious -docker-image-malicious: git-submodule-setup - @DOCKER_BUILDKIT=1 docker build --ssh default --build-arg features="malicious" -t axelar/tofnd-malicious . - - .PHONY: copy-binary copy-binary-from-image: guard-SEMVER ./scripts/copy-binaries-from-image.sh @@ -20,7 +15,6 @@ upload-binaries-to-s3: guard-S3_PATH .PHONY: docker-image-all docker-image-all: git-submodule-setup make docker-image - make docker-image-malicious .PHONY: git-submodule-setup git-submodule-setup: @@ -28,4 +22,4 @@ git-submodule-setup: git submodule update guard-%: - @ if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi \ No newline at end of file + @ if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi diff --git a/README.md b/README.md index 85879801..a653edff 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,39 @@ # Tofnd: A gRPC threshold signature scheme daemon -Tofnd is a [gRPC](https://grpc.io/) server written in Rust that wraps the [tofn](https://github.com/axelarnetwork/tofn) threshold cryptography library. +Tofnd is a [gRPC](https://grpc.io/) server written in Rust that wraps the [tofn](https://github.com/axelarnetwork/tofn) cryptography library. -# Setup +## Setup The gRPC protobuf file is a separate [submodule](https://github.com/axelarnetwork/grpc-protobuf/). To fetch it, please be sure that the `--recursive` flag is enabled: -``` + +```bash git clone git@github.com:axelarnetwork/tofnd.git --recursive ``` -`tofnd` uses the [hyperium/tonic](https://github.com/hyperium/tonic) Rust gRPC implementation, which requires: -* Rust `1.56` or greater - ``` - $ rustup update - ``` -* `rustfmt` to tidy up the code it generates - ``` - $ rustup component add rustfmt - ``` +## Build binaries -`tofnd` depends on `tofn`, which needs the GNU Multiple Precision Arithmetic Library -* MacOS: `brew install gmp` -* Ubuntu: `sudo apt install libgmp-dev` +Pre-built releases can be found [here](https://github.com/axelarnetwork/tofnd/releases) -# Build binaries +To build yourself, run: -The pipeline will build binaries for the following OS/architecures : - -* Linux AMD64 -* MacOS AMD64 -* MacOS ARM64 - -See https://github.com/axelarnetwork/tofnd/releases - -For any other OS/Architecture, binaries should be built locally. +```bash +cargo build --release --locked +``` -# Running the server +## Running the server -``` +```bash # install tofnd at ./target/release/tofnd -$ cargo install --path . && cd ./target/release +cargo install --locked --path . && cd ./target/release # init tofnd -$ ./tofnd -m create +./tofnd -m create # IMPORTANT: store the content of ./.tofnd/export file at a safe, offline place, and then delete the file -$ rm ./.tofnd/export +rm ./.tofnd/export # start tofnd daemon -$ ./tofnd +./tofnd ``` Terminate the server with `ctrl+C`. @@ -59,21 +44,21 @@ By default, `tofnd` prompts for a password from stdin immediately upon launch. Users may automate password entry as they see fit. Some examples follow. These examples are not necessarily secure as written---it's the responsibility of the user to secure password entry. -``` +```bash # feed password from MacOS keyring -$ security find-generic-password -a $(whoami) -s "tofnd" -w | ./tofnd +security find-generic-password -a $(whoami) -s "tofnd" -w | ./tofnd # feed password from 1password-cli -$ op get item tofnd --fields password | ./tofnd +op get item tofnd --fields password | ./tofnd # feed password from Pass -$ pass show tofnd | ./tofnd +pass show tofnd | ./tofnd # feed password from environment variable `PASSWORD` -$ echo $PASSWORD | ./tofnd +echo $PASSWORD | ./tofnd # feed password from a file `password.txt` -$ cat ./password.txt | ./tofnd +cat ./password.txt | ./tofnd ``` Sophisticated users may explicitly opt out of password entry via the `--no-password` terminal argument (see below). In this case, on-disk storage is not secure---it is the responsibility of the user to take additional steps to secure on-disk storage. @@ -83,15 +68,17 @@ Sophisticated users may explicitly opt out of password entry via the `--no-passw We use [clap](https://clap.rs/) to manage command line arguments. Users can specify: -1. Tofnd's root folder. Use `--directory` or `-d` to specify a full or a relative path. If no argument is provided, then the environment variable `TOFND_HOME` is used. If no environment variable is set either, the default `./tofnd` directory is used. + +1. Tofnd's root folder. Use `--directory` or `-d` to specify a full or a relative path. If no argument is provided, then the environment variable `TOFND_HOME` is used. If no environment variable is set either, the default `./tofnd` directory is used. 2. The port number of the gRPC server (default is 50051). 3. The option to run in _unsafe_ mode. By default, this option is off, and safe primes are used for keygen. Use the `--unsafe` flag only for testing. 4. `mnemonic` operations for their `tofnd` instance (default is `Existing`). For more information, see on mnemonic options, see [Mnemonic](#mnemonic). -4. The option to run in _unsafe_ mode. By default, this option is off, and safe primes are used for keygen. **Attention: Use the `--unsafe` flag only for testing**. -5. By default, `tofnd` expects a password from the standard input. Users that don't want to use passwords can use the `--no-password` flag. **Attention: Use `--no-password` only for testing .** -``` -A threshold signature scheme daemon +5. The option to run in _unsafe_ mode. By default, this option is off, and safe primes are used for keygen. **Attention: Use the `--unsafe` flag only for testing**. +6. By default, `tofnd` expects a password from the standard input. Users that don't want to use passwords can use the `--no-password` flag. **Attention: Use `--no-password` only for testing .** + +```text +A cryptographic signing service USAGE: tofnd [FLAGS] [OPTIONS] @@ -111,44 +98,45 @@ OPTIONS: -p, --port [default: 50051]] ``` -# Docker +## Docker -## Setup +### Setup To setup a `tofnd` container, use the `create` mnemonic command: -``` +```bash docker-compose run -e MNEMONIC_CMD=create tofnd ``` This will initialize `tofnd`, and then exit. -## Execution +### Execution To run a `tofnd` daemon inside a container, run: -``` +```bash docker-compose up ``` -## Storage +### Storage We use [data containers](https://docs.docker.com/engine/reference/commandline/volume_create/) to persist data across restarts. To clean up storage, remove all `tofnd` containers, and run -``` +```bash docker volume rm tofnd_tofnd ``` -## Testing +### Testing For testing purposes, `docker-compose.test.yml` is available, which is equivelent to `./tofnd --no-password --unsafe`. To spin up a test `tofnd` container, run -``` +```bash docker-compose -f docker-compose.test.yml up ``` -## The `auto` command +### The `auto` command In containerized environments the `auto` mnemonic command can be used. This command is implemented in `entrypoint.sh` and does the following: + 1. Try to use existing mnemonic. If successful then launch `tofnd` server. 2. Try to import a mnemonic from file. If successful then launch `tofnd` server. 3. Create a new mnemonic. The newly created mnemonic is automatically written to the file `TOFND_HOME/export`---rename this file to `TOFND_HOME/import` so as to unblock future executions of tofnd. Then launch `tofnd` server. @@ -158,13 +146,11 @@ The rationale behind `auto` is that users can frictionlessly launch and restart **Attention:** `auto` leaves the mnemonic on plain text on disk. You should remove the `TOFND_HOME/import` file and store the mnemonic at a safe, offline place. -# Mnemonic - -`Tofnd` uses the [tiny-bip39](https://docs.rs/crate/tiny-bip39/0.8.0) crate to enable users manage mnemonic passphrases. Currently, each party can use only one passphrase. +## Mnemonic -Mnemonic is used to enable _recovery_ of shares in case of unexpected loss. See more about recovery under the [Recover](#Recover) section. +`Tofnd` uses the [tiny-bip39](https://docs.rs/crate/tiny-bip39) crate to enable users manage mnemonic passphrases. Currently, each party can use only one passphrase. -## Mnemonic options +### Mnemonic options The command line API supports the following commands: @@ -178,226 +164,35 @@ The command line API supports the following commands: ## Zeroization -We use the [zeroize](https://docs.rs/zeroize/1.1.1/zeroize/) crate to clear sensitive info for memory as a good procatie. The data we clean are related to the mnemonic: +We use the [zeroize](https://docs.rs/zeroize/1.1.1/zeroize/) crate to clear sensitive info for memory as a good practice. The data we clean are related to the mnemonic: + 1. entropy 2. passwords 3. passphrases -Note that, [tiny-bip39](https://docs.rs/crate/tiny-bip39/0.8.0) also uses `zeroize` internally. +Note that, [tiny-bip39](https://docs.rs/crate/tiny-bip39) also uses `zeroize` internally. -# KV Store +## KV Store To persist information between different gRPCs (i.e. _keygen_ and _sign_), we use a key-value storage based on [sled](https://sled.rs/). -`Tofnd` uses two separate KV Stores: -1. `Share KV Store`. Stores all user's shares when `keygen` protocol is completed, and uses them for `sign` protocol. Default path is _./kvstore/shares_. -2. `Mnemonic KV Store`. Stores the entropy of a mnemonic passphrase. This entropy is used to encrypt and decrypt users' sensitive info, i.e. the content of the `Share KV Store`. Default path is _./kvstore/mnemonic_. +`Tofnd` uses an encrypted mnemonic KV Store which stores the entropy of a mnemonic passphrase. This entropy is used to derive user's keys. The KV Store is encrypted with a password provided by the user. The password is used to derive a key that encrypts the KV Store. ## Security **Important note**: Currently, the `mnemonic KV Store` is **not** encrypted. The mnemonic entropy is stored in clear text on disk. Our current security model assumes secure device access. -# Multiple shares - -Multiple shares are handled internally. That is, if a party has 3 shares, the `tofnd` binary spawns 3 protocol execution threads, and each thread invokes `tofn` functions independently. - -When a message is received from the gRPC client, it is broadcasted to all shares. This is done in the [broadcast](https://github.com/axelarnetwork/tofnd/tree/main/src/gg20/broadcast.rs) module. - -At the end of the protocol, the outputs of all N party's shares are aggregated and a single result is created and sent to the client. There are separate modules [keygen result](https://github.com/axelarnetwork/tofnd/tree/main/src/gg20/keygen/result.rs) and [sign result](https://github.com/axelarnetwork/tofnd/tree/main/src/gg20/sign/result.rs) that handles the aggregation results for each protocol. - -For `tofn` support on multiple shares, see [here](https://github.com/axelarnetwork/tofn#support-for-multiple-shares-per-party). - -# gRPCs -Tofnd currently supports the following gRPCs: -1. `keygen` -2. `sign` -3. `recover` - -`Keygen` and `sign` use [bidirectional streaming](https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc) and `recover` is [unary](https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc). - -## Diagrams - -See a generic protocol sequence diagram, [here](https://github.com/axelarnetwork/tofnd/blob/main/diagrams/protocol.pdf). - -See [keygen](https://github.com/axelarnetwork/tofnd/blob/main/diagrams/keygen.svg) and [sign](https://github.com/axelarnetwork/tofnd/blob/main/diagrams/sign.svg) diagrams of detailed message flow of each protocol. By opening the `.svg` files at a new tab (instead of previewing from github), hyperlinks will be available that will point you to the code block in which the underlying operations are implemented. - -## Keygen -The _keygen_ gRPC executes the keygen protocol as implemented in [tofn](https://github.com/axelarnetwork/tofn) and described in [GG20](https://eprint.iacr.org/2020/540.pdf). - -The initialization of _keygen_ is actualized by the following message: - -``` -message KeygenInit { - string new_key_uid; // keygen's identifier - repeated string party_uids; - repeated uint32 party_share_counts; - int32 my_party_index; - int32 threshold; -} -``` - -### Successful keygen -On success, the _keygen_ protocol returns a `SecretKeyShare` struct defined by `tofn` -``` -pub struct SecretKeyShare { - group: GroupPublicInfo, - share: ShareSecretInfo, -} -``` - -This struct includes: -1. The information that is needed by the party in order to participate in subsequent _sign_ protocols that are associated with the completed _keygen_. -2. The `public key` of the current _keygen_. - -Since multiple shares per party are supported, _keygen_'s result may produce multiple `SecretKeyShare`s. The collection of `SecretKeyShare`s is stored in the `Share KV Store` as the _value_ with the `key_uid` as _key_. - -Each `SecretKeyShare` is then encrypted using the party's `mnemonic`, and the encrypted data is sent to the client as bytes, along with the `public key`. We send the encrypted `SecretKeyShare`s to facilitate _recovery_ in case of data loss. - -The gRPC message of _keygen_'s data is the following: -``` -message KeygenOutput { - bytes pub_key = 1; // pub_key - repeated bytes share_recovery_infos = 2; // recovery info -} -``` - -### Unsuccessful keygen - -The `tofn` library supports fault detection. That is, if a party does not follow the protocol (e.g. by corrupting zero knowledge proofs, stalling messages etc), a fault detection mechanism is triggered, and the protocol ends prematurely with all honest parties composing a faulter list. - -In this case, instead of the aforementioned result, _keygen_ returns a `Vec`, which is sent over the gRPC stream before closing the connection. - -### File structure -_Keygen_ is implemented in [tofnd/src/gg20/keygen](https://github.com/axelarnetwork/tofnd/tree/main/src/gg20/keygen), which has the following file structure: - -``` -├── keygen - ├── mod.rs - ├── init.rs - ├── execute.rs - ├── result.rs - └── types.rs -``` - -* In `mod.rs`, the handlers of protocol initialization, execution and aggregation of results are called. Also, in case of multiple shares, multiple execution threads are spawned. -* In `init.rs`, the verification and sanitization of the `Keygen Init` message is handled. -* In `execute.rs`, the instantiation and execution of the protocol is actualized. -* In `result.rs`, the results of all party shares are aggregated, validated and sent to the gRPC client. -* In `types.rs`, useful structs that are needed in the rest of the modules are defined. - -## Sign -The _sign_ gRPC executes the sign protocol as implemented in [tofn](https://github.com/axelarnetwork/tofn) and described in [GG20](https://eprint.iacr.org/2020/540.pdf). - -The initialization of _sign_ is actualized by the following message: - -``` -message SignInit { - string key_uid; // keygen's identifier - repeated string party_uids; - bytes message_to_sign; -} -``` - -### Successful sign - -On success, the _keygen_ protocol returns a `signature` which is a `Vec`. - -Since multiple shares per party are supported, _sign_'s result may produce multiple `signatures`s which are the same across all shares. Only one copy of the `signature` is sent to the gRPC client. - -### Unsuccessful sign +## Threshold cryptography -Similarly to _keygen_, if faulty parties are detected during the execution of _sign_, the protocol is stopped and a `Vec` is returned to the client. - -### Trigger recovery - -_Sign_ is started with the special gRPC message `SignInit`. -``` -message SignInit { - string key_uid = 1; - repeated string party_uids = 2; - bytes message_to_sign = 3; -} -``` - -`key_uid` indicates the session identifier of an executed _keygen_. In order to be able to participate to _sign_, parties need to have their `share` info stored at the `Share KV Store` as _value_, under the _key_ `key_uid`. If this data is not present at the machine of a party (i.e. no `key_uid` exists in `Share KV Store`), a `need_recover` gRPC message is sent to the client and the connection is then closed. In the `need_recover` message, the missing `key_uid` is included. - -``` -message NeedRecover { - string session_id = 1; -} -``` - -The client then proceeds by triggering _recover_ gRPC, and then starts the _sign_ again for the recovered party. Other participants are not affected. - -### File structure -The keygen protocol is implemented in [tofnd/src/gg20/sign](https://github.com/axelarnetwork/tofnd/tree/main/src/gg20/sign), which, similar to _keygen_, has the following file structure: - -``` -├── sign - ├── mod.rs - ├── init.rs - ├── execute.rs - ├── result.rs - └── types.rs -``` - -* In `mod.rs`, the handlers of protocol initialization, execution and aggregation of results are called. Also, in case of multiple shares, multiple execution threads are spawned. -* In `init.rs`, the verification and sanitization of `Sign Init` message is handled. If the absence of shares is discovered, the client sends a `need_recover` and stops. -* In `execute.rs`, the instantiation and execution of the protocol is actualized. -* In `result.rs`, the results of all party shares are aggregated, validated and sent to the gRPC client. -* In `types.rs`, useful structs that are needed in the rest of the modules are defined. - -## Recover - -As discussed in [keygen](#keygen) and [sign](#sign) section, the recovery of lost keys and shares is supported. In case of sudden data loss, for example due to a hard disk crash, parties are able to recover their shares. This is possible because each party sends it's encrypted secret info to the client before storing it inside the `Share KV Store`. - -When _keygen_ is completed, the party's information is encryped and sent to the client. When the absence of party's information is detected during _sign_, `Tofnd` sends the `need_recover` message, indicating that recovery must be triggered. - -Recovery is a [unary](https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc) gRPC. The client re-sends the `KeygenInit` message and the encrypted recovery info. This allows `Tofnd` to reconstruct the `Share KV Store` by decrypting the recovery info using the party's `mnemonic`. - -``` -message RecoverRequest { - KeygenInit keygen_init = 1; - repeated bytes share_recovery_infos = 2; -} -``` - -If _recovery_ was successful, a `success` message is sent, other wise `Tofnd` sends a `fail` message. - -``` -message RecoverResponse { - enum Response { - success = 0; - fail = 1; - } - Response response = 1; -} -``` - -# Testing - -## Honest behaviours - -Both unit tests and integration tests are provided: -``` -$ cargo test -``` - -## Malicious behaviours - -`Tofn` supports faulty behaviours to test fault detection. These behaviours are only supported under the `malicious` feature. See more for Rust features [here](https://doc.rust-lang.org/cargo/reference/features.html). - -`Tofnd` incorporates the `malicious` feature. You can run malicious tests by: -``` -$ cargo test --all-features -``` +For an implementation of the [GG20](https://eprint.iacr.org/2020/540.pdf) threshold-ECDSA protocol, +see this version of [tofnd](https://github.com/axelarnetwork/tofnd/tree/v0.10.1). The GG20 protocol implementation should not be considered ready for production since it doesn't protect against recently discovered attacks on the protocol implementation. This was removed from `tofnd` as it is not being used in the Axelar protocol. -# License +## License All crates licensed under either of - * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) - * [MIT license](http://opensource.org/licenses/MIT) +* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) +* [MIT license](http://opensource.org/licenses/MIT) at your option. diff --git a/src/config/malicious.rs b/src/config/malicious.rs deleted file mode 100644 index 0e40f3c0..00000000 --- a/src/config/malicious.rs +++ /dev/null @@ -1,96 +0,0 @@ -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -use tofn::{ - collections::TypedUsize, - gg20::{ - keygen::malicious::Behaviour as KeygenBehaviour, - sign::malicious::Behaviour as SignBehaviour, - }, -}; - -use clap::App; - -pub(super) type Behaviours = crate::gg20::service::malicious::Behaviours; - -pub(super) const AVAILABLE_BEHAVIOURS: [&str; 20] = [ - "Honest", - "R1BadProof", - "R1BadGammaI", - "R2FalseAccusation", - "R2BadMta", - "R2BadMtaWc", - "R3BadSigmaI", - "R3FalseAccusationMta", - "R3FalseAccusationMtaWc", - "R3BadProof", - "R3BadDeltaI", - "R3BadKI", - "R3BadAlpha", - "R3BadBeta", - "R4BadReveal", - "R5BadProof", - "R6FalseAccusation", - "R6BadProof", - "R6FalseFailRandomizer", - "R7BadSI", -]; - -pub fn get_behaviour_matches(app: App) -> TofndResult { - // TODO: if we want to read all available behaviours from tofn automatically, - // we should add strum (https://docs.rs/strum) to iterate over enums and - // print their names, but it has to be imported in tofn. - - let matches = app.get_matches(); - - // Set a default behaviour - let mut sign_behaviour = "Honest"; - let mut victim = 0; - if let Some(matches) = matches.subcommand_matches("malicious") { - sign_behaviour = matches - .value_of("behaviour") - .ok_or_else(|| anyhow!("behaviour value"))?; - victim = matches - .value_of("victim") - .ok_or_else(|| anyhow!("victim value"))? - .parse::()?; - } - - // TODO: parse keygen malicious types as well - let keygen = KeygenBehaviour::R1BadCommit; - let sign = match_string_to_behaviour(sign_behaviour, victim); - Ok(Behaviours { keygen, sign }) -} - -fn match_string_to_behaviour(behaviour: &str, victim: usize) -> SignBehaviour { - use SignBehaviour::*; - let victim = TypedUsize::from_usize(victim); - // TODO: some of the behaviours do not demand a victim. In the future, more - // will be added that potentially need different set of arguments. - // Adjust this as needed to support that. - match behaviour { - "Honest" => Honest, - "R1BadProof" => R1BadProof { victim }, - "R1BadGammaI" => R1BadGammaI, - "R2FalseAccusation" => R2FalseAccusation { victim }, - "R2BadMta" => R2BadMta { victim }, - "R2BadMtaWc" => R2BadMtaWc { victim }, - "R3BadSigmaI" => R3BadSigmaI, - "R3FalseAccusationMta" => R3FalseAccusationMta { victim }, - "R3FalseAccusationMtaWc" => R3FalseAccusationMtaWc { victim }, - "R3BadProof" => R3BadProof, - "R3BadDeltaI" => R3BadDeltaI, - "R3BadKI" => R3BadKI, - "R3BadAlpha" => R3BadAlpha { victim }, - "R3BadBeta" => R3BadBeta { victim }, - "R4BadReveal" => R4BadReveal, - "R5BadProof" => R5BadProof { victim }, - "R6FalseAccusation" => R6FalseAccusation { victim }, - "R6BadProof" => R6BadProof, - "R6FalseFailRandomizer" => R6FalseType5Claim, - "R7BadSI" => R7BadSI, - "R7FalseFailRandomizer" => R7FalseType7Claim, - _ => Honest, - } -} diff --git a/src/config/mod.rs b/src/config/mod.rs index 6ef23da0..63dae8bc 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -14,11 +14,6 @@ const DEFAULT_IP: &str = "127.0.0.1"; const DEFAULT_PORT: u16 = 50051; const AVAILABLE_MNEMONIC_CMDS: &[&str] = &["existing", "create", "import", "export", "rotate"]; -#[cfg(feature = "malicious")] -mod malicious; -#[cfg(feature = "malicious")] -use malicious::*; - // default path is ~/.tofnd fn default_tofnd_dir() -> TofndResult { Ok(dirs::home_dir() @@ -35,8 +30,6 @@ pub struct Config { pub mnemonic_cmd: Cmd, pub tofnd_path: PathBuf, pub password_method: PasswordMethod, - #[cfg(feature = "malicious")] - pub behaviours: Behaviours, } pub fn parse_args() -> TofndResult { @@ -49,7 +42,7 @@ pub fn parse_args() -> TofndResult { .ok_or_else(|| anyhow!("can't convert default dir to str"))?; let app = App::new("tofnd") - .about("A threshold signature scheme daemon") + .about("A cryptographic signing service") .version(crate_version!()) .arg( Arg::new("ip") @@ -103,21 +96,6 @@ pub fn parse_args() -> TofndResult { .default_value(default_dir), ); - #[cfg(feature = "malicious")] - let app = app.subcommand( - App::new("malicious") - .about("Select malicious behaviour") - .arg( - Arg::new("behaviour") - .required(true) - .possible_values(&AVAILABLE_BEHAVIOURS) - .help("malicious behaviour"), - ) - .arg(Arg::new("victim").required(true).help("victim")), - ); - #[cfg(feature = "malicious")] - let behaviours = get_behaviour_matches(app.clone())?; - let matches = app.get_matches(); let ip = matches @@ -150,7 +128,5 @@ pub fn parse_args() -> TofndResult { mnemonic_cmd, tofnd_path, password_method, - #[cfg(feature = "malicious")] - behaviours, }) } diff --git a/src/encrypted_sled/mod.rs b/src/encrypted_sled/mod.rs index 17c2003d..fcebb350 100644 --- a/src/encrypted_sled/mod.rs +++ b/src/encrypted_sled/mod.rs @@ -10,7 +10,7 @@ mod result; // match the API of sled pub use kv::EncryptedDb as Db; -pub use password::{Password, PasswordMethod, PasswordSalt}; +pub use password::{Password, PasswordMethod}; pub use result::EncryptedDbError as Error; pub use result::EncryptedDbResult as Result; diff --git a/src/encrypted_sled/tests.rs b/src/encrypted_sled/tests.rs index 51412875..d4ea703d 100644 --- a/src/encrypted_sled/tests.rs +++ b/src/encrypted_sled/tests.rs @@ -4,7 +4,7 @@ use testdir::testdir; #[test] fn test_encrypted_sled() { let db_path = testdir!("encrypted_db"); - let db = EncryptedDb::open(&db_path, get_test_password()).unwrap(); + let db = EncryptedDb::open(db_path, get_test_password()).unwrap(); // insert -> returns None let res = db.insert("key", "value").unwrap(); @@ -75,7 +75,7 @@ fn test_password() { fn test_large_input() { let db_path = testdir!("large_input"); - let db = EncryptedDb::open(&db_path, get_test_password()).unwrap(); + let db = EncryptedDb::open(db_path, get_test_password()).unwrap(); let large_value = vec![0; 100000]; let res = db.insert("key", large_value.clone()).unwrap(); diff --git a/src/gg20/broadcast.rs b/src/gg20/broadcast.rs deleted file mode 100644 index 4ddd447a..00000000 --- a/src/gg20/broadcast.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! This module handles the routing of incoming traffic. -//! Receives and validates messages until the connection is closed by the client. -//! The incoming messages come from the gRPC stream and are forwarded to shares' internal channels. - -// tonic cruft -use super::proto; -use futures_util::StreamExt; -use tokio::sync::mpsc; -use tonic::Status; - -// logging -use tracing::{debug, info, span, warn, Level, Span}; - -/// Results of routing -#[derive(Debug, PartialEq)] -enum RoutingStatus { - Continue { traffic: proto::TrafficIn }, - Stop, - Skip, -} - -/// Receives incoming from a gRPC stream and broadcasts them to internal channels; -/// Loops until client closes the socket, or a message containing [proto::message_in::Data::Abort] is received -/// Empty and unknown messages are ignored -pub(super) async fn broadcast_messages( - in_grpc_stream: &mut tonic::Streaming, - mut out_internal_channels: Vec>>, - span: Span, -) { - // loop until `stop` is received - loop { - // read message from stream - let msg_data = in_grpc_stream.next().await; - - // check incoming message - let traffic = match open_message(msg_data, span.clone()) { - RoutingStatus::Continue { traffic } => traffic, - RoutingStatus::Stop => break, - RoutingStatus::Skip => continue, - }; - - // send the message to all channels - for out_channel in &mut out_internal_channels { - let _ = out_channel.send(Some(traffic.clone())); - } - } -} - -/// gets a gPRC [proto::MessageIn] and checks the type -/// available messages are: -/// [proto::message_in::Data::Traffic] -> return [RoutingResult::Continue] -/// [proto::message_in::Data::Abort] -> return [RoutingResult::Stop] -/// [proto::message_in::Data::KeygenInit] -> return [RoutingResult::Skip] -/// [proto::message_in::Data::SignInit] -> return [RoutingResult::Skip] -fn open_message(msg: Option>, span: Span) -> RoutingStatus { - // start routing span - let route_span = span!(parent: &span, Level::INFO, "routing"); - let _start = route_span.enter(); - - // we receive MessageIn wrapped in multiple layers. We have to unpeel tonic message - - // get result - let msg_result = match msg { - Some(msg_result) => msg_result, - None => { - info!("Stream closed"); - return RoutingStatus::Stop; - } - }; - - // get data option - - // TODO examine why this happens: Sometimes, when the connection is - // closed by the client, instead of a `None` message, we get a `Some` - // message containing an "error reading a body from connection: protocol - // error: not a result of an error" error Removing for now to prevent this - // message from appearing while doing keygen/signs but will need to - // find out why this happens - // https://github.com/axelarnetwork/tofnd/issues/167 - let msg_data_opt = match msg_result { - Ok(msg_in) => msg_in.data, - Err(err) => { - info!("Stream closed"); - debug!("Stream closed with err {}", err); - return RoutingStatus::Stop; - } - }; - - // get message data - let msg_data = match msg_data_opt { - Some(msg_data) => msg_data, - None => { - warn!("ignore incoming msg: missing `data` field"); - return RoutingStatus::Skip; - } - }; - - // match message data to types - let traffic = match msg_data { - proto::message_in::Data::Traffic(t) => t, - proto::message_in::Data::Abort(_) => { - warn!("received abort message"); - return RoutingStatus::Stop; - } - proto::message_in::Data::KeygenInit(_) | proto::message_in::Data::SignInit(_) => { - warn!("ignore incoming msg: expect `data` to be TrafficIn type"); - return RoutingStatus::Skip; - } - }; - - // return traffic - RoutingStatus::Continue { traffic } -} - -#[cfg(test)] -mod tests { - use super::*; - - struct TestCase { - message_in: proto::MessageIn, - expected_result: RoutingStatus, - } - - impl TestCase { - fn new(message_in: proto::MessageIn, expected_result: RoutingStatus) -> Self { - TestCase { - message_in, - expected_result, - } - } - } - - fn new_msg_in(msg_in: proto::message_in::Data) -> proto::MessageIn { - proto::MessageIn { data: Some(msg_in) } - } - - #[test] - fn test_validate_message() { - let test_cases = vec![ - TestCase::new( - new_msg_in(proto::message_in::Data::Abort(true)), - RoutingStatus::Stop, - ), - TestCase::new( - new_msg_in(proto::message_in::Data::KeygenInit( - proto::KeygenInit::default(), - )), - RoutingStatus::Skip, - ), - TestCase::new( - new_msg_in(proto::message_in::Data::SignInit(proto::SignInit::default())), - RoutingStatus::Skip, - ), - TestCase::new( - new_msg_in(proto::message_in::Data::Traffic(proto::TrafficIn::default())), - RoutingStatus::Continue { - traffic: proto::TrafficIn::default(), - }, - ), - TestCase::new(proto::MessageIn { data: None }, RoutingStatus::Skip), - ]; - - let span = span!(Level::INFO, "test-span"); - - for test_case in test_cases { - let result = open_message(Some(Ok(test_case.message_in)), span.clone()); - assert_eq!(result, test_case.expected_result); - } - - let result = open_message(Some(Err(tonic::Status::ok("test status"))), span.clone()); - assert_eq!(result, RoutingStatus::Stop); - - let result = open_message(None, span); - assert_eq!(result, RoutingStatus::Stop); - } -} diff --git a/src/gg20/key_presence.rs b/src/gg20/key_presence.rs deleted file mode 100644 index 214511d1..00000000 --- a/src/gg20/key_presence.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! This module handles the key_presence gRPC. -//! Request includes [proto::message_in::Data::KeyPresenceRequest] struct and encrypted recovery info. -//! The recovery info is decrypted by party's mnemonic seed and saved in the KvStore. - -use super::{proto, service::Gg20Service}; - -// logging -use tracing::info; - -// error handling -use crate::TofndResult; - -impl Gg20Service { - pub(super) async fn handle_key_presence( - &self, - request: proto::KeyPresenceRequest, - ) -> TofndResult { - // check if mnemonic is available - let _ = self.kv_manager.seed().await?; - - // check if requested key exists - if self.kv_manager.kv().exists(&request.key_uid).await? { - info!( - "Found session-id {} in kv store during key presence check", - request.key_uid - ); - Ok(proto::key_presence_response::Response::Present) - } else { - info!( - "Did not find session-id {} in kv store during key presence check", - request.key_uid - ); - Ok(proto::key_presence_response::Response::Absent) - } - } -} diff --git a/src/gg20/keygen/execute.rs b/src/gg20/keygen/execute.rs deleted file mode 100644 index ccd3ac9e..00000000 --- a/src/gg20/keygen/execute.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! This module creates and executes the keygen protocol -//! On success it returns [super::TofnKeygenOutput]. A successful [Keygen] can produce either an Ok(SecretKeyShare) of an Err(Vec>). -//! On failure it returns [anyhow!] error if [Keygen] struct cannot be instantiated. - -use super::{ - proto, - types::{Context, PartyShareCounts, TofndKeygenOutput}, - Gg20Service, ProtocolCommunication, -}; - -use crate::gg20::protocol; -use tofn::{ - gg20::keygen::{new_keygen, KeygenProtocol}, - sdk::api::TofnResult, -}; - -// logging -use tracing::{info, Span}; - -// error handling -use anyhow::anyhow; - -impl Gg20Service { - /// create a new keygen. - /// The field of Gg20Service `safe_keygen` dictates whether the new keygen will use big primes of not - /// TODO: support `cfg(feature="unsafe")` in the future instead of matching `gg20.safe_keygen` - async fn new_keygen( - &self, - party_share_counts: PartyShareCounts, - ctx: &Context, - ) -> TofnResult { - new_keygen( - party_share_counts, - ctx.threshold, - ctx.tofnd_index, - ctx.tofnd_subindex, - &ctx.party_keygen_data, - #[cfg(feature = "malicious")] - self.cfg.behaviours.keygen.clone(), - ) - } - - /// create and execute keygen protocol and returning the result. - /// if the protocol cannot be instantiated, return a [anyhow!] - pub(super) async fn execute_keygen( - &self, - chans: ProtocolCommunication< - Option, - Result, - >, - ctx: &Context, - execute_span: Span, - ) -> TofndKeygenOutput { - // try to create keygen with context - let party_share_counts = ctx.share_counts()?; - let keygen = self - .new_keygen(party_share_counts, ctx) - .await - .map_err(|_| anyhow!("keygen protocol instantiation failed"))?; - - // execute protocol and wait for completion - let protocol_result = protocol::execute_protocol( - keygen, - chans, - &ctx.uids, - &ctx.share_counts, - execute_span.clone(), - ) - .await; - - let res = protocol_result - .map_err(|err| anyhow!("Keygen was not completed due to error: {}", err))?; - - info!("Keygen completed"); - Ok(res) - } -} diff --git a/src/gg20/keygen/init.rs b/src/gg20/keygen/init.rs deleted file mode 100644 index c621c812..00000000 --- a/src/gg20/keygen/init.rs +++ /dev/null @@ -1,351 +0,0 @@ -//! This module handles the initialization of the Keygen protocol. -//! A [KeygenInitSanitized] struct is created out of the raw incoming [proto::KeygenInit] message and a key is reserved inside the KvStore -//! If [proto::KeygenInit] fails to be parsed, an [InitResult] is returned - -// tonic cruft -use futures_util::StreamExt; - -// spans for logging -use tracing::Span; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -use super::{ - proto, - types::{KeygenInitSanitized, MAX_PARTY_SHARE_COUNT, MAX_TOTAL_SHARE_COUNT}, - Gg20Service, -}; -use crate::kv_manager::KeyReservation; - -impl Gg20Service { - /// Receives a message from the stream and tries to handle keygen init operations. - /// On success, it reserves a key in the KVStrore and returns a sanitized struct ready to be used by the protocol. - /// On failure, returns a [KeygenInitError] and no changes are been made in the KvStore. - pub(super) async fn handle_keygen_init( - &self, - stream: &mut tonic::Streaming, - keygen_span: Span, - ) -> TofndResult<(KeygenInitSanitized, KeyReservation)> { - // try to receive message - let msg = stream - .next() - .await - .ok_or_else(|| anyhow!("stream closed by client"))? - .map_err(|e| anyhow!("stream closed by server: {}", e))?; - - // try to get message data - let msg_data = msg - .data - .ok_or_else(|| anyhow!("received `None` message from client"))?; - - // check if message is of expected type - let keygen_init = match msg_data { - proto::message_in::Data::KeygenInit(k) => k, - _ => { - return Err(anyhow!( - "wrong message type; expecting KeygenInit, got {:?}", - msg_data - )) - } - }; - - // try to process incoming message - let (keygen_init, key_reservation) = self.process_keygen_init(keygen_init).await?; - - // log keygen init state - keygen_init.log_info(keygen_span); - - // return sanitized key and its KvStore reservation - Ok((keygen_init, key_reservation)) - } - - // makes all needed assertions on incoming data, and create structures that are - // needed for the execution of the protocol - async fn process_keygen_init( - &self, - keygen_init: proto::KeygenInit, - ) -> TofndResult<(KeygenInitSanitized, KeyReservation)> { - // try to sanitize arguments - let keygen_init = Self::keygen_sanitize_args(keygen_init) - .map_err(|err| anyhow!("failed to sanitize KeygenInit: {}", err))?; - - // reserve key - let key_uid_reservation = self - .kv_manager - .kv() - .reserve_key(keygen_init.new_key_uid.clone()) - .await - .map_err(|err| anyhow!("failed to reseve key: {}", err))?; - - // return sanitized keygen init and key reservation - Ok((keygen_init, key_uid_reservation)) - } - - /// This function is pub(crate) because it is also needed in handle_recover - /// sanitize arguments of incoming message. - /// Example: - /// input for party 'a': - /// args.party_uids = [c, b, a] - /// args.party_share_counts = [1, 2, 3] - /// args.my_party_index = 2 - /// args.threshold = 1 - /// output for party 'a': - /// keygen_init.party_uids = [a, b, c] <- sorted array - /// keygen_init.party_share_counts = [3, 2, 1] . <- sorted with respect to party_uids - /// keygen_init.my_party_index = 0 . <- index inside sorted array - /// keygen_init.threshold = 1 <- same as in input - pub(crate) fn keygen_sanitize_args( - args: proto::KeygenInit, - ) -> TofndResult { - // convert `u32`s to `usize`s - use std::convert::TryFrom; - let my_index = usize::try_from(args.my_party_index)?; - let threshold = usize::try_from(args.threshold)?; - let mut party_share_counts = args - .party_share_counts - .iter() - .map(|i| usize::try_from(*i)) - .collect::, _>>()?; - - // if share_counts are not provided, fall back to 1 share per party - if party_share_counts.is_empty() { - party_share_counts = vec![1; args.party_uids.len()]; - } - - // assert that uids and party shares are alligned - if args.party_uids.len() != party_share_counts.len() { - return Err(anyhow!( - "uid vector and share counts vector not alligned: {:?}, {:?}", - args.party_uids, - party_share_counts, - )); - } - - // check if my_index is inside party_uids - if my_index >= args.party_uids.len() { - return Err(anyhow!( - "my index is {}, but there are only {} parties.", - my_index, - args.party_uids.len(), - )); - } - - // if party's shares are above max, return error - for party_share_count in &party_share_counts { - if *party_share_count > MAX_PARTY_SHARE_COUNT { - return Err(anyhow!( - "party {} has {} shares, but maximum number of shares per party is {}.", - args.party_uids[my_index], - args.party_share_counts[my_index], - MAX_PARTY_SHARE_COUNT, - )); - } - } - - let total_shares = party_share_counts.iter().sum::(); - if total_shares <= threshold { - return Err(anyhow!( - "threshold is not satisfied: t = {}, total number of shares = {}", - threshold, - total_shares, - )); - } else if total_shares > MAX_TOTAL_SHARE_COUNT { - return Err(anyhow!( - "total shares count is {}, but maximum number of share count is {}.", - total_shares, - MAX_PARTY_SHARE_COUNT, - )); - } - - // sort uids and share counts - // we need to sort uids and shares because the caller does not necessarily - // send the same vectors (in terms of order) to all tofnd instances. - let (my_new_index, sorted_uids, sorted_share_counts) = - sort_uids_and_shares(my_index, args.party_uids, party_share_counts)?; - - Ok(KeygenInitSanitized { - new_key_uid: args.new_key_uid, - party_uids: sorted_uids, - party_share_counts: sorted_share_counts, - my_index: my_new_index, - threshold, - }) - } -} - -// helper function to co-sort uids and shares with respect to uids an find new index -fn sort_uids_and_shares( - my_index: usize, - uids: Vec, - share_counts: Vec, -) -> TofndResult<(usize, Vec, Vec)> { - // save my uid - let my_uid = uids - .get(my_index) - .ok_or_else(|| anyhow!("Error: Index out of bounds"))? - .clone(); - - // create a vec of (uid, share_count) and sort it - let mut pairs: Vec<(String, usize)> = uids.into_iter().zip(share_counts.into_iter()).collect(); - pairs.sort(); - - // unzip vec and search for duplicates in uids - let (mut sorted_uids, sorted_share_counts): (Vec<_>, Vec<_>) = pairs.into_iter().unzip(); - let old_len = sorted_uids.len(); - sorted_uids.dedup(); - if old_len != sorted_uids.len() { - return Err(anyhow!("Error: party_uid vector contained a duplicate")); - } - - // find my new index - let my_index = sorted_uids - .iter() - .position(|x| x == &my_uid) - .ok_or_else(|| anyhow!("Error: Lost my uid after sorting uids"))?; - - Ok((my_index, sorted_uids, sorted_share_counts)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_sort_uids_and_shares() { - let in_pairs = vec![ - ("c".to_owned(), 1), - ("b".to_owned(), 2), - ("a".to_owned(), 3), - ]; - let out_pairs = vec![ - ("a".to_owned(), 3), - ("b".to_owned(), 2), - ("c".to_owned(), 1), - ]; - - let (in_keys, in_values): (Vec, Vec) = in_pairs.into_iter().unzip(); - let (out_keys, out_values): (Vec, Vec) = out_pairs.into_iter().unzip(); - - let res = sort_uids_and_shares(0, in_keys.clone(), in_values.clone()).unwrap(); - assert_eq!((2, out_keys.clone(), out_values.clone()), res); - let res = sort_uids_and_shares(1, in_keys.clone(), in_values.clone()).unwrap(); - assert_eq!((1, out_keys.clone(), out_values.clone()), res); - let res = sort_uids_and_shares(2, in_keys.clone(), in_values.clone()).unwrap(); - assert_eq!((0, out_keys, out_values), res); - assert!(sort_uids_and_shares(3, in_keys, in_values).is_err()); // index out of bounds - - let err_pairs = vec![("a".to_owned(), 1), ("a".to_owned(), 2)]; - let (err_keys, err_values): (Vec, Vec) = err_pairs.into_iter().unzip(); - assert!(sort_uids_and_shares(0, err_keys.clone(), err_values.clone()).is_err()); - assert!(sort_uids_and_shares(1, err_keys, err_values).is_err()); - } - - #[test] - fn test_ok_keygen_sanitize_args() { - // check sorting of parties and shares - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_2".to_owned(), "party_1".to_owned()], // unsorted parties - party_share_counts: vec![2, 1], // unsorted shares - my_party_index: 1, // index of "party_1" - threshold: 1, - }; - let sanitized_keygen_init = KeygenInitSanitized { - new_key_uid: "test_uid".to_owned(), // should be same as in raw keygen init - party_uids: vec!["party_1".to_owned(), "party_2".to_owned()], // parties should be sorted - party_share_counts: vec![1, 2], // shares should be sorted with respect to parties - my_index: 0, // index should track "party_1" in the sorted party_uids - threshold: 1, // threshold should be the same - }; - let res = Gg20Service::keygen_sanitize_args(raw_keygen_init).unwrap(); - assert_eq!(&res.new_key_uid, &sanitized_keygen_init.new_key_uid); - assert_eq!(&res.party_uids, &sanitized_keygen_init.party_uids); - assert_eq!( - &res.party_share_counts, - &sanitized_keygen_init.party_share_counts - ); - assert_eq!(&res.my_index, &sanitized_keygen_init.my_index); - assert_eq!(&res.threshold, &sanitized_keygen_init.threshold); - - // check empty share counts - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned(), "party_2".to_owned()], - party_share_counts: vec![], // empty share counts; should default to [1, 1] - my_party_index: 0, - threshold: 1, - }; - let res = Gg20Service::keygen_sanitize_args(raw_keygen_init).unwrap(); - assert_eq!(&res.party_share_counts, &vec![1, 1]); - - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned()], - party_share_counts: vec![MAX_PARTY_SHARE_COUNT as u32], // should be ok - my_party_index: 0, - threshold: 1, - }; - let res = Gg20Service::keygen_sanitize_args(raw_keygen_init).unwrap(); - assert_eq!(&res.party_share_counts, &vec![MAX_PARTY_SHARE_COUNT]); - - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned(), "party_2".to_owned()], - party_share_counts: vec![MAX_TOTAL_SHARE_COUNT as u32 - 1, 1], // should be ok - my_party_index: 0, - threshold: 1, - }; - let res = Gg20Service::keygen_sanitize_args(raw_keygen_init).unwrap(); - assert_eq!(&res.party_share_counts, &vec![MAX_TOTAL_SHARE_COUNT - 1, 1]); - } - - #[test] - fn test_fail_keygen_sanitize_args() { - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned(), "party_2".to_owned()], - party_share_counts: vec![1, 1, 1], // counts are not the same number as parties - my_party_index: 0, - threshold: 1, - }; - assert!(Gg20Service::keygen_sanitize_args(raw_keygen_init).is_err()); - - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned(), "party_2".to_owned()], - party_share_counts: vec![1, 1], - my_party_index: 0, - threshold: 2, // incorrect threshold - }; - assert!(Gg20Service::keygen_sanitize_args(raw_keygen_init).is_err()); - - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned(), "party_2".to_owned()], - party_share_counts: vec![1, 1], - my_party_index: 2, // index out of bounds - threshold: 1, - }; - assert!(Gg20Service::keygen_sanitize_args(raw_keygen_init).is_err()); - - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned()], - party_share_counts: vec![(MAX_PARTY_SHARE_COUNT + 1) as u32], // party has more than max number of shares - my_party_index: 0, - threshold: 1, - }; - assert!(Gg20Service::keygen_sanitize_args(raw_keygen_init).is_err()); - - let raw_keygen_init = proto::KeygenInit { - new_key_uid: "test_uid".to_owned(), - party_uids: vec!["party_1".to_owned(), "party_2".to_owned()], - party_share_counts: vec![MAX_TOTAL_SHARE_COUNT as u32, 1], // total share count is more than max total shares - my_party_index: 0, - threshold: 1, - }; - assert!(Gg20Service::keygen_sanitize_args(raw_keygen_init).is_err()); - } -} diff --git a/src/gg20/keygen/mod.rs b/src/gg20/keygen/mod.rs deleted file mode 100644 index f40b171c..00000000 --- a/src/gg20/keygen/mod.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Handles the keygen streaming gRPC for one party. -//! -//! Protocol: -//! 1. [self::init] First, the initialization message [proto::KeygenInit] is received from the client. -//! This message describes the execution of the protocol (i.e. number of participants, share counts, etc). -//! 2. [self::execute] Then, the party starts to generate messages by invoking calls of the [tofn] library until the protocol is completed. -//! These messages are send to the client using the gRPC stream, and are broadcasted to all participating parties by the client. -//! 3. [self::result] Finally, the party receives the result of the protocol, which is also send to the client through the gRPC stream. Afterwards, the stream is closed. -//! -//! Shares: -//! Each party might have multiple shares. A single thread is created for each share. -//! We keep this information agnostic to the client, and we use the [crate::gg20::routing] layer to distribute the messages to each share. -//! The result of the protocol is common across all shares, and unique for each party. We make use of [self::result] layer to aggregate and process the result. -//! -//! All relevant helper structs and types are defined in [self::types] - -use super::{ - broadcast::broadcast_messages, proto, service::Gg20Service, types::ProtocolCommunication, -}; - -use tonic::Status; - -use tofn::{ - collections::TypedUsize, - gg20::keygen::{ - create_party_keypair_and_zksetup, create_party_keypair_and_zksetup_unsafe, KeygenPartyId, - }, -}; - -// tonic cruft -use tokio::sync::{mpsc, oneshot}; - -// logging -use tracing::{info, span, Level, Span}; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -pub mod types; -use types::*; -mod execute; -mod init; -mod result; - -impl Gg20Service { - /// handle keygen gRPC - pub async fn handle_keygen( - &self, - mut stream_in: tonic::Streaming, - mut stream_out_sender: mpsc::UnboundedSender>, - keygen_span: Span, - ) -> TofndResult<()> { - // 1. Receive KeygenInit, open message, sanitize arguments -> init mod - // 2. Spawn N keygen threads to execute the protocol in parallel; one of each of our shares -> execute mod - // 3. Spawn 1 router thread to route messages from client to the respective keygen thread -> routing mod - // 4. Wait for all keygen threads to finish and aggregate all responses -> result mod - - // 1. - // get KeygenInit message from stream, sanitize arguments and reserve key - let (keygen_init, key_uid_reservation) = self - .handle_keygen_init(&mut stream_in, keygen_span.clone()) - .await?; - - // 2. - // find my share count to allocate channel vectors - let my_share_count = keygen_init.my_shares_count(); - if my_share_count == 0 { - return Err(anyhow!( - "Party {} has 0 shares assigned", - keygen_init.my_index - )); - } - - // create in and out channels for each share, and spawn as many threads - let mut keygen_senders = Vec::with_capacity(my_share_count); - let mut aggregator_receivers = Vec::with_capacity(my_share_count); - - // computation of (party_keypair, party_zksetup) is intensive so we compute them here once - let secret_recovery_key = self.kv_manager.seed().await?; - let session_nonce = keygen_init.new_key_uid.as_bytes(); - - info!("Generating keypair for party {} ...", keygen_init.my_index); - - let party_id = TypedUsize::::from_usize(keygen_init.my_index); - - let party_keygen_data = match self.cfg.safe_keygen { - true => create_party_keypair_and_zksetup(party_id, &secret_recovery_key, session_nonce), - false => create_party_keypair_and_zksetup_unsafe( - party_id, - &secret_recovery_key, - session_nonce, - ), - } - .map_err(|_| anyhow!("Party keypair generation failed"))?; - - info!( - "Finished generating keypair for party {}", - keygen_init.my_index - ); - - for my_tofnd_subindex in 0..my_share_count { - // channels for communication between router (sender) and protocol threads (receivers) - let (keygen_sender, keygen_receiver) = mpsc::unbounded_channel(); - keygen_senders.push(keygen_sender); - // channels for communication between protocol threads (senders) and final result aggregator (receiver) - let (aggregator_sender, aggregator_receiver) = oneshot::channel(); - aggregator_receivers.push(aggregator_receiver); - - // wrap channels needed by internal threads; receiver chan for router and sender chan gRPC stream - let chans = ProtocolCommunication::new(keygen_receiver, stream_out_sender.clone()); - // wrap all context data needed for each thread - let ctx = Context::new( - &keygen_init, - keygen_init.my_index, - my_tofnd_subindex, - party_keygen_data.clone(), - ); - // clone gg20 service because tokio thread takes ownership - let gg20 = self.clone(); - - // set up log state - let log_info = ctx.log_info(); - let state = log_info.as_str(); - let execute_span = span!(parent: &keygen_span, Level::DEBUG, "execute", state); - - // spawn keygen thread and continue immediately - tokio::spawn(async move { - // wait for keygen's result inside thread - let secret_key_share = gg20.execute_keygen(chans, &ctx, execute_span).await; - // send result to aggregator - let _ = aggregator_sender.send(secret_key_share); - }); - } - - // 3. - // spin up broadcaster thread and return immediately - tokio::spawn(async move { - broadcast_messages(&mut stream_in, keygen_senders, keygen_span).await; - }); - - // 4. - // wait for all keygen threads to end, aggregate their responses, and store data in KV store - self.aggregate_results( - aggregator_receivers, - &mut stream_out_sender, - key_uid_reservation, - keygen_init, - ) - .await?; - - Ok(()) - } -} diff --git a/src/gg20/keygen/result.rs b/src/gg20/keygen/result.rs deleted file mode 100644 index f3c6f0d3..00000000 --- a/src/gg20/keygen/result.rs +++ /dev/null @@ -1,200 +0,0 @@ -//! This module handles the aggregation of process of keygen results. -//! When all keygen threads finish, we aggregate their results and retrieve: -//! 1. the public key - must be the same across all results; stored in KvStore -//! 2. all secret share data - data used to allow parties to participate to future Signs; stored in KvStore -//! 3. all secret share recovery info - information used to allow client to issue secret share recovery in case of data loss; sent to client - -use tofn::{gg20::keygen::SecretKeyShare, sdk::api::serialize}; - -use super::{ - proto::{self}, - types::{BytesVec, KeygenInitSanitized, TofnKeygenOutput, TofndKeygenOutput}, - Gg20Service, -}; -use crate::{gg20::types::PartyInfo, kv_manager::KeyReservation}; - -// tonic cruft -use tokio::sync::{ - mpsc, - oneshot::{self, Receiver}, -}; -use tonic::Status; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -use std::convert::TryInto; - -impl Gg20Service { - /// aggregate results from all keygen threads, create a record and insert it in the KvStore - pub(super) async fn aggregate_results( - &self, - aggregator_receivers: Vec>, - stream_out_sender: &mut mpsc::UnboundedSender>, - key_uid_reservation: KeyReservation, - keygen_init: KeygenInitSanitized, - ) -> TofndResult<()> { - // wait all keygen threads and aggregate results - // can't use `map_err` because of `.await` func :( - let keygen_outputs = match Self::aggregate_keygen_outputs(aggregator_receivers).await { - Ok(keygen_outputs) => keygen_outputs, - Err(err) => { - self.kv_manager - .kv() - .unreserve_key(key_uid_reservation) - .await; - return Err(anyhow!( - "Error at Keygen output aggregation. Unreserving key {}", - err - )); - } - }; - - // try to process keygen outputs - let (pub_key, group_recover_info, secret_key_shares) = - Self::process_keygen_outputs(&keygen_init, keygen_outputs, stream_out_sender)?; - - // try to retrieve private recovery info from all shares - let private_recover_info = - Self::get_private_recovery_data(&secret_key_shares).map_err(|err| anyhow!(err))?; - - // combine responses from all keygen threads to a single struct - let kv_data = PartyInfo::get_party_info( - secret_key_shares, - keygen_init.party_uids.clone(), - keygen_init.party_share_counts.clone(), - keygen_init.my_index, - ); - - // try to put data inside kv store - self.kv_manager - .kv() - .put(key_uid_reservation, kv_data.try_into()?) - .await - .map_err(|err| anyhow!(err))?; - - // try to send result - Ok( - stream_out_sender.send(Ok(proto::MessageOut::new_keygen_result( - &keygen_init.party_uids, - Ok(proto::KeygenOutput { - pub_key, - group_recover_info, - private_recover_info, - }), - )))?, - ) - } - - /// iterate all keygen outputs, and return data that need to be permenantly stored - /// we perform a sanity check that all shares produces the same pubkey and group recovery - /// and then return a single copy of the common info and a vec with `SecretKeyShares` of each party - /// This vec is later used to derive private recovery info - fn process_keygen_outputs( - keygen_init: &KeygenInitSanitized, - keygen_outputs: Vec, - stream_out_sender: &mut mpsc::UnboundedSender>, - ) -> TofndResult<(BytesVec, BytesVec, Vec)> { - // Collect all key shares unless there's a protocol fault - let keygen_outputs = keygen_outputs - .into_iter() - .collect::, _>>(); - - match keygen_outputs { - Ok(secret_key_shares) => { - if secret_key_shares.is_empty() { - return Err(anyhow!( - "Party {} created no secret key shares", - keygen_init.my_index - )); - } - - // check that all shares returned the same public key and group recover info - let share_id = secret_key_shares[0].share().index(); - let pub_key = secret_key_shares[0].group().encoded_pubkey(); - let group_info = secret_key_shares[0] - .group() - .all_shares_bytes() - .map_err(|_| anyhow!("unable to call all_shares_bytes()"))?; - - // sanity check: pubkey and group recovery info should be the same across all shares - // Here we check that the first share produced the same info as the i-th. - for secret_key_share in &secret_key_shares[1..] { - // try to get pubkey of i-th share. Each share should produce the same pubkey - if pub_key != secret_key_share.group().encoded_pubkey() { - return Err(anyhow!( - "Party {}'s share {} and {} returned different public key", - keygen_init.my_index, - share_id, - secret_key_share.share().index() - )); - } - - // try to get group recovery info of i-th share. Each share should produce the same group info - let curr_group_info = secret_key_share - .group() - .all_shares_bytes() - .map_err(|_| anyhow!("unable to call all_shares_bytes()"))?; - if group_info != curr_group_info { - return Err(anyhow!( - "Party {}'s share {} and {} returned different group recovery info", - keygen_init.my_index, - share_id, - secret_key_share.share().index() - )); - } - } - - Ok((pub_key, group_info, secret_key_shares)) - } - Err(crimes) => { - // send crimes and exit with an error - stream_out_sender.send(Ok(proto::MessageOut::new_keygen_result( - &keygen_init.party_uids, - Err(crimes.clone()), - )))?; - - Err(anyhow!( - "Party {} found crimes: {:?}", - keygen_init.my_index, - crimes - )) - } - } - } - - /// Create private recovery info out of a vec with all parties' SecretKeyShares - fn get_private_recovery_data(secret_key_shares: &[SecretKeyShare]) -> TofndResult { - // try to retrieve private recovery info from all party's shares - let private_infos = secret_key_shares - .iter() - .enumerate() - .map(|(index, secret_key_share)| { - secret_key_share - .recovery_info() - .map_err(|_| anyhow!("Unable to get recovery info for share {}", index)) - }) - .collect::>>()?; - - // We use an additional layer of serialization to simplify the protobuf definition - let private_bytes = serialize(&private_infos) - .map_err(|_| anyhow!("Failed to serialize private recovery infos"))?; - - Ok(private_bytes) - } - - /// wait all keygen threads and get keygen outputs - async fn aggregate_keygen_outputs( - aggregator_receivers: Vec>, - ) -> TofndResult> { - let mut keygen_outputs = Vec::with_capacity(aggregator_receivers.len()); - - for aggregator in aggregator_receivers { - let res = aggregator.await??; - keygen_outputs.push(res); - } - - Ok(keygen_outputs) - } -} diff --git a/src/gg20/keygen/types.rs b/src/gg20/keygen/types.rs deleted file mode 100644 index 24d15b7f..00000000 --- a/src/gg20/keygen/types.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Helper structs and implementations for [crate::gg20::keygen]. - -use tofn::{ - collections::TypedUsize, - gg20::keygen::{KeygenPartyId, KeygenPartyShareCounts, PartyKeygenData, SecretKeyShare}, - sdk::api::ProtocolOutput, -}; - -pub(super) type PartyShareCounts = KeygenPartyShareCounts; -pub const MAX_PARTY_SHARE_COUNT: usize = tofn::gg20::keygen::MAX_PARTY_SHARE_COUNT; -pub const MAX_TOTAL_SHARE_COUNT: usize = tofn::gg20::keygen::MAX_TOTAL_SHARE_COUNT; - -use crate::TofndResult; -use anyhow::anyhow; -use tracing::{info, span, Level, Span}; - -/// tofn's ProtocolOutput for Keygen -pub type TofnKeygenOutput = ProtocolOutput; -/// tofnd's ProtocolOutput for Keygen -pub type TofndKeygenOutput = TofndResult; -/// type for bytes -pub use tofn::sdk::api::BytesVec; - -/// KeygenInitSanitized holds all arguments needed by Keygen in the desired form; populated by proto::KeygenInit -/// pub because it is also needed by recovery module -pub struct KeygenInitSanitized { - pub new_key_uid: String, // session's UID - pub party_uids: Vec, // vector of party uids; this is alligned with party_share_count vector - pub party_share_counts: Vec, // vector of share counts; this is alligned with party_uids vector - pub my_index: usize, // the _tofnd_ index of the party inside party_uids and party_shares_counts - pub threshold: usize, // protocol's threshold -} -impl KeygenInitSanitized { - // get the share count of `my_index`th party - pub(super) fn my_shares_count(&self) -> usize { - self.party_share_counts[self.my_index] as usize - } - - // log KeygenInitSanitized state - pub(super) fn log_info(&self, keygen_span: Span) { - // create log span and display current status - let init_span = span!(parent: &keygen_span, Level::INFO, "init"); - let _enter = init_span.enter(); - info!( - "[uid:{}, shares:{}] starting Keygen with [key: {}, (t,n)=({},{}), participants:{:?}", - self.party_uids[self.my_index], - self.my_shares_count(), - self.new_key_uid, - self.threshold, - self.party_share_counts.iter().sum::(), - self.party_uids, - ); - } -} - -/// Context holds the all arguments that need to be passed from keygen gRPC call into protocol execution -pub struct Context { - pub(super) key_id: String, // session id; used for logs - pub(super) uids: Vec, // all party uids; alligned with `share_counts` - pub(super) share_counts: Vec, // all party share counts; alligned with `uids` - pub(super) threshold: usize, // protocol's threshold - pub(super) tofnd_index: TypedUsize, // tofnd index of party - pub(super) tofnd_subindex: usize, // index of party's share - pub(super) party_keygen_data: PartyKeygenData, -} - -impl Context { - /// create a new Context - pub fn new( - keygen_init: &KeygenInitSanitized, - tofnd_index: usize, - tofnd_subindex: usize, - party_keygen_data: PartyKeygenData, - ) -> Self { - let tofnd_index = TypedUsize::from_usize(tofnd_index); - Context { - key_id: keygen_init.new_key_uid.clone(), - uids: keygen_init.party_uids.clone(), - share_counts: keygen_init.party_share_counts.clone(), - threshold: keygen_init.threshold, - tofnd_index, - tofnd_subindex, - party_keygen_data, - } - } - - /// get share_counts in the form of tofn::PartyShareCounts - pub fn share_counts(&self) -> TofndResult { - match PartyShareCounts::from_vec(self.share_counts.clone()) { - Ok(party_share_counts) => Ok(party_share_counts), - Err(_) => Err(anyhow!("failed to create party_share_counts")), - } - } - - /// export state; used for logging - pub fn log_info(&self) -> String { - format!( - "[{}] [uid:{}, share:{}/{}]", - self.key_id, - self.uids[self.tofnd_index.as_usize()], - self.tofnd_subindex + 1, - self.share_counts[self.tofnd_index.as_usize()] - ) - } -} diff --git a/src/gg20/mod.rs b/src/gg20/mod.rs deleted file mode 100644 index 654c7161..00000000 --- a/src/gg20/mod.rs +++ /dev/null @@ -1,134 +0,0 @@ -//! [proto::gg20_server::Gg20] gRPC server API -//! Available gRPCs are: -//! [recover] - Recovers private data of a party provided a mnemonic. -//! [keygen] - Starts keygen. -//! [sign] - Starts sing. - -// tonic cruft -use super::proto; -use tokio::sync::mpsc; -use tokio_stream::wrappers::UnboundedReceiverStream; -use tonic::{Request, Response, Status}; -pub mod proto_helpers; - -// logging -use tracing::{error, info, span, Level}; - -// gRPC -mod broadcast; -mod key_presence; -mod keygen; -mod protocol; -mod recover; -pub mod service; -mod sign; -pub mod types; -use types::*; - -#[tonic::async_trait] -impl proto::gg20_server::Gg20 for service::Gg20Service { - type KeygenStream = UnboundedReceiverStream>; - type SignStream = Self::KeygenStream; - - /// Recover unary gRPC. See [recover]. - async fn recover( - &self, - request: tonic::Request, - ) -> Result, Status> { - let request = request.into_inner(); - - let response = self.handle_recover(request).await; - let response = match response { - Ok(()) => { - info!("Recovery completed successfully!"); - proto::recover_response::Response::Success - } - Err(err) => { - error!("Unable to complete recovery: {}", err); - proto::recover_response::Response::Fail - } - }; - - Ok(Response::new(proto::RecoverResponse { - // the prost way to convert enums to i32 https://github.com/danburkert/prost#enumerations - response: response as i32, - })) - } - - /// KeyPresence unary gRPC. See [key_presence]. - async fn key_presence( - &self, - request: tonic::Request, - ) -> Result, Status> { - let request = request.into_inner(); - - let response = match self.handle_key_presence(request).await { - Ok(res) => { - info!("Key presence check completed succesfully!"); - res - } - Err(err) => { - error!("Unable to complete key presence check: {}", err); - proto::key_presence_response::Response::Fail - } - }; - - Ok(Response::new(proto::KeyPresenceResponse { - response: response as i32, - })) - } - - /// Keygen streaming gRPC. See [keygen]. - async fn keygen( - &self, - request: Request>, - ) -> Result, Status> { - let stream_in = request.into_inner(); - let (msg_sender, rx) = mpsc::unbounded_channel(); - - // log span for keygen - let span = span!(Level::INFO, "Keygen"); - let _enter = span.enter(); - let s = span.clone(); - let gg20 = self.clone(); - - tokio::spawn(async move { - // can't return an error from a spawned thread - if let Err(e) = gg20.handle_keygen(stream_in, msg_sender.clone(), s).await { - error!("keygen failure: {:?}", e.to_string()); - // we can't handle errors in tokio threads. Log error if we are unable to send the status code to client. - if let Err(e) = msg_sender.send(Err(Status::invalid_argument(e.to_string()))) { - error!("could not send error to client: {}", e.to_string()); - } - } - }); - Ok(Response::new(UnboundedReceiverStream::new(rx))) - } - - /// Sign sreaming gRPC. See [sign]. - async fn sign( - &self, - request: Request>, - ) -> Result, Status> { - let stream = request.into_inner(); - let (msg_sender, rx) = mpsc::unbounded_channel(); - - // log span for sign - let span = span!(Level::INFO, "Sign"); - let _enter = span.enter(); - let s = span.clone(); - let gg20 = self.clone(); - - tokio::spawn(async move { - // can't return an error from a spawned thread - if let Err(e) = gg20.handle_sign(stream, msg_sender.clone(), s).await { - error!("sign failure: {:?}", e.to_string()); - // we can't handle errors in tokio threads. Log error if we are unable to send the status code to client. - if let Err(e) = msg_sender.send(Err(Status::invalid_argument(e.to_string()))) { - error!("could not send error to client: {}", e.to_string()); - } - } - }); - Ok(Response::new(UnboundedReceiverStream::new(rx))) - } -} diff --git a/src/gg20/proto_helpers.rs b/src/gg20/proto_helpers.rs deleted file mode 100644 index 4de75b11..00000000 --- a/src/gg20/proto_helpers.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Wrappers for sending and receiving [proto] messages - -use tofn::{ - collections::FillVecMap, - gg20::{keygen::KeygenPartyId, sign::SignPartyId}, - sdk::api::Fault, -}; - -use crate::proto; -type KeygenFaults = FillVecMap; -type SignFaults = FillVecMap; -type KeygenResultData = Result; -type SignResultData = Result, SignFaults>; -use proto::message_out::criminal_list::criminal::CrimeType as ProtoCrimeType; -use proto::message_out::criminal_list::Criminal as ProtoCriminal; -use proto::message_out::keygen_result::KeygenResultData::Criminals as ProtoKeygenCriminals; -use proto::message_out::keygen_result::KeygenResultData::Data as ProtoKeygenData; -use proto::message_out::sign_result::SignResultData::Criminals as ProtoSignCriminals; -use proto::message_out::sign_result::SignResultData::Signature as ProtoSignature; -use proto::message_out::CriminalList as ProtoCriminalList; - -// convenience constructors -impl proto::MessageOut { - pub(super) fn new_bcast(bcast: &[u8]) -> Self { - Self::new_traffic("", bcast, true) - } - pub(super) fn new_p2p(receiver_id: &str, p2p: &[u8]) -> Self { - Self::new_traffic(receiver_id, p2p, false) - } - pub(super) fn new_traffic(receiver_id: &str, msg: &[u8], is_broadcast: bool) -> Self { - proto::MessageOut { - data: Some(proto::message_out::Data::Traffic(proto::TrafficOut { - to_party_uid: receiver_id.to_string(), - payload: msg.to_vec(), - is_broadcast, - })), - } - } - pub(super) fn need_recover() -> Self { - proto::MessageOut { - data: Some(proto::message_out::Data::NeedRecover(true)), - } - } - - pub(super) fn new_keygen_result(participant_uids: &[String], result: KeygenResultData) -> Self { - let result = match result { - Ok(keygen_output) => ProtoKeygenData(keygen_output), - Err(faults) => ProtoKeygenCriminals(ProtoCriminalList::from_tofn_faults( - faults, - participant_uids, - )), - }; - proto::MessageOut { - data: Some(proto::message_out::Data::KeygenResult( - proto::message_out::KeygenResult { - keygen_result_data: Some(result), - }, - )), - } - } - - pub(super) fn new_sign_result(participant_uids: &[String], result: SignResultData) -> Self { - let result = match result { - Err(faults) => ProtoSignCriminals(ProtoCriminalList::from_tofn_faults( - faults, - participant_uids, - )), - Ok(sign_output) => ProtoSignature(sign_output), - }; - proto::MessageOut { - data: Some(proto::message_out::Data::SignResult( - proto::message_out::SignResult { - sign_result_data: Some(result), - }, - )), - } - } -} - -fn fault_to_crime(f: &Fault) -> ProtoCrimeType { - match f { - Fault::MissingMessage | Fault::CorruptedMessage => ProtoCrimeType::NonMalicious, - Fault::ProtocolFault => ProtoCrimeType::Malicious, - } -} - -impl ProtoCriminalList { - fn from_tofn_faults

(faults: FillVecMap, uids: &[String]) -> Self { - let criminals = faults - .into_iter_some() - .map(|(i, fault)| ProtoCriminal { - party_uid: uids[i.as_usize()].clone(), - crime_type: fault_to_crime(&fault) as i32, // why `as i32`? https://github.com/danburkert/prost#enumerations - }) - .collect(); - Self { criminals } - } -} diff --git a/src/gg20/protocol.rs b/src/gg20/protocol.rs deleted file mode 100644 index a92541e1..00000000 --- a/src/gg20/protocol.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! Abstract functionality used by keygen, sign, etc. - -use tofn::{ - collections::TypedUsize, - sdk::api::{Protocol, ProtocolOutput, Round}, -}; - -// tonic cruft -use super::{proto, ProtocolCommunication}; -use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; - -// logging -use tracing::{debug, error, span, warn, Level, Span}; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -/// execute gg20 protocol -pub(super) async fn execute_protocol( - mut party: Protocol, - mut chans: ProtocolCommunication< - Option, - Result, - >, - party_uids: &[String], - party_share_counts: &[usize], - span: Span, -) -> TofndResult> -where - K: Clone, -{ - // set up counters for logging - let total_num_of_shares = party_share_counts.iter().fold(0, |acc, s| acc + *s); - let total_round_p2p_msgs = total_num_of_shares * (total_num_of_shares - 1); // total number of messages is n(n-1) - - let mut round_count = 0; - while let Protocol::NotDone(mut round) = party { - round_count += 1; - - // handle outgoing traffic - handle_outgoing(&chans.sender, &round, party_uids, round_count, span.clone())?; - - // collect incoming traffic - handle_incoming( - &mut chans.receiver, - &mut round, - party_uids, - total_round_p2p_msgs, - total_num_of_shares, - round_count, - span.clone(), - ) - .await?; - - // check if everything was ok this round - party = round - .execute_next_round() - .map_err(|_| anyhow!("Error in tofn::execute_next_round"))?; - } - - match party { - Protocol::NotDone(_) => Err(anyhow!("Protocol failed to complete")), - Protocol::Done(result) => Ok(result), - } -} - -fn handle_outgoing( - sender: &UnboundedSender>, - round: &Round, - party_uids: &[String], - round_count: usize, - span: Span, -) -> TofndResult<()> { - let send_span = span!(parent: &span, Level::DEBUG, "outgoing", round = round_count); - let _start = send_span.enter(); - debug!("begin"); - // send outgoing bcasts - if let Some(bcast) = round.bcast_out() { - debug!("generating out bcast"); - // send message to gRPC client - sender.send(Ok(proto::MessageOut::new_bcast(bcast)))? - } - // send outgoing p2ps - if let Some(p2ps_out) = round.p2ps_out() { - let mut p2p_msg_count = 1; - for (i, p2p) in p2ps_out.iter() { - // get tofnd index from tofn - let tofnd_idx = round - .info() - .party_share_counts() - .share_to_party_id(i) - .map_err(|_| anyhow!("Unable to get tofnd index for party {}", i))?; - - debug!( - "out p2p to [{}] ({}/{})", - party_uids[tofnd_idx.as_usize()], - p2p_msg_count, - p2ps_out.len() - 1 - ); - p2p_msg_count += 1; - - // send message to gRPC client - sender.send(Ok(proto::MessageOut::new_p2p( - &party_uids[tofnd_idx.as_usize()], - p2p, - )))? - } - } - debug!("finished"); - Ok(()) -} - -async fn handle_incoming( - receiver: &mut UnboundedReceiver>, - round: &mut Round, - party_uids: &[String], - total_round_p2p_msgs: usize, - total_num_of_shares: usize, - round_count: usize, - span: Span, -) -> TofndResult<()> { - let mut p2p_msg_count = 0; - let mut bcast_msg_count = 0; - - // loop until no more messages are needed for this round - while round.expecting_more_msgs_this_round() { - // get internal message from broadcaster - let traffic = receiver.recv().await.ok_or(format!( - "{}: stream closed by client before protocol has completed", - round_count - )); - - // unpeel TrafficIn - let traffic = match traffic { - Ok(traffic_opt) => match traffic_opt { - Some(traffic) => traffic, - None => { - // if data is missing, ignore the message, - warn!("ignore incoming msg: missing `data` field"); - continue; - } - }, - Err(_) => { - // if channel is closed, stop - error!("internal channel closed prematurely"); - break; - } - }; - - // We have to spawn a new span it in each loop because `async` calls don't work well with tracing - // See details on how we need to make spans curve around `.await`s here: - // https://docs.rs/tracing/0.1.25/tracing/span/index.html#entering-a-span - let recv_span = span!(parent: &span, Level::DEBUG, "incoming", round = round_count); - let _start = recv_span.enter(); - - // log incoming message - if traffic.is_broadcast { - bcast_msg_count += 1; - debug!( - "got incoming bcast message {}/{}", - bcast_msg_count, total_num_of_shares - ); - } else { - p2p_msg_count += 1; - debug!( - "got incoming p2p message {}/{}", - p2p_msg_count, total_round_p2p_msgs - ); - } - - // get sender's party index - let from = party_uids - .iter() - .position(|uid| uid == &traffic.from_party_uid) - .ok_or_else(|| anyhow!("from uid does not exist in party uids"))?; - - // try to set a message - if round - .msg_in(TypedUsize::from_usize(from), &traffic.payload) - .is_err() - { - return Err(anyhow!("error calling tofn::msg_in with [from: {}]", from)); - }; - } - - Ok(()) -} diff --git a/src/gg20/recover.rs b/src/gg20/recover.rs deleted file mode 100644 index 8d85a57e..00000000 --- a/src/gg20/recover.rs +++ /dev/null @@ -1,170 +0,0 @@ -//! This module handles the recover gRPC. -//! Request includes [proto::message_in::Data::KeygenInit] struct and encrypted recovery info. -//! The recovery info is decrypted by party's mnemonic seed and saved in the KvStore. - -use super::{keygen::types::KeygenInitSanitized, proto, service::Gg20Service, types::PartyInfo}; -use tofn::{ - collections::TypedUsize, - gg20::keygen::{ - recover_party_keypair, recover_party_keypair_unsafe, KeygenPartyId, SecretKeyShare, - SecretRecoveryKey, - }, - sdk::api::{deserialize, BytesVec, PartyShareCounts}, -}; - -// logging -use tracing::{info, warn}; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -use std::convert::TryInto; - -impl Gg20Service { - pub(super) async fn handle_recover(&self, request: proto::RecoverRequest) -> TofndResult<()> { - // get keygen init sanitized from request - let keygen_init = { - let keygen_init = request - .keygen_init - .ok_or_else(|| anyhow!("missing keygen_init field in recovery request"))?; - Self::keygen_sanitize_args(keygen_init)? - }; - - let keygen_output = request - .keygen_output - .ok_or_else(|| anyhow!("missing keygen_output field in recovery request"))?; - - // check if key-uid already exists in kv-store. If yes, return success and don't update the kv-store - if self - .kv_manager - .kv() - .exists(&keygen_init.new_key_uid) - .await - .map_err(|err| anyhow!(err))? - { - warn!( - "Request to recover shares for [key {}, party {}] but shares already exist in kv-store. Abort request.", - keygen_init.new_key_uid, keygen_init.party_uids[keygen_init.my_index] - ); - return Ok(()); - } - - // recover secret key shares from request - // get mnemonic seed - let secret_recovery_key = self.kv_manager.seed().await?; - let secret_key_shares = self - .recover_secret_key_shares(&secret_recovery_key, &keygen_init, &keygen_output) - .map_err(|err| anyhow!("Failed to acquire secret key share {}", err))?; - - self.update_share_kv_store(keygen_init, secret_key_shares) - .await - } - - /// get recovered secret key shares from serilized share recovery info - fn recover_secret_key_shares( - &self, - secret_recovery_key: &SecretRecoveryKey, - init: &KeygenInitSanitized, - output: &proto::KeygenOutput, - ) -> TofndResult> { - // get my share count safely - let my_share_count = *init.party_share_counts.get(init.my_index).ok_or_else(|| { - anyhow!( - "index {} is out of party_share_counts bounds {}", - init.my_index, - init.party_share_counts.len() - ) - })?; - if my_share_count == 0 { - return Err(anyhow!("Party {} has 0 shares assigned", init.my_index)); - } - - // check party share counts - let party_share_counts = PartyShareCounts::from_vec(init.party_share_counts.to_owned()) - .map_err(|_| { - anyhow!( - "PartyCounts::from_vec() error for {:?}", - init.party_share_counts - ) - })?; - - // check private recovery infos - // use an additional layer of deserialization to simpify the protobuf definition - // deserialize recovery info here to catch errors before spending cycles on keypair recovery - let private_info_vec: Vec = deserialize(&output.private_recover_info) - .ok_or_else(|| anyhow!("Failed to deserialize private recovery infos"))?; - - if private_info_vec.len() != my_share_count { - return Err(anyhow!( - "Party {} has {} shares assigned, but retrieved {} shares from client", - init.my_index, - my_share_count, - private_info_vec.len() - )); - } - - info!("Recovering keypair for party {} ...", init.my_index); - - let party_id = TypedUsize::::from_usize(init.my_index); - - // try to recover keypairs - let session_nonce = init.new_key_uid.as_bytes(); - let party_keypair = match self.cfg.safe_keygen { - true => recover_party_keypair(party_id, secret_recovery_key, session_nonce), - false => recover_party_keypair_unsafe(party_id, secret_recovery_key, session_nonce), - } - .map_err(|_| anyhow!("party keypair recovery failed"))?; - - info!("Finished recovering keypair for party {}", init.my_index); - - // try to gather secret key shares from recovery infos - let secret_key_shares = private_info_vec - .iter() - .enumerate() - .map(|(i, share_recovery_info_bytes)| { - SecretKeyShare::recover( - &party_keypair, - share_recovery_info_bytes, // request recovery for ith share - &output.group_recover_info, - &output.pub_key, - party_id, - i, - party_share_counts.clone(), - init.threshold, - ) - .map_err(|_| anyhow!("Cannot recover share [{}] of party [{}]", i, party_id)) - }) - .collect::>()?; - - Ok(secret_key_shares) - } - - /// attempt to write recovered secret key shares to the kv-store - async fn update_share_kv_store( - &self, - keygen_init_sanitized: KeygenInitSanitized, - secret_key_shares: Vec, - ) -> TofndResult<()> { - // try to make a reservation - let reservation = self - .kv_manager - .kv() - .reserve_key(keygen_init_sanitized.new_key_uid) - .await - .map_err(|err| anyhow!("failed to complete reservation: {}", err))?; - // acquire kv-data - let kv_data = PartyInfo::get_party_info( - secret_key_shares, - keygen_init_sanitized.party_uids, - keygen_init_sanitized.party_share_counts, - keygen_init_sanitized.my_index, - ); - // try writing the data to the kv-store - self.kv_manager - .kv() - .put(reservation, kv_data.try_into()?) - .await - .map_err(|err| anyhow!("failed to update kv store: {}", err)) - } -} diff --git a/src/gg20/service/malicious.rs b/src/gg20/service/malicious.rs deleted file mode 100644 index 4aec2932..00000000 --- a/src/gg20/service/malicious.rs +++ /dev/null @@ -1,10 +0,0 @@ -use tofn::gg20::{ - keygen::malicious::Behaviour as KeygenBehaviour, sign::malicious::Behaviour as SignBehaviour, -}; - -/// Behaviours are pub because config mod needs access -#[derive(Clone, Debug)] -pub struct Behaviours { - pub keygen: KeygenBehaviour, - pub sign: SignBehaviour, -} diff --git a/src/gg20/service/mod.rs b/src/gg20/service/mod.rs deleted file mode 100644 index db145cdf..00000000 --- a/src/gg20/service/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! This mod includes the service implementation derived from - -use super::proto; -use crate::config::Config; -use crate::kv_manager::KvManager; - -#[cfg(feature = "malicious")] -pub mod malicious; - -/// Gg20Service -#[derive(Clone)] -pub struct Gg20Service { - pub(super) kv_manager: KvManager, - pub(super) cfg: Config, -} - -/// create a new Gg20 gRPC server -pub fn new_service(cfg: Config, kv_manager: KvManager) -> impl proto::gg20_server::Gg20 { - Gg20Service { kv_manager, cfg } -} diff --git a/src/gg20/sign/execute.rs b/src/gg20/sign/execute.rs deleted file mode 100644 index f9d0b598..00000000 --- a/src/gg20/sign/execute.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! This module creates and executes the sign protocol -//! On success it returns [super::TofndSignOutput]. A successful sign execution can produce either an Ok(Vec) of an Err(Vec>). -//! On failure it returns [anyhow!] error if [Sign] struct cannot be instantiated. - -use super::{ - proto, - types::{Context, TofndSignOutput}, - Gg20Service, ProtocolCommunication, -}; -use crate::gg20::protocol; -use tofn::gg20::sign::new_sign; - -// logging -use tracing::{info, Span}; - -// error handling -use anyhow::anyhow; - -impl Gg20Service { - /// create and execute sign protocol and returning the result. - /// if the protocol cannot be instantiated, return an [anyhow!] error - pub(super) async fn execute_sign( - &self, - chans: ProtocolCommunication< - Option, - Result, - >, - ctx: &Context, - execute_span: Span, - ) -> TofndSignOutput { - // try to create sign with context - let sign = new_sign( - ctx.group(), - &ctx.share, - &ctx.sign_parties, - ctx.msg_to_sign(), - #[cfg(feature = "malicious")] - self.cfg.behaviours.sign.clone(), - ) - .map_err(|_| anyhow!("sign instantiation failed"))?; - - // execute protocol and wait for completion - let protocol_result = protocol::execute_protocol( - sign, - chans, - // &ctx.sign_init.participant_uids, - &ctx.sign_uids(), - &ctx.sign_share_counts, - execute_span.clone(), - ) - .await; - - let res = protocol_result - .map_err(|err| anyhow!("Sign was not completed due to error: {}", err))?; - - info!("Sign completed"); - Ok(res) - } -} diff --git a/src/gg20/sign/init.rs b/src/gg20/sign/init.rs deleted file mode 100644 index b1593acd..00000000 --- a/src/gg20/sign/init.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! This module handles the initialization of the Sign protocol. -//! A [SignInitSanitized] struct is created out of the raw incoming [proto::SignInit] message and the session key is queried inside from KvStore. -//! If [proto::SignInit] fails to be parsed, or no Keygen has been executed for the current session ID, an [anyhow!] error is returned - -// try_into() for MessageDigest -use std::convert::TryInto; - -use super::{proto, types::SignInitSanitized, Gg20Service}; -use crate::gg20::types::PartyInfo; - -// tonic cruft -use futures_util::StreamExt; -use tokio::sync::mpsc; -use tonic::Status; - -// logging -use tracing::Span; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -impl Gg20Service { - /// Receives a message from the stream and tries to handle sign init operations. - /// On success, it extracts the PartyInfo from the KVStrore and returns a sanitized struct ready to be used by the protocol. - /// On failure, returns an [anyhow!] error and no changes are been made in the KvStore. - pub(super) async fn handle_sign_init( - &self, - in_stream: &mut tonic::Streaming, - out_stream: &mut mpsc::UnboundedSender>, - sign_span: Span, - ) -> TofndResult<(SignInitSanitized, PartyInfo)> { - let msg_type = in_stream - .next() - .await - .ok_or_else(|| anyhow!("sign: stream closed by client without sending a message"))?? - .data - .ok_or_else(|| anyhow!("sign: missing `data` field in client message"))?; - - let sign_init = match msg_type { - proto::message_in::Data::SignInit(k) => k, - _ => return Err(anyhow!("Expected sign init message")), - }; - - // try to get party info related to session id - let party_info: PartyInfo = match self.kv_manager.kv().get(&sign_init.key_uid).await { - Ok(value) => value.try_into()?, - Err(err) => { - // if no such session id exists, send a message to client that indicates that recovery is needed and stop sign - Self::send_kv_store_failure(out_stream)?; - let err = anyhow!("Unable to find session-id {} in kv store. Issuing share recovery and exit sign {:?}", sign_init.key_uid, err); - return Err(err); - } - }; - - // try to sanitize arguments - let sign_init = Self::sign_sanitize_args(sign_init, &party_info.tofnd.party_uids)?; - - // log SignInitSanitized state - party_info.log_info(&sign_init.new_sig_uid, sign_span); - - Ok((sign_init, party_info)) - } - - /// send "need recover" message to client - fn send_kv_store_failure( - out_stream: &mut mpsc::UnboundedSender>, - ) -> TofndResult<()> { - Ok(out_stream.send(Ok(proto::MessageOut::need_recover()))?) - } - - /// sanitize arguments of incoming message. - /// Example: - /// input for party 'a': - /// (from keygen) party_uids = [a, b, c] - /// (from keygen) party_share_counts = [3, 2, 1] - /// proto::SignInit.party_uids = [c, a] - /// output for party 'a': - /// SignInitSanitized.party_uids = [2, 0] <- index of c, a in party_uids - fn sign_sanitize_args( - sign_init: proto::SignInit, - all_party_uids: &[String], - ) -> TofndResult { - // create a vector of the tofnd indices of the participant uids - let participant_indices = sign_init - .party_uids - .iter() - .map(|s| { - all_party_uids.iter().position(|k| k == s).ok_or_else(|| { - anyhow!( - "participant [{}] not found in key [{}]", - s, - sign_init.key_uid - ) - }) - }) - .collect::, _>>()?; - - Ok(SignInitSanitized { - new_sig_uid: sign_init.new_sig_uid, - participant_uids: sign_init.party_uids, - participant_indices, - message_to_sign: sign_init.message_to_sign.as_slice().try_into()?, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_ok_sign_sanitize_args() { - let all_party_uids = vec![ - "party_0".to_owned(), // party 0 has index 0 - "party_1".to_owned(), // party 1 has index 1 - "party_2".to_owned(), // party 2 has index 2 - ]; - - let raw_sign_init = proto::SignInit { - new_sig_uid: "test_uid".to_owned(), - key_uid: "test_uid".to_owned(), - party_uids: vec!["party_2".to_owned(), "party_1".to_owned()], - message_to_sign: vec![42; 32], - }; - let sanitized_sign_init = SignInitSanitized { - new_sig_uid: "test_uid".to_owned(), // new sig uid should be the same - participant_uids: vec!["party_2".to_owned(), "party_1".to_owned()], // party 2 has index 2, party 1 has index 1 - participant_indices: vec![2, 1], // indices should be [2, 1] - message_to_sign: vec![42; 32].as_slice().try_into().unwrap(), // msg of 32 bytes should be successfully converted to MessageDigest - }; - - let res = Gg20Service::sign_sanitize_args(raw_sign_init, &all_party_uids).unwrap(); - assert_eq!(&res.new_sig_uid, &sanitized_sign_init.new_sig_uid); - assert_eq!(&res.participant_uids, &sanitized_sign_init.participant_uids); - assert_eq!( - &res.participant_indices, - &sanitized_sign_init.participant_indices - ); - assert_eq!(&res.message_to_sign, &sanitized_sign_init.message_to_sign); - } - - #[test] - fn test_fail_sign_sanitize_args() { - let all_party_uids = vec![ - "party_0".to_owned(), - "party_1".to_owned(), - "party_2".to_owned(), - ]; - let raw_sign_init = proto::SignInit { - new_sig_uid: "test_uid".to_owned(), - key_uid: "test_uid".to_owned(), - party_uids: vec!["party_4".to_owned(), "party_1".to_owned()], // party 4 does not exist - message_to_sign: vec![42; 32], - }; - assert!(Gg20Service::sign_sanitize_args(raw_sign_init, &all_party_uids).is_err()); - - let raw_sign_init = proto::SignInit { - new_sig_uid: "test_uid".to_owned(), - key_uid: "test_uid".to_owned(), - party_uids: vec!["party_2".to_owned(), "party_1".to_owned()], - message_to_sign: vec![42; 33], // message is not 32 bytes - }; - assert!(Gg20Service::sign_sanitize_args(raw_sign_init, &all_party_uids).is_err()); - } -} diff --git a/src/gg20/sign/mod.rs b/src/gg20/sign/mod.rs deleted file mode 100644 index 58e0cb06..00000000 --- a/src/gg20/sign/mod.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! Handles the sign streaming gRPC for one party. -//! -//! Protocol: -//! 1. [self::init] First, the initialization message [proto::SignInit] is received from the client. -//! This message describes the execution of the protocol (i.e. number of sign participants, message-to-sign, etc). -//! 2. [self::execute] Then, the party starts to generate messages by invoking calls of the [tofn] library until the protocol is completed. -//! These messages are send to the client using the gRPC stream, and are broadcasted to all participating parties by the client. -//! 3. [self::result] Finally, the party receives the result of the protocol, which is also send to the client through the gRPC stream. Afterwards, the stream is closed. -//! -//! Shares: -//! Each party might have multiple shares. A single thread is created for each share. -//! We keep this information agnostic to the client, and we use the [crate::gg20::routing] layer to distribute the messages to each share. -//! The result of the protocol is common across all shares, and unique for each party. We make use of [self::result] layer to aggregate and process the result. -//! -//! All relevant helper structs and types are defined in [self::types] - -use super::{broadcast::broadcast_messages, proto, service::Gg20Service, ProtocolCommunication}; - -// tonic cruft -use tokio::sync::{mpsc, oneshot}; -use tonic::Status; - -// logging -use tracing::{span, Level, Span}; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -pub mod types; -use types::*; -mod execute; -mod init; -mod result; - -impl Gg20Service { - // we wrap the functionality of sign gRPC here because we can't handle errors - // conveniently when spawning theads. - pub async fn handle_sign( - &self, - mut stream_in: tonic::Streaming, - mut stream_out_sender: mpsc::UnboundedSender>, - sign_span: Span, - ) -> TofndResult<()> { - // 1. Receive SignInit, open message, sanitize arguments -> init mod - // 2. Spawn N sign threads to execute the protocol in parallel; one of each of our shares -> execute mod - // 3. Spawn 1 router thread to route messages from client to the respective sign thread -> routing mod - // 4. Wait for all sign threads to finish and aggregate all responses -> result mod - - // 1. - // get SignInit message from stream and sanitize arguments - let mut stream_out = stream_out_sender.clone(); - let (sign_init, party_info) = self - .handle_sign_init(&mut stream_in, &mut stream_out, sign_span.clone()) - .await?; - - // 2. - // find my share count to allocate channel vectors - let my_share_count = party_info.shares.len(); - if my_share_count == 0 { - return Err(anyhow!( - "Party {} has 0 shares assigned", - party_info.tofnd.index - )); - } - - // create in and out channels for each share, and spawn as many threads - let mut sign_senders = Vec::with_capacity(my_share_count); - let mut aggregator_receivers = Vec::with_capacity(my_share_count); - - for my_tofnd_subindex in 0..my_share_count { - // channels for communication between router (sender) and protocol threads (receivers) - let (sign_sender, sign_receiver) = mpsc::unbounded_channel(); - sign_senders.push(sign_sender); - // channels for communication between protocol threads (senders) and final result aggregator (receiver) - let (aggregator_sender, aggregator_receiver) = oneshot::channel(); - aggregator_receivers.push(aggregator_receiver); - - // wrap channels needed by internal threads; receiver chan for router and sender chan gRPC stream - let chans = ProtocolCommunication::new(sign_receiver, stream_out_sender.clone()); - // wrap all context data needed for each thread - let ctx = Context::new(sign_init.clone(), party_info.clone(), my_tofnd_subindex)?; - // clone gg20 service because tokio thread takes ownership - let gg20 = self.clone(); - - // set up log state - let log_info = ctx.log_info(); - let state = log_info.as_str(); - let execute_span = span!(parent: &sign_span, Level::INFO, "execute", state); - - // spawn sign threads - tokio::spawn(async move { - // get result of sign - let signature = gg20.execute_sign(chans, &ctx, execute_span.clone()).await; - // send result to aggregator - let _ = aggregator_sender.send(signature); - }); - } - - // 3. - // spin up broadcaster thread and return immediately - let span = sign_span.clone(); - tokio::spawn(async move { - broadcast_messages(&mut stream_in, sign_senders, span).await; - }); - - // 4. - // wait for all sign threads to end, get responses, and return signature - Self::handle_results( - aggregator_receivers, - &mut stream_out_sender, - &sign_init.participant_uids, - ) - .await?; - - Ok(()) - } -} diff --git a/src/gg20/sign/result.rs b/src/gg20/sign/result.rs deleted file mode 100644 index 8316ecef..00000000 --- a/src/gg20/sign/result.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! This module handles the aggregation and process of sign results. -//! When all sign threads finish, we aggregate their results and retrieve the signature of the message. The signature must be the same across all results. - -use super::{proto, types::TofnSignOutput, Gg20Service}; - -// tonic cruft -use tokio::sync::mpsc; -use tokio::sync::oneshot; -use tonic::Status; - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -impl Gg20Service { - /// handle results from all shares - /// if all shares return a valid output, send the result to client - /// if a share does not return a valid output, return an [anyhow!] - pub(super) async fn handle_results( - aggregator_receivers: Vec>>, - stream_out_sender: &mut mpsc::UnboundedSender>, - participant_uids: &[String], - ) -> TofndResult<()> { - // create vec to store all sign outputs - // cannot use aggregator_receivers.map(|aggr| aggr.await??) because map() does not support async funcs - let mut sign_outputs = Vec::with_capacity(aggregator_receivers.len()); - - // wait all sign threads and get signature - for aggregator in aggregator_receivers { - let sign_output = aggregator.await??; - sign_outputs.push(sign_output); - } - - // sanity check: check if all shares produced the same signature - let first_sign_output = &sign_outputs[0]; - // skip() first element of sign outputs to avoid extra loop - for (i, sign_output) in sign_outputs.iter().enumerate().skip(1) { - if sign_output != first_sign_output { - let mut error_msg = format!( - "Signature mismatch between shares [{}] and [{}]. More mismatches may exist.", - 0, i - ); - error_msg = format!( - "{}\nReceived signatures: {:#?}", - error_msg, - sign_output.iter().enumerate().collect::>() - ); - return Err(anyhow!(error_msg)); - } - } - - // send signature to client - stream_out_sender.send(Ok(proto::MessageOut::new_sign_result( - participant_uids, - sign_outputs[0].clone(), - )))?; - Ok(()) - } -} diff --git a/src/gg20/sign/types.rs b/src/gg20/sign/types.rs deleted file mode 100644 index a6138ddc..00000000 --- a/src/gg20/sign/types.rs +++ /dev/null @@ -1,245 +0,0 @@ -//! Helper structs and implementations for [crate::gg20::sign]. - -// error handling -use crate::TofndResult; -use anyhow::anyhow; - -// tofn types -use super::super::MessageDigest; -use tofn::collections::{Subset, TypedUsize}; -use tofn::gg20::keygen::{GroupPublicInfo, KeygenPartyId, ShareSecretInfo}; -use tofn::gg20::sign::{SignParties, SignPartyId}; -use tofn::sdk::api::ProtocolOutput; - -/// tofn's ProtocolOutput for Sign -pub type TofnSignOutput = ProtocolOutput, SignPartyId>; -/// tofnd's ProtocolOutput for Sign -pub type TofndSignOutput = TofndResult; - -#[derive(Clone, Debug)] -pub(super) struct SignInitSanitized { - pub(super) new_sig_uid: String, // this is only used for logging - // pub(super) key_uid: String, - pub(super) participant_uids: Vec, - pub(super) participant_indices: Vec, - pub(super) message_to_sign: MessageDigest, -} - -use crate::gg20::types::PartyInfo; - -pub(super) struct Context { - pub(super) sign_init: SignInitSanitized, - pub(super) party_info: PartyInfo, - pub(super) sign_share_counts: Vec, - pub(super) tofnd_subindex: usize, - pub(super) share: ShareSecretInfo, - pub(super) sign_parties: Subset, -} - -impl Context { - /// create a new signing context - pub(super) fn new( - sign_init: SignInitSanitized, - party_info: PartyInfo, - tofnd_subindex: usize, - ) -> TofndResult { - // retrieve sign_share_couts and secret_key_shares here instead of adding - // getters to immediatelly dicover potential errors - let sign_share_counts = Self::get_sign_share_counts( - &party_info.tofnd.party_uids, - &party_info.tofnd.share_counts, - &sign_init.participant_uids, - )?; - - let sign_parties = Self::get_sign_parties( - party_info.tofnd.party_uids.len(), - &sign_init.participant_indices, - )?; - - let share = Self::get_share(&party_info, tofnd_subindex)?; - Ok(Self { - sign_init, - party_info, - sign_share_counts, - tofnd_subindex, - share, - sign_parties, - }) - } - - pub(super) fn group(&self) -> &GroupPublicInfo { - &self.party_info.common - } - - /// from keygen we have - /// party uids: [A, B, C, D] - /// share counts: [1, 2, 3, 4] - /// in sign we receive - /// sign uids: [D, B] - /// we need to construct an array of share counts that is alligned with sign uids - /// sign share counts: [4, 2] - fn get_sign_share_counts( - keygen_uids: &[String], - keygen_share_counts: &[usize], - sign_uids: &[String], - ) -> TofndResult> { - if keygen_uids.len() != keygen_share_counts.len() { - return Err(anyhow!("misalligned keygen uids and keygen share counts")); - } - let mut sign_share_counts = vec![]; - for sign_uid in sign_uids { - let keygen_index = keygen_uids - .iter() - .position(|uid| uid == sign_uid) - .ok_or_else(|| anyhow!("Sign uid was not found"))?; - let sign_share_count = *keygen_share_counts - .get(keygen_index) - .ok_or_else(|| anyhow!("invalid index"))?; - sign_share_counts.push(sign_share_count); - } - Ok(sign_share_counts) - } - - fn get_share(party_info: &PartyInfo, tofnd_subindex: usize) -> TofndResult { - Ok(party_info - .shares - .get(tofnd_subindex) - .ok_or_else(|| anyhow!("failed to get ShareSecretInfo from PartyInfo"))? - .clone()) - } - - pub(super) fn msg_to_sign(&self) -> &MessageDigest { - &self.sign_init.message_to_sign - } - - /// create a `Subset` of sign parties - /// Example: - /// from keygen init we have: - /// keygen_party_uids: [a, b, c, d] - /// keygen_party_indices: [0, 1, 2, 3] - /// from sign init we have: - /// sign_party_uids: [d, b] - /// sign_party_indices: [3, 1] - /// result: - /// sign_parties: [None -> party a with index 0 is not a signer - /// Some(()) -> party b with index 1 is a signer - /// None -> party c with index 2 is not a signer - /// Some(())] -> party d with index 3 is a signer - pub(super) fn get_sign_parties( - length: usize, - sign_indices: &[usize], - ) -> TofndResult { - let mut sign_parties = Subset::with_max_size(length); - for signer_idx in sign_indices.iter() { - if sign_parties - .add(TypedUsize::from_usize(*signer_idx)) - .is_err() - { - return Err(anyhow!("failed to call Subset::add")); - } - } - Ok(sign_parties) - } - - /// get signers' uids with respect to keygen uids ordering - /// Example: - /// from keygen init we have: - /// keygen_party_uids: [a, b, c, d] - /// from sign init we have: - /// sign_party_uids: [d, c, a] - /// result: - /// sign_parties: [a, c, d] - pub(super) fn sign_uids(&self) -> Vec { - let mut sign_uids = vec![]; - for uid in self.party_info.tofnd.party_uids.iter() { - if self - .sign_init - .participant_uids - .iter() - .any(|s_uid| s_uid == uid) - { - sign_uids.push(uid.clone()); - } - } - sign_uids - } - - /// export state; used for logging - pub(super) fn log_info(&self) -> String { - format!( - "[{}] [uid:{}, share:{}/{}]", - self.sign_init.new_sig_uid, - self.party_info.tofnd.party_uids[self.party_info.tofnd.index], - self.party_info.shares[self.tofnd_subindex] - .index() - .as_usize() - + 1, - self.party_info.common.share_count(), - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_sign_parties() {} - - #[test] - fn test_sign_share_counts() { - struct TestCase { - keygen_uids: Vec, - keygen_share_counts: Vec, - sign_uids: Vec, - result: Vec, - } - - let ok_test_cases = vec![ - TestCase { - keygen_uids: vec!["a".to_owned(), "b".to_owned()], - keygen_share_counts: vec![1, 2], - sign_uids: vec!["a".to_owned(), "b".to_owned()], - result: vec![1, 2], - }, - TestCase { - keygen_uids: vec!["b".to_owned(), "a".to_owned()], - keygen_share_counts: vec![1, 2], - sign_uids: vec!["a".to_owned()], - result: vec![2], - }, - ]; - - let fail_test_cases = vec![ - TestCase { - keygen_uids: vec!["a".to_owned(), "b".to_owned()], - keygen_share_counts: vec![1, 2], - sign_uids: vec!["c".to_owned()], // party "c" does not exist - result: vec![], - }, - TestCase { - keygen_uids: vec!["a".to_owned(), "b".to_owned()], - keygen_share_counts: vec![1, 2, 3], // keygen shares not alligned with uids - sign_uids: vec!["a".to_owned()], - result: vec![], - }, - ]; - - for t in ok_test_cases { - let res = Context::get_sign_share_counts( - &t.keygen_uids, - &t.keygen_share_counts, - &t.sign_uids, - ); - assert_eq!(res.unwrap(), t.result); - } - for t in fail_test_cases { - let res = Context::get_sign_share_counts( - &t.keygen_uids, - &t.keygen_share_counts, - &t.sign_uids, - ); - assert!(res.is_err()); - } - } -} diff --git a/src/kv_manager/kv.rs b/src/kv_manager/kv.rs index 30c8b018..1d9ebb04 100644 --- a/src/kv_manager/kv.rs +++ b/src/kv_manager/kv.rs @@ -63,6 +63,7 @@ where } /// Unreserves an existing reservation + #[allow(dead_code)] pub async fn unreserve_key(&self, reservation: KeyReservation) { let _ = self.sender.send(UnreserveKey { reservation }); } @@ -150,12 +151,10 @@ pub fn get_kv_store( } // private handler function to process commands as per the "actor" pattern (see above) -async fn kv_cmd_handler( +async fn kv_cmd_handler( mut rx: mpsc::UnboundedReceiver>, kv: encrypted_sled::Db, -) where - V: Serialize + DeserializeOwned, -{ +) { // if resp.send() fails then log a warning and continue // see discussion https://github.com/axelarnetwork/tofnd/pull/15#discussion_r595426775 while let Some(cmd) = rx.recv().await { diff --git a/src/kv_manager/tests.rs b/src/kv_manager/tests.rs index defa0d88..f47a22b7 100644 --- a/src/kv_manager/tests.rs +++ b/src/kv_manager/tests.rs @@ -153,7 +153,7 @@ fn get_failure() { #[test] fn test_exists() { let kv_name = testdir!(); - let kv = open_with_test_password(&kv_name).unwrap(); + let kv = open_with_test_password(kv_name).unwrap(); let key: String = "key".to_string(); let value: String = "value".to_string(); diff --git a/src/kv_manager/value.rs b/src/kv_manager/value.rs index 527d989e..849c2c47 100644 --- a/src/kv_manager/value.rs +++ b/src/kv_manager/value.rs @@ -3,8 +3,7 @@ use tofn::sdk::api::{deserialize, serialize}; use crate::{ encrypted_sled::Password, - gg20::types::{Entropy, PartyInfo}, - mnemonic::FileIo, + mnemonic::{Entropy, FileIo}, }; use super::{ @@ -37,22 +36,6 @@ impl KvManager { /// Value type stored in the kv-store type KvValue = Vec; -/// Create PartyInfo from KvValue -impl TryFrom for PartyInfo { - type Error = InnerKvError; - fn try_from(v: KvValue) -> Result { - deserialize(&v).ok_or(InnerKvError::DeserializationErr) - } -} - -/// Create KvValue from PartyInfo -impl TryFrom for KvValue { - type Error = InnerKvError; - fn try_from(v: PartyInfo) -> Result { - serialize(&v).map_err(|_| InnerKvError::SerializationErr) - } -} - /// Create Entropy from KvValue impl TryFrom for Entropy { type Error = InnerKvError; diff --git a/src/main.rs b/src/main.rs index de49d43a..2f07de67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ use tokio::net::TcpListener; use tokio_stream::wrappers::TcpListenerStream; mod encrypted_sled; -mod gg20; mod kv_manager; mod mnemonic; mod multisig; @@ -36,12 +35,6 @@ fn set_up_logs() { .init(); } -#[cfg(feature = "malicious")] -pub fn warn_for_malicious_build() { - use tracing::warn; - warn!("WARNING: THIS tofnd BINARY AS COMPILED IN 'MALICIOUS' MODE. MALICIOUS BEHAVIOUR IS INTENTIONALLY INSERTED INTO SOME MESSAGES. THIS BEHAVIOUR WILL CAUSE OTHER tofnd PROCESSES TO IDENTIFY THE CURRENT PROCESS AS MALICIOUS."); -} - fn warn_for_unsafe_execution() { use tracing::warn; warn!("WARNING: THIS tofnd BINARY IS NOT SAFE: SAFE PRIMES ARE NOT USED BECAUSE '--unsafe' FLAG IS ENABLED. USE '--unsafe' FLAG ONLY FOR TESTING."); @@ -59,8 +52,6 @@ async fn main() -> TofndResult<()> { let password = cfg.password_method.execute()?; // print config warnings - #[cfg(feature = "malicious")] - warn_for_malicious_build(); if !cfg.safe_keygen { warn_for_unsafe_execution(); } @@ -75,7 +66,6 @@ async fn main() -> TofndResult<()> { .handle_mnemonic(&cfg.mnemonic_cmd) .await?; - let gg20_service = gg20::service::new_service(cfg, kv_manager.clone()); let multisig_service = multisig::service::new_service(kv_manager); if cmd.exit_after_cmd() { @@ -83,7 +73,6 @@ async fn main() -> TofndResult<()> { return Ok(()); } - let gg20_service = proto::gg20_server::Gg20Server::new(gg20_service); let multisig_service = proto::multisig_server::MultisigServer::new(multisig_service); let incoming = TcpListener::bind(socket_address).await?; @@ -93,7 +82,6 @@ async fn main() -> TofndResult<()> { ); tonic::transport::Server::builder() - .add_service(gg20_service) .add_service(multisig_service) .serve_with_incoming_shutdown(TcpListenerStream::new(incoming), shutdown_signal()) .await?; diff --git a/src/mnemonic/bip39_bindings.rs b/src/mnemonic/bip39_bindings.rs index 9fc017fe..f5a0ed20 100644 --- a/src/mnemonic/bip39_bindings.rs +++ b/src/mnemonic/bip39_bindings.rs @@ -8,7 +8,7 @@ //! [crate::gg20::Password], [crate::gg20::Entropy], [bip39::Mnemonic], [bip39::Seed] use super::results::bip39::{Bip39Error::*, Bip39Result}; -use crate::gg20::types::{Entropy, Password}; +use super::types::{Entropy, Password}; use bip39::{Language, Mnemonic, Seed}; // TODO: we can enrich the API so that users can decide which language they want to use diff --git a/src/mnemonic/cmd_handler.rs b/src/mnemonic/cmd_handler.rs index 2d783b44..d82bedd8 100644 --- a/src/mnemonic/cmd_handler.rs +++ b/src/mnemonic/cmd_handler.rs @@ -5,13 +5,11 @@ use super::{ results::mnemonic::{ InnerMnemonicError::*, InnerMnemonicResult, MnemonicError::*, MnemonicResult, SeedResult, }, + types::{Entropy, Password}, }; -use crate::{ - gg20::types::{Entropy, Password}, // TODO: move from gg20::types - kv_manager::{ - error::{InnerKvError, KvError}, - KeyReservation, KvManager, - }, +use crate::kv_manager::{ + error::{InnerKvError, KvError}, + KeyReservation, KvManager, }; use tofn::{ gg20::keygen::SecretRecoveryKey, diff --git a/src/mnemonic/file_io.rs b/src/mnemonic/file_io.rs index 06edf93a..3e348aa0 100644 --- a/src/mnemonic/file_io.rs +++ b/src/mnemonic/file_io.rs @@ -4,8 +4,8 @@ use std::{io::Write, path::PathBuf}; use tracing::info; +use super::types::Entropy; use super::{bip39_bindings::bip39_from_entropy, results::file_io::FileIoError::Exists}; -use crate::gg20::types::Entropy; /// name of export file const EXPORT_FILE: &str = "export"; @@ -48,7 +48,7 @@ impl FileIo { // if there is an existing exported file raise an error self.check_if_not_exported()?; - let mut file = std::fs::File::create(&self.export_path())?; + let mut file = std::fs::File::create(self.export_path())?; file.write_all(phrase.as_bytes())?; file.sync_all()?; diff --git a/src/mnemonic/mod.rs b/src/mnemonic/mod.rs index c8a23787..00de07f5 100644 --- a/src/mnemonic/mod.rs +++ b/src/mnemonic/mod.rs @@ -10,6 +10,8 @@ mod bip39_bindings; mod cmd_handler; mod file_io; mod results; +mod types; pub use cmd_handler::Cmd; pub use file_io::FileIo; +pub use types::Entropy; diff --git a/src/mnemonic/types.rs b/src/mnemonic/types.rs new file mode 100644 index 00000000..ab61d0a5 --- /dev/null +++ b/src/mnemonic/types.rs @@ -0,0 +1,13 @@ +//! Mnemonic types + +use serde::{Deserialize, Serialize}; +use zeroize::Zeroize; + +/// Mnemonic type needs to be known globaly to create/access the mnemonic kv store +#[derive(Zeroize, Debug, Clone, Serialize, Deserialize)] +#[zeroize(drop)] +pub struct Entropy(pub Vec); + +#[derive(Zeroize, Clone)] +#[zeroize(drop)] +pub struct Password(pub String); diff --git a/src/multisig/keypair.rs b/src/multisig/keypair.rs index 836df969..39bcd5cb 100644 --- a/src/multisig/keypair.rs +++ b/src/multisig/keypair.rs @@ -18,14 +18,14 @@ impl KeyPair { ) -> TofndResult { Ok(match algorithm { Algorithm::Ecdsa => { - let key_pair = ecdsa::keygen(&secret_recovery_key, session_nonce) + let key_pair = ecdsa::keygen(secret_recovery_key, session_nonce) .map_err(|_| anyhow!("Cannot generate keypair"))?; Self::Ecdsa(key_pair) } Algorithm::Ed25519 => { - let key_pair = ed25519::keygen(&secret_recovery_key, session_nonce) + let key_pair = ed25519::keygen(secret_recovery_key, session_nonce) .map_err(|_| anyhow!("Cannot generate keypair"))?; Self::Ed25519(key_pair) diff --git a/src/tests/honest_test_cases.rs b/src/tests/honest_test_cases.rs deleted file mode 100644 index cef119a6..00000000 --- a/src/tests/honest_test_cases.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::tests::TestCase; -use crate::tests::{ - run_keygen_fail_test_cases, run_restart_recover_test_cases, run_restart_test_cases, - run_sign_fail_test_cases, run_test_cases, -}; - -#[cfg(feature = "malicious")] -use super::malicious::MaliciousData; - -use crate::proto::message_out::CriminalList; - -use tracing_test::traced_test; // logs for tests - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn general_honest_test_cases() { - run_test_cases(&generate_honest_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn honest_test_cases_with_restart() { - run_restart_test_cases(&generate_honest_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn honest_test_cases_with_recover() { - run_restart_recover_test_cases(&generate_honest_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn keygen_fail_cases() { - run_keygen_fail_test_cases(&generate_fail_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn sign_fail_cases() { - run_sign_fail_test_cases(&generate_fail_cases()).await; -} - -impl TestCase { - pub(super) fn new( - uid_count: usize, - share_counts: Vec, - threshold: usize, - signer_indices: Vec, - ) -> TestCase { - TestCase { - uid_count, - share_counts, - threshold, - signer_indices, - expected_keygen_faults: CriminalList::default(), - expected_sign_faults: CriminalList::default(), - #[cfg(feature = "malicious")] - malicious_data: MaliciousData::empty(uid_count), - } - } -} - -#[rustfmt::skip] // skip formatting to make file more readable -pub(super) fn generate_honest_cases() -> Vec { - vec![ - TestCase::new(4, vec![], 0, vec![0, 1, 2, 3]), // should initialize share_counts into [1,1,1,1,1] - TestCase::new(5, vec![1, 1, 1, 1, 1], 3, vec![1, 4, 2, 3]), // 1 share per uid - TestCase::new(5, vec![1, 2, 1, 3, 2], 6, vec![1, 4, 2, 3]), // multiple shares per uid - TestCase::new(1, vec![1], 0, vec![0]), // trivial case - // TestCase::new(5, vec![1,2,3,4,20], 27, vec![0, 1, 4, 3, 2]), // Create a malicious party - ] -} - -pub(super) fn generate_fail_cases() -> Vec { - vec![ - TestCase::new(1, vec![], 0, vec![0]), // trivial case - TestCase::new(5, vec![1, 2, 1, 3, 2], 6, vec![1, 4, 2, 3]), // multiple shares per uid - ] -} diff --git a/src/tests/malicious/keygen_test_cases.rs b/src/tests/malicious/keygen_test_cases.rs deleted file mode 100644 index da26c1ed..00000000 --- a/src/tests/malicious/keygen_test_cases.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::proto::message_out::{ - criminal_list::{criminal::CrimeType, Criminal}, - CriminalList, -}; -use tofn::collections::TypedUsize; - -use tofn::gg20::keygen::malicious::Behaviour::{self, *}; - -use super::super::{run_test_cases, TestCase}; -use super::{Disrupt, MaliciousData, Timeout}; - -use tracing_test::traced_test; // log for tests - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn keygen_malicious_general_cases() { - run_test_cases(&generate_basic_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn keygen_malicious_multiple_per_round() { - run_test_cases(&generate_multiple_malicious_per_round()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn malicious_timeout_cases() { - run_test_cases(&timeout_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn malicious_disrupt_cases() { - run_test_cases(&disrupt_cases()).await; -} - -#[derive(Clone, Debug)] -pub(crate) struct KeygenData { - pub(crate) behaviours: Vec, - pub(crate) timeout: Option, - pub(crate) disrupt: Option, -} - -impl KeygenData { - pub(super) fn empty(party_count: usize) -> KeygenData { - KeygenData { - behaviours: vec![Honest; party_count], - timeout: None, - disrupt: None, - } - } -} - -impl TestCase { - fn new_malicious_keygen( - uid_count: usize, - share_counts: Vec, - threshold: usize, - behaviours: Vec, - ) -> TestCase { - // expected faults: Vec, crime_type: CrimeType::Malicious}> - let mut expected_faults = vec![]; - for (i, behaviour) in behaviours.iter().enumerate() { - if matches!(behaviour, &Behaviour::Honest) { - continue; - } - expected_faults.push(Criminal { - party_uid: ((b'A' + i as u8) as char).to_string(), - crime_type: CrimeType::Malicious as i32, - }); - } - let expected_faults = CriminalList { - criminals: expected_faults, - }; - - let mut malicious_data = MaliciousData::empty(uid_count); - malicious_data.set_keygen_data(KeygenData { - behaviours, - timeout: None, - disrupt: None, - }); - - TestCase { - uid_count, - share_counts, - threshold, - signer_indices: vec![], - expected_keygen_faults: expected_faults, - expected_sign_faults: CriminalList::default(), - malicious_data, - } - } - - fn with_keygen_timeout(mut self, index: usize, round: usize) -> Self { - self.malicious_data.keygen_data.timeout = Some(Timeout { index, round }); - self.expected_keygen_faults = CriminalList { - criminals: vec![Criminal { - party_uid: ((b'A' + index as u8) as char).to_string(), - crime_type: CrimeType::NonMalicious as i32, - }], - }; - self - } - - fn with_keygen_disrupt(mut self, index: usize, round: usize) -> Self { - self.malicious_data.keygen_data.disrupt = Some(Disrupt { index, round }); - self.expected_keygen_faults = CriminalList { - criminals: vec![Criminal { - party_uid: ((b'A' + index as u8) as char).to_string(), - crime_type: CrimeType::NonMalicious as i32, - }], - }; - self - } -} - -fn generate_basic_cases() -> Vec { - let behaviours = vec![ - R1BadCommit, - R1BadEncryptionKeyProof, - R1BadZkSetupProof, - R2BadShare { - victim: TypedUsize::from_usize(0), - }, - R2BadEncryption { - victim: TypedUsize::from_usize(0), - }, - R3FalseAccusation { - victim: TypedUsize::from_usize(0), - }, - R3BadXIWitness, - ]; - - behaviours - .into_iter() - .map(|b| { - TestCase::new_malicious_keygen(4, vec![1, 2, 1, 3], 3, vec![Honest, Honest, Honest, b]) - }) - .collect() -} - -fn generate_multiple_malicious_per_round() -> Vec { - let victim = TypedUsize::from_usize(0); - let all_rounds_faults = vec![ - // round 1 faults - vec![R1BadCommit], - // round 2 faults - vec![R2BadEncryption { victim }, R2BadShare { victim }], - // round 3 faults - vec![R3FalseAccusation { victim }], - ]; - // create test cases for all rounds - let mut cases = Vec::new(); - for round_faults in all_rounds_faults { - let mut participants = vec![Honest]; - for fault in round_faults.into_iter() { - participants.push(fault.clone()); // behaviour data initialized with Default:default() - } - cases.push(TestCase::new_malicious_keygen( - participants.len(), - vec![1; participants.len()], - participants.len() - 1, // threshold < #parties - participants, - )); - } - cases -} - -fn timeout_cases() -> Vec { - let timeout_rounds = vec![1, 2, 3]; - timeout_rounds - .into_iter() - .map(|r| { - TestCase::new_malicious_keygen(3, vec![1, 1, 1], 2, vec![Honest, Honest, Honest]) - .with_keygen_timeout(0, r) // add timeout party at index 0 - }) - .collect() -} - -fn disrupt_cases() -> Vec { - let disrupt_rounds = vec![1, 2, 3]; - disrupt_rounds - .into_iter() - .map(|r| { - TestCase::new_malicious_keygen(3, vec![1, 1, 1], 2, vec![Honest, Honest, Honest]) - .with_keygen_disrupt(0, r) // add disrupt party at index 0 - }) - .collect() -} diff --git a/src/tests/malicious/mod.rs b/src/tests/malicious/mod.rs deleted file mode 100644 index 34eb06ed..00000000 --- a/src/tests/malicious/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -pub mod keygen_test_cases; -use keygen_test_cases::KeygenData; -pub(super) type KeygenBehaviour = tofn::gg20::keygen::malicious::Behaviour; - -pub mod sign_test_cases; -use sign_test_cases::SignData; -pub(super) type SignBehaviour = tofn::gg20::sign::malicious::Behaviour; - -#[derive(Clone, Debug)] -pub(crate) struct Timeout { - pub(crate) index: usize, - pub(crate) round: usize, -} - -#[derive(Clone, Debug)] -pub(crate) struct Disrupt { - pub(crate) index: usize, - pub(crate) round: usize, -} - -#[derive(Clone, Debug)] -pub(super) struct MaliciousData { - pub(super) keygen_data: KeygenData, - pub(super) sign_data: SignData, -} - -impl MaliciousData { - pub(super) fn empty(party_count: usize) -> MaliciousData { - MaliciousData { - keygen_data: KeygenData::empty(party_count), - sign_data: SignData::empty(party_count), - } - } - pub(super) fn set_keygen_data(&mut self, keygen_data: KeygenData) { - self.keygen_data = keygen_data; - } - pub(super) fn set_sign_data(&mut self, sign_data: SignData) { - self.sign_data = sign_data; - } -} - -#[derive(Clone, Debug)] -pub(super) struct PartyMaliciousData { - pub(super) timeout_round: usize, - pub(super) disrupt_round: usize, - pub(super) keygen_behaviour: KeygenBehaviour, - pub(super) sign_behaviour: SignBehaviour, -} diff --git a/src/tests/malicious/sign_test_cases.rs b/src/tests/malicious/sign_test_cases.rs deleted file mode 100644 index 90b90f7c..00000000 --- a/src/tests/malicious/sign_test_cases.rs +++ /dev/null @@ -1,243 +0,0 @@ -use crate::proto::message_out::{ - criminal_list::{criminal::CrimeType, Criminal}, - CriminalList, -}; - -use tofn::{ - collections::TypedUsize, - gg20::sign::malicious::Behaviour::{self, *}, -}; - -use super::super::{run_test_cases, TestCase}; -use super::{Disrupt, MaliciousData, Timeout}; - -use tracing_test::traced_test; // log for tests - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn malicious_general_cases() { - run_test_cases(&generate_basic_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn malicious_timeout_cases() { - run_test_cases(&timeout_cases()).await; -} - -#[traced_test] -#[tokio::test(flavor = "multi_thread")] -async fn malicious_disrupt_cases() { - run_test_cases(&disrupt_cases()).await; -} - -pub(super) struct Signer { - pub(super) party_index: usize, - pub(super) behaviour: Behaviour, -} - -impl Signer { - pub(super) fn new(party_index: usize, behaviour: Behaviour) -> Self { - Signer { - party_index, - behaviour, - } - } -} - -#[derive(Clone, Debug)] -pub(crate) struct SignData { - pub(crate) behaviours: Vec, - pub(crate) timeout: Option, - pub(crate) disrupt: Option, -} - -impl SignData { - pub(crate) fn empty(party_count: usize) -> SignData { - SignData { - behaviours: vec![Honest; party_count], - timeout: None, - disrupt: None, - } - } -} - -impl TestCase { - fn new_malicious_sign( - uid_count: usize, - share_counts: Vec, - threshold: usize, - signers: Vec, - ) -> TestCase { - let mut expected_faults = vec![]; - // TODO: enable this when sign faults are available - for (i, signer) in signers.iter().enumerate() { - if matches!(signer.behaviour, Behaviour::Honest) { - continue; - } - expected_faults.push(Criminal { - party_uid: ((b'A' + i as u8) as char).to_string(), - crime_type: CrimeType::Malicious as i32, - }); - } - let expected_faults = CriminalList { - criminals: expected_faults, - }; - - // we use the Signer struct to allign the beaviour type with the index of each signer - // However, in the context of tofnd, behaviour is not only related with signers, but with - // init_party, as well. That is, because we need to initialize a Gg20 service for both - // signers and non-signers. We build these vectors from user's input `sign_participants`: - // 1. behaviours -> holds the behaviour of every party (not just signers) and is alligned with tofnd party uids - // 2. signer_indices -> holds the tofnd index of every signer - let mut signer_indices = Vec::new(); - let mut signer_behaviours = Vec::new(); - - for signer in signers.iter() { - signer_indices.push(signer.party_index); - signer_behaviours.push(signer.behaviour.clone()); - } - - let mut behaviours = Vec::new(); - for i in 0..uid_count { - if !signer_indices.contains(&i) { - behaviours.push(Honest); - } else { - let signer_index = signer_indices.iter().position(|&idx| idx == i).unwrap(); - let signer_type = signer_behaviours[signer_index].clone(); - behaviours.push(signer_type); - } - } - - let mut malicious_data = MaliciousData::empty(uid_count); - malicious_data.set_sign_data(SignData { - behaviours, - timeout: None, - disrupt: None, - }); - - TestCase { - uid_count, - share_counts, - threshold, - signer_indices, - expected_keygen_faults: CriminalList::default(), - expected_sign_faults: expected_faults, - malicious_data, - } - } - - fn with_sign_timeout(mut self, index: usize, round: usize) -> Self { - let keygen_rounds = 4; - self.malicious_data.sign_data.timeout = Some(Timeout { - index, - round: keygen_rounds + round, - }); - self.expected_sign_faults = CriminalList { - criminals: vec![Criminal { - party_uid: ((b'A' + index as u8) as char).to_string(), - crime_type: CrimeType::NonMalicious as i32, - }], - }; - self - } - - fn with_sign_disrupt(mut self, index: usize, round: usize) -> Self { - let keygen_rounds = 4; - self.malicious_data.sign_data.disrupt = Some(Disrupt { - index, - round: round + keygen_rounds, - }); - self.expected_sign_faults = CriminalList { - criminals: vec![Criminal { - party_uid: ((b'A' + index as u8) as char).to_string(), - crime_type: CrimeType::NonMalicious as i32, - }], - }; - self - } -} - -fn generate_basic_cases() -> Vec { - let victim = TypedUsize::from_usize(0); - let behaviours = vec![ - R1BadProof { victim }, - R1BadGammaI, - R2FalseAccusation { victim }, - R2BadMta { victim }, - R2BadMtaWc { victim }, - R3FalseAccusationMta { victim }, - R3FalseAccusationMtaWc { victim }, - R3BadProof, - R3BadDeltaI, - R3BadKI, - R3BadAlpha { victim }, - R3BadBeta { victim }, - R4BadReveal, - R5BadProof { victim }, - R6FalseAccusation { victim }, - R6BadProof, - R6FalseType5Claim, - R7BadSI, - R7FalseType7Claim, - R3BadSigmaI, - ]; - - behaviours - .into_iter() - .map(|b| { - TestCase::new_malicious_sign( - 4, - vec![1, 1, 1, 1], - 3, - vec![ - Signer::new(0, Honest), - Signer::new(1, Honest), - Signer::new(2, Honest), - Signer::new(3, b), - ], - ) - }) - .collect() -} - -fn timeout_cases() -> Vec { - // let timeout_rounds = vec![1]; - let timeout_rounds = vec![1, 2, 3, 4, 5, 6, 7]; - timeout_rounds - .into_iter() - .map(|r| { - TestCase::new_malicious_sign( - 3, - vec![1, 1, 1], - 2, - vec![ - Signer::new(0, Honest), - Signer::new(1, Honest), - Signer::new(2, Honest), - ], - ) - .with_sign_timeout(0, r) // add timeout party at _keygen_ index 0 - }) - .collect() -} - -fn disrupt_cases() -> Vec { - let disrupt_rounds = vec![1, 2, 3, 4, 5, 6, 7]; - disrupt_rounds - .into_iter() - .map(|r| { - TestCase::new_malicious_sign( - 3, - vec![1, 1, 1], - 2, - vec![ - Signer::new(0, Honest), - Signer::new(1, Honest), - Signer::new(2, Honest), - ], - ) - .with_sign_disrupt(0, r) // add disrupt party at _keygen_ index 0 - }) - .collect() -} diff --git a/src/tests/mnemonic.rs b/src/tests/mnemonic.rs index 74be269a..44d47626 100644 --- a/src/tests/mnemonic.rs +++ b/src/tests/mnemonic.rs @@ -1,19 +1,12 @@ //! mnemonic tests at the TofndParty level -use super::{InitParty, TofndParty}; - use crate::mnemonic::Cmd; use testdir::testdir; -#[cfg(feature = "malicious")] -use super::MaliciousData; +use super::{tofnd_party::TofndParty, InitParty}; fn dummy_init_party() -> InitParty { - InitParty::new( - 0, - #[cfg(feature = "malicious")] - &MaliciousData::empty(1), - ) + InitParty::new(0) } #[should_panic] diff --git a/src/tests/mock.rs b/src/tests/mock.rs deleted file mode 100644 index 226987d3..00000000 --- a/src/tests/mock.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::proto; -use std::collections::HashMap; -use tokio::sync::mpsc; -use tracing::error; - -use super::{GrpcKeygenResult, GrpcSignResult}; - -#[tonic::async_trait] -pub(super) trait Party: Sync + Send { - async fn execute_keygen( - &mut self, - init: proto::KeygenInit, - channels: SenderReceiver, - delivery: Deliverer, - notify: std::sync::Arc, - ) -> GrpcKeygenResult; - async fn execute_recover( - &mut self, - keygen_init: proto::KeygenInit, - keygen_output: proto::KeygenOutput, - ); - async fn execute_key_presence(&mut self, key_uid: String) -> bool; - async fn execute_sign( - &mut self, - init: proto::SignInit, - channels: SenderReceiver, - delivery: Deliverer, - my_uid: &str, - notify: std::sync::Arc, - ) -> GrpcSignResult; - async fn shutdown(mut self); - fn get_root(&self) -> std::path::PathBuf; -} - -pub(super) type SenderReceiver = ( - mpsc::UnboundedSender, - mpsc::UnboundedReceiver, -); -#[derive(Clone)] -pub(super) struct Deliverer { - senders: HashMap>, // (party_uid, sender) -} -impl Deliverer { - pub(super) fn with_party_ids(party_ids: &[String]) -> (Self, Vec) { - let channels: Vec = (0..party_ids.len()) - .map(|_| mpsc::unbounded_channel()) - .collect(); - let senders = party_ids - .iter() - .cloned() - .zip(channels.iter().map(|(tx, _)| tx.clone())) - .collect(); - (Deliverer { senders }, channels) - } - pub fn deliver(&self, msg: &proto::MessageOut, from: &str) { - let msg = msg.data.as_ref().expect("missing data"); - let msg = match msg { - proto::message_out::Data::Traffic(t) => t, - _ => { - panic!("msg must be traffic out"); - } - }; - - // simulate wire transmission: translate proto::MessageOut to proto::MessageIn - let msg_in = proto::MessageIn { - data: Some(proto::message_in::Data::Traffic(proto::TrafficIn { - from_party_uid: from.to_string(), - is_broadcast: msg.is_broadcast, - payload: msg.payload.clone(), - })), - }; - - // deliver all msgs to all parties (even p2p msgs) - for (_, sender) in self.senders.iter() { - // we need to catch for errors in case the receiver's channel closes unexpectedly - if let Err(err) = sender.send(msg_in.clone()) { - error!("Error in deliverer while sending message: {:?}", err); - } - } - } - pub fn send_timeouts(&self, secs: u64) { - let abort = proto::message_in::Data::Abort(false); - let msg_in = proto::MessageIn { data: Some(abort) }; - - // allow honest parties to exchange messages for this round - let t = std::time::Duration::from_secs(secs); - std::thread::sleep(t); - - // deliver to all parties - for (_, sender) in self.senders.iter() { - sender.send(msg_in.clone()).unwrap(); - } - } -} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 1358fd42..5c954b86 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,878 +1,23 @@ -// Notes: -// # Helper functions: -// Since we are using tokio, we need to make use of async function. That comes -// with the unfortunate necessity to declare some extra functions in order to -// facilitate the tests. These functions are: -// 1. src/kv_manager::KV::get_db_paths -// 2. src/gg20/mod::get_db_paths -// 3. src/gg20/mod::with_db_name - -use std::convert::TryFrom; -use std::path::{Path, PathBuf}; -use testdir::testdir; -use tokio::time::{sleep, Duration}; -use tonic::Code::InvalidArgument; - -mod mock; -mod tofnd_party; - -mod honest_test_cases; -#[cfg(feature = "malicious")] -mod malicious; -#[cfg(feature = "malicious")] -use malicious::{MaliciousData, PartyMaliciousData}; - mod mnemonic; mod socket_address; - -use crate::mnemonic::Cmd::{self, Create}; -use proto::message_out::CriminalList; -use tracing::{info, warn}; - -use crate::proto::{ - self, - message_out::{ - keygen_result::KeygenResultData::{Criminals as KeygenCriminals, Data as KeygenData}, - sign_result::SignResultData::{Criminals as SignCriminals, Signature}, - KeygenResult, SignResult, - }, -}; -use mock::{Deliverer, Party}; -use tofnd_party::TofndParty; - -// use crate::gg20::proto_helpers::to_criminals; +mod tofnd_party; lazy_static::lazy_static! { static ref MSG_TO_SIGN: Vec = vec![42; 32]; - // TODO add test for messages smaller and larger than 32 bytes } + const SLEEP_TIME: u64 = 1; const MAX_TRIES: u32 = 3; pub const DEFAULT_TEST_IP: &str = "0.0.0.0"; pub const DEFAULT_TEST_PORT: u16 = 0; // use port 0 and let the OS decide -struct TestCase { - uid_count: usize, - share_counts: Vec, - threshold: usize, - signer_indices: Vec, - expected_keygen_faults: CriminalList, - expected_sign_faults: CriminalList, - #[cfg(feature = "malicious")] - malicious_data: MaliciousData, -} - -async fn run_test_cases(test_cases: &[TestCase]) { - let restart = false; - let recover = false; - let dir = testdir!(); - for test_case in test_cases { - basic_keygen_and_sign(test_case, &dir, restart, recover).await; - } -} - -async fn run_restart_test_cases(test_cases: &[TestCase]) { - let restart = true; - let recover = false; - let dir = testdir!(); - for test_case in test_cases { - basic_keygen_and_sign(test_case, &dir, restart, recover).await; - } -} - -async fn run_restart_recover_test_cases(test_cases: &[TestCase]) { - let restart = true; - let recover = true; - let dir = testdir!(); - for test_case in test_cases { - basic_keygen_and_sign(test_case, &dir, restart, recover).await; - } -} - -async fn run_keygen_fail_test_cases(test_cases: &[TestCase]) { - let dir = testdir!(); - for test_case in test_cases { - keygen_init_fail(test_case, &dir).await; - } -} - -async fn run_sign_fail_test_cases(test_cases: &[TestCase]) { - let dir = testdir!(); - for test_case in test_cases { - sign_init_fail(test_case, &dir).await; - } -} - -// Horrible code duplication indeed. Don't think we should spend time here though -// because this will be deleted when axelar-core accommodates crimes -fn successful_keygen_results(results: Vec, expected_faults: &CriminalList) -> bool { - // get the first non-empty result. We can't simply take results[0] because some behaviours - // don't return results and we pad them with `None`s - let first = results.iter().find(|r| r.keygen_result_data.is_some()); - - let mut pub_keys = vec![]; - for result in results.iter() { - let res = match result.keygen_result_data.clone().unwrap() { - KeygenData(data) => data.pub_key, - KeygenCriminals(_) => continue, - }; - pub_keys.push(res); - } - - // else we have at least one result - let first = first.unwrap().clone(); - match first.keygen_result_data { - Some(KeygenData(data)) => { - let first_pub_key = &data.pub_key; - assert_eq!( - expected_faults, - &CriminalList::default(), - "expected faults but none was found" - ); - for (i, pub_key) in pub_keys.iter().enumerate() { - assert_eq!( - first_pub_key, pub_key, - "party {} didn't produce the expected pub_key", - i - ); - } - } - Some(KeygenCriminals(ref actual_faults)) => { - assert_eq!(expected_faults, actual_faults); - info!("Fault list: {:?}", expected_faults); - return false; - } - None => { - panic!("Result was None"); - } - } - true -} - -// Horrible code duplication indeed. Don't think we should spend time here though -// because this will be deleted when axelar-core accommodates crimes -fn check_sign_results(results: Vec, expected_faults: &CriminalList) -> bool { - // get the first non-empty result. We can't simply take results[0] because some behaviours - // don't return results and we pad them with `None`s - let first = results.iter().find(|r| r.sign_result_data.is_some()); - - let mut pub_keys = vec![]; - for result in results.iter() { - let res = match result.sign_result_data.clone().unwrap() { - Signature(signature) => signature, - SignCriminals(_) => continue, - }; - pub_keys.push(res); - } - - // else we have at least one result - let first = first.unwrap().clone(); - match first.sign_result_data { - Some(Signature(signature)) => { - let first_signature = signature; - assert_eq!( - expected_faults, - &CriminalList::default(), - "expected faults but none was found" - ); - for (i, signature) in pub_keys.iter().enumerate() { - assert_eq!( - &first_signature, signature, - "party {} didn't produce the expected signature", - i - ); - } - } - Some(SignCriminals(ref actual_faults)) => { - assert_eq!(expected_faults, actual_faults); - info!("Fault list: {:?}", expected_faults); - return false; - } - None => { - panic!("Result was None"); - } - } - true -} - -fn gather_recover_info(results: &[KeygenResult]) -> Vec { - // gather recover info - let mut recover_infos = vec![]; - for result in results.iter() { - let result_data = result.keygen_result_data.clone().unwrap(); - match result_data { - KeygenData(output) => { - recover_infos.push(output); - } - KeygenCriminals(_) => {} - } - } - recover_infos -} - -// shutdown i-th party -// returns i-th party's db path and a vec of Option that contain all parties (including i-th) -async fn shutdown_party( - parties: Vec, - party_index: usize, -) -> (Vec>, PathBuf) { - info!("shutdown party {}", party_index); - let party_root = parties[party_index].get_root(); - // use Option to temporarily transfer ownership of individual parties to a spawn - let mut party_options: Vec> = parties.into_iter().map(Some).collect(); - let shutdown_party = party_options[party_index].take().unwrap(); - shutdown_party.shutdown().await; - (party_options, party_root) -} - -// deletes the share kv-store of a party's db path -fn delete_party_export(mut mnemonic_path: PathBuf) { - mnemonic_path.push("export"); - std::fs::remove_file(mnemonic_path).unwrap(); -} - -// deletes the share kv-store of a party's db path -async fn delete_party_shares(mut party_db_path: PathBuf, key: &str) { - party_db_path.push("kvstore/kv"); - info!("Deleting shares for {:?}", party_db_path); - - let mut tries = 0; - let db = loop { - match sled::open(&party_db_path) { - Ok(db) => break db, - Err(err) => { - sleep(Duration::from_secs(SLEEP_TIME)).await; - warn!("({}/{}) Cannot open db: {}", tries, err, MAX_TRIES); - } - } - tries += 1; - if tries == MAX_TRIES { - panic!("Cannot open db"); - } - }; - - match db.remove(key) { - Ok(_) => {} - Err(err) => { - panic!("Could not remove key {} from kvstore: {}", key, err) - } - }; -} - -// reinitializes i-th party -// pass malicious data if we are running in malicious mode -async fn reinit_party( - mut party_options: Vec>, - party_index: usize, - testdir: &Path, - #[cfg(feature = "malicious")] malicious_data: &MaliciousData, -) -> Vec { - // initialize restarted party with its previous behaviour if we are in malicious mode - let init_party = InitParty::new( - party_index, - #[cfg(feature = "malicious")] - malicious_data, - ); - - // here we assume that the party already has a mnemonic, so we pass Cmd::Existing - party_options[party_index] = Some(TofndParty::new(init_party, Cmd::Existing, testdir).await); - - party_options - .into_iter() - .map(|o| o.unwrap()) - .collect::>() -} - -// delete all kv-stores of all parties and kill servers -async fn clean_up(parties: Vec) { - delete_dbs(&parties); - shutdown_parties(parties).await; -} - -// create parties that will participate in keygen/sign from testcase args -async fn init_parties_from_test_case( - test_case: &TestCase, - dir: &Path, -) -> (Vec, Vec) { - let init_parties_t = InitParties::new( - test_case.uid_count, - #[cfg(feature = "malicious")] - &test_case.malicious_data, - ); - init_parties(&init_parties_t, dir).await -} - -// keygen wrapper -async fn basic_keygen( - test_case: &TestCase, - parties: Vec, - party_uids: Vec, - new_key_uid: &str, -) -> (Vec, proto::KeygenInit, Vec, bool) { - let party_share_counts = &test_case.share_counts; - let threshold = test_case.threshold; - let expected_keygen_faults = &test_case.expected_keygen_faults; - - info!( - "======= Expected keygen crimes: {:?}", - expected_keygen_faults - ); - - #[allow(unused_variables)] // allow unsused in non malicious - let expect_timeout = false; - #[cfg(feature = "malicious")] - let expect_timeout = test_case.malicious_data.keygen_data.timeout.is_some(); - - let (parties, results, keygen_init) = execute_keygen( - parties, - &party_uids, - party_share_counts, - new_key_uid, - threshold, - expect_timeout, - ) - .await; - - // a successful keygen does not have grpc errors - let results = results.into_iter().map(|r| r.unwrap()).collect::>(); - let success = successful_keygen_results(results.clone(), expected_keygen_faults); - (parties, keygen_init, results, success) -} - -// restart i-th and optionally delete its shares kv-store -async fn restart_party( - dir: &Path, - parties: Vec, - party_index: usize, - recover: bool, - key_uid: String, - #[cfg(feature = "malicious")] malicious_data: &MaliciousData, -) -> Vec { - // shutdown party with party_index - let (party_options, shutdown_db_path) = shutdown_party(parties, party_index).await; - - // if we are going to restart, delete exported mnemonic to allow using Cmd::Existing - delete_party_export(shutdown_db_path.clone()); - - if recover { - // if we are going to recover, delete party's shares - delete_party_shares(shutdown_db_path, &key_uid).await; - } - - // reinit party - let mut parties = reinit_party( - party_options, - party_index, - dir, - #[cfg(feature = "malicious")] - malicious_data, - ) - .await; - - if recover { - // Check that session for the party doing recovery is absent in kvstore - let is_key_present = parties[party_index].execute_key_presence(key_uid).await; - - assert!( - !is_key_present, - "Expected session to be absent after a restart" - ); - } - - parties -} - -// main testing function -async fn basic_keygen_and_sign(test_case: &TestCase, dir: &Path, restart: bool, recover: bool) { - // set up a key uid - let new_key_uid = "Gus-test-key"; - - // use test case params to create parties - let (parties, party_uids) = init_parties_from_test_case(test_case, dir).await; - - // Check that the session is not present in the kvstore - let parties = execute_key_presence(parties, new_key_uid.into(), false).await; - - // execute keygen and return everything that will be needed later on - let (parties, keygen_init, keygen_results, success) = - basic_keygen(test_case, parties, party_uids.clone(), new_key_uid).await; - - if !success { - clean_up(parties).await; - return; - } - - // Check that the session is present in the kvstore - let parties = execute_key_presence(parties, new_key_uid.into(), true).await; - - // restart party if restart is enabled and return new parties' set - let parties = match restart { - true => { - restart_party( - dir, - parties, - test_case.signer_indices[0], - recover, - keygen_init.new_key_uid.clone(), - #[cfg(feature = "malicious")] - &test_case.malicious_data, - ) - .await - } - false => parties, - }; - - // delete party's if recover is enabled and return new parties' set - let parties = match recover { - true => { - execute_recover( - parties, - test_case.signer_indices[0], - keygen_init, - gather_recover_info(&keygen_results), - ) - .await - } - false => parties, - }; - - let expected_sign_faults = &test_case.expected_sign_faults; - - #[allow(unused_variables)] // allow unsused in non malicious - let expect_timeout = false; - #[cfg(feature = "malicious")] - let expect_timeout = test_case.malicious_data.sign_data.timeout.is_some(); - - // Check that the session is present in the kvstore - let parties = execute_key_presence(parties, new_key_uid.into(), true).await; - - // execute sign - let new_sig_uid = "Gus-test-sig"; - let (parties, results) = execute_sign( - parties, - &party_uids, - &test_case.signer_indices, - new_key_uid, - new_sig_uid, - &MSG_TO_SIGN, - expect_timeout, - ) - .await; - let results = results.into_iter().map(|r| r.unwrap()).collect::>(); - check_sign_results(results, expected_sign_faults); - - clean_up(parties).await; -} - -async fn keygen_init_fail(test_case: &TestCase, dir: &Path) { - // set up a key uid - let new_key_uid = "test-key"; - - // use test case params to create parties - let (parties, party_uids) = init_parties_from_test_case(test_case, dir).await; - - // execute keygen and return everything that will be needed later on - let (parties, _, _, _) = - basic_keygen(test_case, parties, party_uids.clone(), new_key_uid).await; - - // attempt to execute keygen again with the same `new_key_id` - let (parties, results, _) = execute_keygen( - parties, - &party_uids, - &test_case.share_counts, - new_key_uid, - test_case.threshold, - false, - ) - .await; - - // all results must be Err(Status) with Code::InvalidArgument - for result in results { - assert_eq!(result.err().unwrap().code(), InvalidArgument); - } - - clean_up(parties).await; -} - -async fn sign_init_fail(test_case: &TestCase, dir: &Path) { - // set up a key uid - let new_key_uid = "test-key"; - let new_sign_uid = "sign-test-key"; - - // use test case params to create parties - let (parties, party_uids) = init_parties_from_test_case(test_case, dir).await; - - // execute keygen and return everything that will be needed later on - let (parties, _, _, success) = - basic_keygen(test_case, parties, party_uids.clone(), new_key_uid).await; - assert!(success); - - // attempt to execute sign with malformed `MSG_TO_SIGN` - let (parties, results) = execute_sign( - parties, - &party_uids, - &test_case.signer_indices, - new_key_uid, - new_sign_uid, - &MSG_TO_SIGN[0..MSG_TO_SIGN.len() - 1], - false, - ) - .await; - - // all results must be Err(Status) with Code::InvalidArgument - for result in results { - assert_eq!(result.err().unwrap().code(), InvalidArgument); - } - - clean_up(parties).await; -} - -// struct to pass in TofndParty constructor. -// needs to include malicious when we are running in malicious mode +// Struct to pass in TofndParty constructor. struct InitParty { party_index: usize, - #[cfg(feature = "malicious")] - malicious_data: PartyMaliciousData, } impl InitParty { - // as ugly as it gets - fn new( - my_index: usize, - #[cfg(feature = "malicious")] all_malicious_data: &MaliciousData, - ) -> InitParty { - #[cfg(feature = "malicious")] - let malicious_data = { - // register timeouts - let mut timeout_round = 0; - if let Some(timeout) = all_malicious_data.keygen_data.timeout.clone() { - if timeout.index == my_index { - timeout_round = timeout.round; - } - } - if let Some(timeout) = all_malicious_data.sign_data.timeout.clone() { - if timeout.index == my_index { - timeout_round = timeout.round; - } - } - - // register disrupts - let mut disrupt_round = 0; - if let Some(disrupt) = all_malicious_data.keygen_data.disrupt.clone() { - if disrupt.index == my_index { - disrupt_round = disrupt.round; - } - } - if let Some(disrupt) = all_malicious_data.sign_data.disrupt.clone() { - if disrupt.index == my_index { - disrupt_round = disrupt.round; - } - } - - // get keygen malicious behaviours - let my_keygen_behaviour = all_malicious_data - .keygen_data - .behaviours - .get(my_index) - .unwrap() - .clone(); - - // get sign malicious behaviours - let my_sign_behaviour = all_malicious_data - .sign_data - .behaviours - .get(my_index) - .unwrap() - .clone(); - - // construct struct of malicous data - PartyMaliciousData { - timeout_round, - disrupt_round, - keygen_behaviour: my_keygen_behaviour, - sign_behaviour: my_sign_behaviour, - } - }; - - InitParty { - party_index: my_index, - #[cfg(feature = "malicious")] - malicious_data, - } - } -} - -// struct to pass in init_parties function. -// needs to include malicious when we are running in malicious mode -struct InitParties { - party_count: usize, - #[cfg(feature = "malicious")] - malicious_data: MaliciousData, -} - -impl InitParties { - fn new( - party_count: usize, - #[cfg(feature = "malicious")] malicious_data: &MaliciousData, - ) -> InitParties { - InitParties { - party_count, - #[cfg(feature = "malicious")] - malicious_data: malicious_data.clone(), - } + fn new(party_index: usize) -> Self { + Self { party_index } } } - -async fn init_parties( - init_parties: &InitParties, - testdir: &Path, -) -> (Vec, Vec) { - let mut parties = Vec::with_capacity(init_parties.party_count); - - // use a for loop because async closures are unstable https://github.com/rust-lang/rust/issues/62290 - for i in 0..init_parties.party_count { - let init_party = InitParty::new( - i, - #[cfg(feature = "malicious")] - &init_parties.malicious_data, - ); - parties.push(TofndParty::new(init_party, Create, testdir).await); - } - - let party_uids: Vec = (0..init_parties.party_count) - .map(|i| format!("{}", (b'A' + i as u8) as char)) - .collect(); - - (parties, party_uids) -} - -async fn shutdown_parties(parties: Vec) { - for p in parties { - p.shutdown().await; - } -} - -fn delete_dbs(parties: &[impl Party]) { - for p in parties { - // Sled creates a directory for the database and its configuration - std::fs::remove_dir_all(p.get_root()).unwrap(); - } -} - -use tonic::Status; -type GrpcKeygenResult = Result; -type GrpcSignResult = Result; - -// need to take ownership of parties `parties` and return it on completion -async fn execute_keygen( - parties: Vec, - party_uids: &[String], - party_share_counts: &[u32], - new_key_uid: &str, - threshold: usize, - expect_timeout: bool, -) -> (Vec, Vec, proto::KeygenInit) { - info!("Expecting timeout: [{}]", expect_timeout); - let share_count = parties.len(); - let (keygen_delivery, keygen_channel_pairs) = Deliverer::with_party_ids(party_uids); - let mut keygen_join_handles = Vec::with_capacity(share_count); - let notify = std::sync::Arc::new(tokio::sync::Notify::new()); - for (i, (mut party, channel_pair)) in parties - .into_iter() - .zip(keygen_channel_pairs.into_iter()) - .enumerate() - { - let init = proto::KeygenInit { - new_key_uid: new_key_uid.to_string(), - party_uids: party_uids.to_owned(), - party_share_counts: party_share_counts.to_owned(), - my_party_index: u32::try_from(i).unwrap(), - threshold: u32::try_from(threshold).unwrap(), - }; - let delivery = keygen_delivery.clone(); - let n = notify.clone(); - let handle = tokio::spawn(async move { - let result = party.execute_keygen(init, channel_pair, delivery, n).await; - (party, result) - }); - keygen_join_handles.push(handle); - } - - // Sleep here to prevent data races between parties: - // some clients might start sending TrafficIn messages to other parties' - // servers before these parties manage to receive their own - // KeygenInit/SignInit from their clients. This leads to an - // `WrongMessage` error. - sleep(Duration::from_secs(SLEEP_TIME)).await; - // wake up one party - notify.notify_one(); - - // if we are expecting a timeout, abort parties after a reasonable amount of time - if expect_timeout { - let unblocker = keygen_delivery.clone(); - abort_parties(unblocker, 10); - } - - let mut parties = Vec::with_capacity(share_count); // async closures are unstable https://github.com/rust-lang/rust/issues/62290 - let mut results = vec![]; - for h in keygen_join_handles { - let handle = h.await.unwrap(); - parties.push(handle.0); - results.push(handle.1); - } - let init = proto::KeygenInit { - new_key_uid: new_key_uid.to_string(), - party_uids: party_uids.to_owned(), - party_share_counts: party_share_counts.to_owned(), - my_party_index: 0, // return keygen for first party. Might need to change index before using - threshold: u32::try_from(threshold).unwrap(), - }; - (parties, results, init) -} - -async fn execute_key_presence( - parties: Vec, - key_uid: String, - expected_key_present: bool, -) -> Vec { - let mut handles = Vec::new(); - - for mut party in parties { - let key_uid = key_uid.clone(); - - let handle = tokio::spawn(async move { - let res = party.execute_key_presence(key_uid).await; - (party, res) - }); - - handles.push(handle); - } - - let mut parties = Vec::new(); - - for handle in handles { - let (party, is_key_present) = handle.await.unwrap(); - assert_eq!( - is_key_present, expected_key_present, - "Key presence expected to be {} but observed {}", - expected_key_present, is_key_present - ); - - parties.push(party); - } - - parties -} - -async fn execute_recover( - mut parties: Vec, - recover_party_index: usize, - mut keygen_init: proto::KeygenInit, - keygen_outputs: Vec, -) -> Vec { - // create keygen init for recovered party - let key_uid = keygen_init.new_key_uid.clone(); - - keygen_init.my_party_index = recover_party_index as u32; - parties[recover_party_index] - .execute_recover(keygen_init, keygen_outputs[recover_party_index].clone()) - .await; - - // Check that session for the party doing recovery is absent in kvstore - let is_key_present = parties[recover_party_index] - .execute_key_presence(key_uid) - .await; - - assert!( - is_key_present, - "Expected session to be present after a recovery" - ); - - parties -} - -// need to take ownership of parties `parties` and return it on completion -async fn execute_sign( - parties: Vec, - party_uids: &[String], - sign_participant_indices: &[usize], - key_uid: &str, - new_sig_uid: &str, - msg_to_sign: &[u8], - expect_timeout: bool, -) -> (Vec, Vec) { - info!("Expecting timeout: [{}]", expect_timeout); - let participant_uids: Vec = sign_participant_indices - .iter() - .map(|&i| party_uids[i].clone()) - .collect(); - let (sign_delivery, sign_channel_pairs) = Deliverer::with_party_ids(&participant_uids); - - // use Option to temporarily transfer ownership of individual parties to a spawn - let mut party_options: Vec> = parties.into_iter().map(Some).collect(); - - let mut sign_join_handles = Vec::with_capacity(sign_participant_indices.len()); - let notify = std::sync::Arc::new(tokio::sync::Notify::new()); - for (i, channel_pair) in sign_channel_pairs.into_iter().enumerate() { - let participant_index = sign_participant_indices[i]; - - // clone everything needed in spawn - let init = proto::SignInit { - new_sig_uid: new_sig_uid.to_string(), - key_uid: key_uid.to_string(), - party_uids: participant_uids.clone(), - message_to_sign: msg_to_sign.to_vec(), - }; - let delivery = sign_delivery.clone(); - let participant_uid = participant_uids[i].clone(); - let mut party = party_options[participant_index].take().unwrap(); - - let n = notify.clone(); - // execute the protocol in a spawn - let handle = tokio::spawn(async move { - let result = party - .execute_sign(init, channel_pair, delivery, &participant_uid, n) - .await; - (party, result) - }); - sign_join_handles.push((i, handle)); - } - - // Sleep here to prevent data races between parties: - // some clients might start sending TrafficIn messages to other parties' - // servers before these parties manage to receive their own - // KeygenInit/SignInit from their clients. This leads to an - // `WrongMessage` error. - sleep(Duration::from_secs(SLEEP_TIME)).await; - notify.notify_one(); - - // if we are expecting a timeout, abort parties after a reasonable amount of time - if expect_timeout { - let unblocker = sign_delivery.clone(); - abort_parties(unblocker, 10); - } - - let mut results = Vec::with_capacity(sign_join_handles.len()); - for (i, h) in sign_join_handles { - info!("Running party {}", i); - let handle = h.await.unwrap(); - party_options[sign_participant_indices[i]] = Some(handle.0); - results.push(handle.1); - } - ( - party_options - .into_iter() - .map(|o| o.unwrap()) - .collect::>(), - results, - ) -} - -fn abort_parties(unblocker: Deliverer, time: u64) { - // send an abort message if protocol is taking too much time - info!("I will send an abort message in {} seconds", time); - std::thread::spawn(move || { - unblocker.send_timeouts(time); - }); - info!("Continuing for now"); -} diff --git a/src/tests/tofnd_party.rs b/src/tests/tofnd_party.rs index ee37ea6d..c5f03235 100644 --- a/src/tests/tofnd_party.rs +++ b/src/tests/tofnd_party.rs @@ -1,48 +1,31 @@ -// TODO: To facilitate timeout and disruption tests we need to count incoming messages. -// This brings a bunch of functions and counters that are needed only for malicious build -// For now, we use `#[allow(allow)]` instead of `#[cfg(feature = "malicious")]` because it -// produces less friction in the code. Should implement a beeter solution soon. - -use super::{ - mock::SenderReceiver, Deliverer, GrpcKeygenResult, GrpcSignResult, InitParty, Party, - DEFAULT_TEST_IP, DEFAULT_TEST_PORT, MAX_TRIES, -}; +use super::{InitParty, DEFAULT_TEST_IP, DEFAULT_TEST_PORT, MAX_TRIES}; use crate::{ addr, config::Config, encrypted_sled::{get_test_password, PasswordMethod}, - gg20, kv_manager::KvManager, mnemonic::Cmd, - proto::{self, Algorithm}, + multisig, proto, tests::SLEEP_TIME, }; -use proto::message_out::{KeygenResult, SignResult}; use std::path::Path; -use std::{convert::TryFrom, path::PathBuf}; +use std::path::PathBuf; use tokio::time::{sleep, Duration}; use tokio::{net::TcpListener, sync::oneshot, task::JoinHandle}; -use tokio_stream::wrappers::{TcpListenerStream, UnboundedReceiverStream}; -use tonic::Request; +use tokio_stream::wrappers::TcpListenerStream; use tracing::{info, warn}; -#[cfg(feature = "malicious")] -use super::malicious::PartyMaliciousData; -#[cfg(feature = "malicious")] -use gg20::service::malicious::Behaviours; - // I tried to keep this struct private and return `impl Party` from new() but ran into so many problems with the Rust compiler // I also tried using Box but ran into this: https://github.com/rust-lang/rust/issues/63033 +#[allow(dead_code)] pub(super) struct TofndParty { tofnd_path: PathBuf, - client: proto::gg20_client::Gg20Client, + client: proto::multisig_client::MultisigClient, server_handle: JoinHandle<()>, server_shutdown_sender: oneshot::Sender<()>, server_port: u16, - #[cfg(feature = "malicious")] - pub(super) malicious_data: PartyMaliciousData, } impl TofndParty { @@ -68,11 +51,6 @@ impl TofndParty { safe_keygen: false, tofnd_path, password_method: PasswordMethod::NoPassword, - #[cfg(feature = "malicious")] - behaviours: Behaviours { - keygen: init_party.malicious_data.keygen_behaviour.clone(), - sign: init_party.malicious_data.sign_behaviour.clone(), - }, }; // start service @@ -97,9 +75,9 @@ impl TofndParty { }; let kv_manager = kv_manager.handle_mnemonic(&cfg.mnemonic_cmd).await.unwrap(); - let my_service = gg20::service::new_service(cfg.clone(), kv_manager); + let my_service = multisig::service::new_service(kv_manager); - let proto_service = proto::gg20_server::Gg20Server::new(my_service); + let proto_service = proto::multisig_server::MultisigServer::new(my_service); // let (startup_sender, startup_receiver) = tokio::sync::oneshot::channel::<()>(); let server_handle = tokio::spawn(async move { tonic::transport::Server::builder() @@ -122,9 +100,10 @@ impl TofndParty { // println!("party [{}] server started!", init.party_uids[my_id_index]); info!("new party [{}] connect to server...", server_port); - let client = proto::gg20_client::Gg20Client::connect(format!("http://{}", server_addr)) - .await - .unwrap(); + let client = + proto::multisig_client::MultisigClient::connect(format!("http://{}", server_addr)) + .await + .unwrap(); TofndParty { tofnd_path: cfg.tofnd_path, @@ -132,388 +111,6 @@ impl TofndParty { server_handle, server_shutdown_sender, server_port, - #[cfg(feature = "malicious")] - malicious_data: init_party.malicious_data, - } - } -} - -// r1 -> bcast -// r2 -> bcast -// r3 -> bcast + p2ps -// r4 -> bcast -#[allow(unused)] // allow unsused traffin in non malicious -fn keygen_round(msg_count: usize, all_share_counts: usize, my_share_count: usize) -> usize { - let bcast = 1; - let p2ps = all_share_counts - 1; - - let r1_msgs = bcast; - let r2_msgs = r1_msgs + bcast; - let r3_msgs = r2_msgs + bcast + p2ps; - let r4_msgs = r3_msgs + bcast; - - // multiply by my share count - let r1_msgs = r1_msgs * my_share_count; - let r2_msgs = r2_msgs * my_share_count; - let r3_msgs = r3_msgs * my_share_count; - let r4_msgs = r4_msgs * my_share_count; - - let last = r4_msgs + my_share_count; // n bcasts and n(n-1) p2ps - - if 1 <= msg_count && msg_count <= r1_msgs { - return 1; - } else if r1_msgs < msg_count && msg_count <= r2_msgs { - return 2; - } else if r2_msgs < msg_count && msg_count <= r3_msgs { - return 3; - } else if r3_msgs < msg_count && msg_count <= r4_msgs { - return 4; - } - - // return something that won't trigger a timeout in non-timeout malicous cases with multiple shares - usize::MAX -} - -// r1 -> bcast + p2ps -// r2 -> p2ps -// r3 -> bcast -// r4 -> bcast -// r5 -> bcast + p2ps -// r6 -> bcast -// r7 -> bcast -#[allow(unused)] // allow unsused traffin in non malicious -fn sign_round(msg_count: usize, all_share_counts: usize, my_share_count: usize) -> usize { - let bcast = 1; - let p2ps = all_share_counts - 1; - - let r1_msgs = bcast + p2ps; - let r2_msgs = r1_msgs + p2ps; - let r3_msgs = r2_msgs + bcast; - let r4_msgs = r3_msgs + bcast; - let r5_msgs = r4_msgs + bcast + p2ps; - let r6_msgs = r5_msgs + bcast; - let r7_msgs = r6_msgs + bcast; - let r8_msgs = r7_msgs + bcast; - - // multiply by my share count - let r1_msgs = r1_msgs * my_share_count; - let r2_msgs = r2_msgs * my_share_count; - let r3_msgs = r3_msgs * my_share_count; - let r4_msgs = r4_msgs * my_share_count; - let r5_msgs = r5_msgs * my_share_count; - let r6_msgs = r6_msgs * my_share_count; - let r7_msgs = r7_msgs * my_share_count; - - // let last = r4_msgs + my_share_count; // n bcasts and n(n-1) p2ps - - let mut round = 0; - if 1 <= msg_count && msg_count <= r1_msgs { - round = 1; - } else if r1_msgs < msg_count && msg_count <= r2_msgs { - round = 2; - } else if r2_msgs < msg_count && msg_count <= r3_msgs { - round = 3; - } else if r3_msgs < msg_count && msg_count <= r4_msgs { - round = 4; - } else if r4_msgs < msg_count && msg_count <= r5_msgs { - round = 5; - } else if r5_msgs < msg_count && msg_count <= r6_msgs { - round = 6; - } else if r6_msgs < msg_count && msg_count <= r7_msgs { - round = 7; - } else if r7_msgs < msg_count && msg_count <= r8_msgs { - round = 8; - } - // if we got a round from message count successfully, then add keygen rounds to it - if round != 0 { - let keygen_rounds = 4; - return round + keygen_rounds; - } - - // TODO: support multiple shares for sign. For now, return something that is not 0. - // panic!("message counter overflow: {}. Max is {}", msg_count, last); // this info should be a panic - - // return something that won't trigger a timeout in non-timeout malicous cases with multiple shares - usize::MAX -} - -#[tonic::async_trait] -impl Party for TofndParty { - async fn execute_keygen( - &mut self, - init: proto::KeygenInit, - channels: SenderReceiver, - delivery: Deliverer, - notify: std::sync::Arc, - ) -> GrpcKeygenResult { - let my_uid = init.party_uids[usize::try_from(init.my_party_index).unwrap()].clone(); - let (keygen_server_incoming, rx) = channels; - let mut keygen_server_outgoing = self - .client - .keygen(Request::new(UnboundedReceiverStream::new(rx))) - .await - .unwrap() - .into_inner(); - - #[allow(unused_variables)] - let all_share_count = { - if init.party_share_counts.is_empty() { - init.party_uids.len() - } else { - init.party_share_counts.iter().sum::() as usize - } - }; - #[allow(unused_variables)] - let my_share_count = { - if init.party_share_counts.is_empty() { - 1 - } else { - init.party_share_counts[init.my_party_index as usize] as usize - } - }; - // the first outbound message is keygen init info - keygen_server_incoming - .send(proto::MessageIn { - data: Some(proto::message_in::Data::KeygenInit(init)), - }) - .unwrap(); - - // block until all parties send their KeygenInit - notify.notified().await; - notify.notify_one(); - - #[allow(unused_variables)] - let mut msg_count = 1; - - let result = loop { - let msg = match keygen_server_outgoing.message().await { - Ok(msg) => match msg { - Some(msg) => msg, - None => { - warn!( - "party [{}] keygen execution was not completed due to abort", - my_uid - ); - return Ok(KeygenResult::default()); - } - }, - Err(status) => { - warn!( - "party [{}] keygen execution was not completed due to connection error: {}", - my_uid, status - ); - return Err(status); - } - }; - - let msg_type = msg.data.as_ref().expect("missing data"); - - match msg_type { - #[allow(unused_variables)] // allow unsused traffin in non malicious - proto::message_out::Data::Traffic(traffic) => { - // in malicous case, if we are stallers we skip the message - #[cfg(feature = "malicious")] - { - let round = keygen_round(msg_count, all_share_count, my_share_count); - if self.malicious_data.timeout_round == round { - warn!("{} is stalling a message in round {}", my_uid, round); - continue; // tough is the life of the staller - } - if self.malicious_data.disrupt_round == round { - warn!("{} is disrupting a message in round {}", my_uid, round); - let mut t = traffic.clone(); - t.payload = traffic.payload[0..traffic.payload.len() / 2].to_vec(); - let mut m = msg.clone(); - m.data = Some(proto::message_out::Data::Traffic(t)); - delivery.deliver(&m, &my_uid); - } - } - delivery.deliver(&msg, &my_uid); - } - proto::message_out::Data::KeygenResult(res) => { - info!("party [{}] keygen finished!", my_uid); - break Ok(res.clone()); - } - _ => panic!("party [{}] keygen error: bad outgoing message type", my_uid), - }; - msg_count += 1; - }; - - info!("party [{}] keygen execution complete", my_uid); - result - } - - async fn execute_recover( - &mut self, - keygen_init: proto::KeygenInit, - keygen_output: proto::KeygenOutput, - ) { - let recover_request = proto::RecoverRequest { - keygen_init: Some(keygen_init), - keygen_output: Some(keygen_output), - }; - let response = self - .client - .recover(Request::new(recover_request)) - .await - .unwrap() - .into_inner(); - - // prost way to convert i32 to enums https://github.com/danburkert/prost#enumerations - match proto::recover_response::Response::from_i32(response.response) { - Some(proto::recover_response::Response::Success) => { - info!("Got success from recover") - } - Some(proto::recover_response::Response::Fail) => { - warn!("Got fail from recover") - } - Some(proto::recover_response::Response::Unspecified) => { - panic!("Unspecified recovery response. Expecting Success/Fail") - } - None => { - panic!("Invalid recovery response. Could not convert i32 to enum") - } } } - - async fn execute_key_presence(&mut self, key_uid: String) -> bool { - let key_presence_request = proto::KeyPresenceRequest { - key_uid, - pub_key: vec![], - algorithm: Algorithm::Ecdsa as i32, - }; - - let response = self - .client - .key_presence(Request::new(key_presence_request)) - .await - .unwrap() - .into_inner(); - - // prost way to convert i32 to enums https://github.com/danburkert/prost#enumerations - match proto::key_presence_response::Response::from_i32(response.response) { - Some(proto::key_presence_response::Response::Present) => true, - Some(proto::key_presence_response::Response::Absent) => false, - Some(proto::key_presence_response::Response::Fail) => { - panic!("key presence request failed") - } - Some(proto::key_presence_response::Response::Unspecified) => { - panic!("Unspecified key presence response") - } - None => { - panic!("Invalid key presence response. Could not convert i32 to enum") - } - } - } - - async fn execute_sign( - &mut self, - init: proto::SignInit, - channels: SenderReceiver, - delivery: Deliverer, - my_uid: &str, - notify: std::sync::Arc, - ) -> GrpcSignResult { - let (sign_server_incoming, rx) = channels; - let mut sign_server_outgoing = self - .client - .sign(Request::new(UnboundedReceiverStream::new(rx))) - .await - .unwrap() - .into_inner(); - - // TODO: support multiple shares for sign - #[allow(unused_variables)] // allow unsused traffin in non malicious - let all_share_count = init.party_uids.len(); - #[allow(unused_variables)] // allow unsused traffin in non malicious - let my_share_count = 1; - - // the first outbound message is sign init info - sign_server_incoming - .send(proto::MessageIn { - data: Some(proto::message_in::Data::SignInit(init)), - }) - .unwrap(); - - // block until all parties send their SignInit - notify.notified().await; - notify.notify_one(); - - #[allow(unused_variables)] // allow unsused traffin in non malicious - let mut msg_count = 1; - - let result = loop { - let msg = match sign_server_outgoing.message().await { - Ok(msg) => match msg { - Some(msg) => msg, - None => { - warn!( - "party [{}] sign execution was not completed due to abort", - my_uid - ); - return Ok(SignResult::default()); - } - }, - Err(status) => { - warn!( - "party [{}] sign execution was not completed due to connection error: {}", - my_uid, status - ); - return Err(status); - } - }; - - let msg_type = msg.data.as_ref().expect("missing data"); - - match msg_type { - #[allow(unused_variables)] // allow unsused traffin in non malicious - proto::message_out::Data::Traffic(traffic) => { - // in malicous case, if we are stallers we skip the message - #[cfg(feature = "malicious")] - { - let round = sign_round(msg_count, all_share_count, my_share_count); - if self.malicious_data.timeout_round == round { - warn!("{} is stalling a message in round {}", my_uid, round - 4); // subtract keygen rounds - continue; // tough is the life of the staller - } - if self.malicious_data.disrupt_round == round { - warn!("{} is disrupting a message in round {}", my_uid, round); - let mut t = traffic.clone(); - t.payload = traffic.payload[0..traffic.payload.len() / 2].to_vec(); - let mut m = msg.clone(); - m.data = Some(proto::message_out::Data::Traffic(t)); - delivery.deliver(&m, my_uid); - } - } - delivery.deliver(&msg, my_uid); - } - proto::message_out::Data::SignResult(res) => { - info!("party [{}] sign finished!", my_uid); - break Ok(res.clone()); - } - proto::message_out::Data::NeedRecover(_) => { - info!("party [{}] needs recover", my_uid); - // when recovery is needed, sign is canceled. We abort the protocol manualy instead of waiting parties to time out - // no worries that we don't wait for enough time, we will not be checking criminals in this case - delivery.send_timeouts(0); - break Ok(SignResult::default()); - } - _ => panic!("party [{}] sign error: bad outgoing message type", my_uid), - }; - msg_count += 1; - }; - - info!("party [{}] sign execution complete", my_uid); - result - } - - async fn shutdown(mut self) { - self.server_shutdown_sender.send(()).unwrap(); // tell the server to shut down - self.server_handle.await.unwrap(); // wait for server to shut down - info!("party [{}] shutdown success", self.server_port); - } - - fn get_root(&self) -> std::path::PathBuf { - self.tofnd_path.clone() - } } From 48833e6f4e9d41d36eb6f48af808458ff6c995ed Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 18:46:57 -0400 Subject: [PATCH 02/15] clean pin rust version and clean up actions --- .../build-docker-image-and-binaries.yaml | 24 ++++++++++--------- .../workflows/build-latest-docker-image.yaml | 2 +- .github/workflows/format.yaml | 4 ++-- .github/workflows/lint.yaml | 10 ++------ .github/workflows/release.yaml | 2 +- .github/workflows/test.yaml | 4 ++-- install-gmp-arm64.sh | 6 ----- 7 files changed, 21 insertions(+), 31 deletions(-) delete mode 100755 install-gmp-arm64.sh diff --git a/.github/workflows/build-docker-image-and-binaries.yaml b/.github/workflows/build-docker-image-and-binaries.yaml index ebd75196..ad2eb7fd 100644 --- a/.github/workflows/build-docker-image-and-binaries.yaml +++ b/.github/workflows/build-docker-image-and-binaries.yaml @@ -40,37 +40,39 @@ jobs: aws s3 ls s3://axelar-releases/tofnd/"$SEMVER" && echo "tag already exists, use a new one" && exit 1 - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: '0' ref: ${{ github.event.inputs.tag }} submodules: recursive - - name: Install Rust - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.78.0 + override: true + components: rustfmt, clippy - - name: build darwin binaries + - name: Build Mac OS binaries env: SEMVER: ${{ github.event.inputs.tag }} if: matrix.os == 'macos-latest' run: | OS="darwin" ARCH="${{ matrix.arch }}" + mkdir tofndbin if [ "$ARCH" == "arm64" ] then - ./install-gmp-arm64.sh rustup target add aarch64-apple-darwin - cargo build --release --target aarch64-apple-darwin - mkdir tofndbin + cargo build --release --locked --target aarch64-apple-darwin mv /Users/runner/work/tofnd/tofnd/target/aarch64-apple-darwin/release/tofnd "./tofndbin/tofnd-$OS-$ARCH-$SEMVER" else cargo install --locked --path . - mkdir tofndbin mv "/Users/runner/work/tofnd/tofnd/target/release/tofnd" "./tofndbin/tofnd-$OS-$ARCH-$SEMVER" fi - - name: build linux binaries + - name: Build Linux binaries env: SEMVER: ${{ github.event.inputs.tag }} if: matrix.os == 'ubuntu-latest' @@ -147,7 +149,7 @@ jobs: steps: - name: Checkout code for docker image build - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: '0' ref: ${{ github.event.inputs.tag }} diff --git a/.github/workflows/build-latest-docker-image.yaml b/.github/workflows/build-latest-docker-image.yaml index dd9b8d55..3d8715b3 100644 --- a/.github/workflows/build-latest-docker-image.yaml +++ b/.github/workflows/build-latest-docker-image.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout code and submodule - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive diff --git a/.github/workflows/format.yaml b/.github/workflows/format.yaml index 94b148e6..ef560801 100644 --- a/.github/workflows/format.yaml +++ b/.github/workflows/format.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive @@ -21,7 +21,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: 1.78.0 override: true components: rustfmt, clippy diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 35765d74..abe81278 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout code and submodule - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive @@ -21,16 +21,10 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: 1.78.0 override: true components: rustfmt, clippy - - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all-targets -- -D warnings - - name: Run cargo clippy with all features uses: actions-rs/cargo@v1 with: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0dd02c8c..c1b19ad7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3.0.1 + uses: actions/checkout@v4 with: fetch-depth: '0' submodules: recursive diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 20ef0323..2307cd81 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout code and submodule - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive @@ -21,7 +21,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: 1.78.0 override: true - name: Run cargo test diff --git a/install-gmp-arm64.sh b/install-gmp-arm64.sh deleted file mode 100755 index 2b3a497c..00000000 --- a/install-gmp-arm64.sh +++ /dev/null @@ -1,6 +0,0 @@ -#! /bin/bash - -export HOMEBREW_NO_INSTALL_CLEANUP=TRUE -brew uninstall --ignore-dependencies gmp -ARM_DEPENDENCY=$(brew fetch --force --bottle-tag=arm64_big_sur gmp | grep Downloaded | awk '{print $3}') -brew install "$ARM_DEPENDENCY" \ No newline at end of file From 0d977eea8f897411fd15df08f2c672554266a9b5 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 18:56:40 -0400 Subject: [PATCH 03/15] remove safe prime config --- Dockerfile | 1 - README.md | 10 +++------- docker-compose.test.yml | 2 -- entrypoint.sh | 8 +++----- src/config/mod.rs | 14 -------------- src/main.rs | 10 ---------- src/tests/tofnd_party.rs | 1 - 7 files changed, 6 insertions(+), 40 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6b8871ba..997584b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,7 +43,6 @@ COPY ./entrypoint.sh / VOLUME [ "/.tofnd" ] -ENV UNSAFE "" ENV MNEMONIC_CMD "" ENV NOPASSWORD "" ENV TOFND_HOME "" diff --git a/README.md b/README.md index a653edff..acce6f5a 100644 --- a/README.md +++ b/README.md @@ -71,11 +71,9 @@ Users can specify: 1. Tofnd's root folder. Use `--directory` or `-d` to specify a full or a relative path. If no argument is provided, then the environment variable `TOFND_HOME` is used. If no environment variable is set either, the default `./tofnd` directory is used. 2. The port number of the gRPC server (default is 50051). -3. The option to run in _unsafe_ mode. By default, this option is off, and safe primes are used for keygen. Use the `--unsafe` flag only for testing. -4. `mnemonic` operations for their `tofnd` instance (default is `Existing`). +3. `mnemonic` operations for their `tofnd` instance (default is `Existing`). For more information, see on mnemonic options, see [Mnemonic](#mnemonic). -5. The option to run in _unsafe_ mode. By default, this option is off, and safe primes are used for keygen. **Attention: Use the `--unsafe` flag only for testing**. -6. By default, `tofnd` expects a password from the standard input. Users that don't want to use passwords can use the `--no-password` flag. **Attention: Use `--no-password` only for testing .** +4. By default, `tofnd` expects a password from the standard input. Users that don't want to use passwords can use the `--no-password` flag. **Attention: Use `--no-password` only for testing .** ```text A cryptographic signing service @@ -86,8 +84,6 @@ USAGE: FLAGS: --no-password Skip providing a password. Disabled by default. **Important note** If --no-password is set, the a default (and public) password is used to encrypt. - --unsafe Use unsafe primes. Deactivated by default. **Important note** This option should only be used - for testing. -h, --help Prints help information -V, --version Prints version information @@ -127,7 +123,7 @@ docker volume rm tofnd_tofnd ### Testing -For testing purposes, `docker-compose.test.yml` is available, which is equivelent to `./tofnd --no-password --unsafe`. To spin up a test `tofnd` container, run +For testing purposes, `docker-compose.test.yml` is available, which is equivelent to `./tofnd --no-password`. To spin up a test `tofnd` container, run ```bash docker-compose -f docker-compose.test.yml up diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 6db3f9af..25464c95 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -15,8 +15,6 @@ services: volumes: - tofnd:/.tofnd environment: - # Attention! Use UNSAFE=true only for testing - - UNSAFE=true - NOPASSWORD=true - MNEMONIC_CMD=auto - TOFND_HOME=.tofnd diff --git a/entrypoint.sh b/entrypoint.sh index 7fe54379..c29f7d83 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -35,10 +35,10 @@ import_mnemonic() { if [ -n "${NOPASSWORD}" ]; then \ echo "No password" - (cat $IMPORT_PATH | tofnd ${ARGS} -m import) || return $ERR + ( cat $IMPORT_PATH | tofnd ${ARGS} -m import ) || return $ERR else echo "With password" - ((echo $PASSWORD && cat $IMPORT_PATH) | tofnd ${ARGS} -m import) || return $ERR + ( (echo $PASSWORD && cat $IMPORT_PATH) | tofnd ${ARGS} -m import ) || return $ERR fi echo "... ok" @@ -66,10 +66,8 @@ echo "Using tofnd root:" $TOFND_HOME # gather user's args -# add '--no-password' and '--unsafe' flags to args if enabled +# add '--no-password' flag to args if enabled ARGS=${NOPASSWORD:+"--no-password"} -# add '--unsafe' flag to args if enabled -ARGS+=${UNSAFE:+" --unsafe"} # add '--address' flag to args if enabled ARGS+=${ADDRESS:+" --address ${ADDRESS}"} # add '--port' flag to args if enabled diff --git a/src/config/mod.rs b/src/config/mod.rs index 63dae8bc..f73344ff 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -26,7 +26,6 @@ fn default_tofnd_dir() -> TofndResult { pub struct Config { pub ip: String, pub port: u16, - pub safe_keygen: bool, pub mnemonic_cmd: Cmd, pub tofnd_path: PathBuf, pub password_method: PasswordMethod, @@ -58,17 +57,6 @@ pub fn parse_args() -> TofndResult { .required(false) .default_value(port), ) - .arg( - // TODO: change to something like `--unsafe-primes` - Arg::new("unsafe") - .help( - "Use unsafe primes for generation of Pailler encryption keys. (default: deactivated) **Security warning:** This option is intented for use only in tests. Do not use this option to secure real value.", - ) - .long("unsafe") - .required(false) - .takes_value(false) - .display_order(0), - ) .arg( Arg::new("no-password") .help( @@ -106,7 +94,6 @@ pub fn parse_args() -> TofndResult { .value_of("port") .ok_or_else(|| anyhow!("port value"))? .parse::()?; - let safe_keygen = !matches.is_present("unsafe"); let mnemonic_cmd = matches .value_of("mnemonic") .ok_or_else(|| anyhow!("cmd value"))? @@ -124,7 +111,6 @@ pub fn parse_args() -> TofndResult { Ok(Config { ip, port, - safe_keygen, mnemonic_cmd, tofnd_path, password_method, diff --git a/src/main.rs b/src/main.rs index 2f07de67..86f15870 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,11 +35,6 @@ fn set_up_logs() { .init(); } -fn warn_for_unsafe_execution() { - use tracing::warn; - warn!("WARNING: THIS tofnd BINARY IS NOT SAFE: SAFE PRIMES ARE NOT USED BECAUSE '--unsafe' FLAG IS ENABLED. USE '--unsafe' FLAG ONLY FOR TESTING."); -} - /// worker_threads defaults to the number of cpus on the system /// https://docs.rs/tokio/1.2.0/tokio/attr.main.html#multi-threaded-runtime #[tokio::main(flavor = "multi_thread")] @@ -51,11 +46,6 @@ async fn main() -> TofndResult<()> { // immediately read an encryption password from stdin let password = cfg.password_method.execute()?; - // print config warnings - if !cfg.safe_keygen { - warn_for_unsafe_execution(); - } - // set up span for logs let main_span = span!(Level::INFO, "main"); let _enter = main_span.enter(); diff --git a/src/tests/tofnd_party.rs b/src/tests/tofnd_party.rs index c5f03235..59ed9fe7 100644 --- a/src/tests/tofnd_party.rs +++ b/src/tests/tofnd_party.rs @@ -48,7 +48,6 @@ impl TofndParty { mnemonic_cmd, ip: server_ip.to_string(), port: server_port, - safe_keygen: false, tofnd_path, password_method: PasswordMethod::NoPassword, }; From 36ddc40bc141e68f0fbff3b8cd96f8cd19bb1efe Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 19:14:25 -0400 Subject: [PATCH 04/15] remove gg20 types --- src/gg20/types.rs | 101 ---------------------------------------------- 1 file changed, 101 deletions(-) delete mode 100644 src/gg20/types.rs diff --git a/src/gg20/types.rs b/src/gg20/types.rs deleted file mode 100644 index 977078a1..00000000 --- a/src/gg20/types.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Helper structs and implementations for [crate::gg20]. - -// zeroize Entropy and Password -use zeroize::Zeroize; - -use tracing::{info, span, Level, Span}; - -pub(super) type MessageDigest = tofn::gg20::sign::MessageDigest; - -/// Mnemonic type needs to be known globaly to create/access the mnemonic kv store -#[derive(Zeroize, Debug, Clone, Serialize, Deserialize)] -#[zeroize(drop)] -pub struct Entropy(pub Vec); - -#[derive(Zeroize, Clone)] -#[zeroize(drop)] -pub struct Password(pub String); - -use tokio::sync::mpsc; -/// define the input and output channels of generic execute_protocol worker -pub(super) struct ProtocolCommunication { - pub(super) receiver: mpsc::UnboundedReceiver, - pub(super) sender: mpsc::UnboundedSender, -} -impl ProtocolCommunication { - pub fn new( - receiver: mpsc::UnboundedReceiver, - sender: mpsc::UnboundedSender, - ) -> Self { - Self { receiver, sender } - } -} - -use serde::{Deserialize, Serialize}; -use tofn::gg20::keygen::{GroupPublicInfo, SecretKeyShare, ShareSecretInfo}; - -/// Struct to hold `tonfd` info. This consists of information we need to -/// store in the KV store that is not relevant to `tofn` -#[derive(Debug, Clone, Serialize, Deserialize)] -pub(super) struct TofndInfo { - pub(super) party_uids: Vec, - pub(super) share_counts: Vec, - pub(super) index: usize, -} - -/// `KeyShareKv` record -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PartyInfo { - pub(super) common: GroupPublicInfo, - pub(super) shares: Vec, - pub(super) tofnd: TofndInfo, -} - -impl PartyInfo { - /// Get GroupPublicInfo and ShareSecretInfo from tofn to create PartyInfo - /// Also needed in recovery - pub(super) fn get_party_info( - secret_key_shares: Vec, - uids: Vec, - share_counts: Vec, - tofnd_index: usize, - ) -> Self { - // grap the first share to acquire common data - let common = secret_key_shares[0].group().clone(); - - // aggregate share data into a vector - let shares = secret_key_shares - .into_iter() - .map(|share| share.share().clone()) - .collect(); - - // add tofnd data - let tofnd = TofndInfo { - party_uids: uids, - share_counts, - index: tofnd_index, - }; - - PartyInfo { - common, - shares, - tofnd, - } - } - - /// log PartyInfo state - pub(super) fn log_info(&self, session_id: &str, sign_span: Span) { - let init_span = span!(parent: &sign_span, Level::INFO, "init"); - let _enter = init_span.enter(); - - info!( - "[uid:{}, shares:{}] starting Sign with [key: {}, (t,n)=({},{}), participants:{:?}", - self.tofnd.party_uids[self.tofnd.index], - self.tofnd.share_counts[self.tofnd.index], - session_id, - self.common.threshold(), - self.tofnd.share_counts.iter().sum::(), - self.tofnd.party_uids, - ); - } -} From 13eaaa5d492fe7c9f04d1360fa0e43b6e3bec329 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Sat, 6 Jul 2024 19:36:16 -0400 Subject: [PATCH 05/15] update protobufs --- build.rs | 2 +- proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index ef673d86..7986f24e 100644 --- a/build.rs +++ b/build.rs @@ -6,6 +6,6 @@ fn main() -> Result<(), Box> { tonic_build::configure() // .build_client(false) // .out_dir(".") // if you want to peek at the generated code - .compile(&["proto/grpc.proto", "proto/multisig.proto"], &["proto"])?; + .compile(&["proto/multisig.proto"], &["proto"])?; Ok(()) } diff --git a/proto b/proto index 5fa83fe0..637f89c2 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 5fa83fe0dbe1463f756348fa48116c7b69564a2f +Subproject commit 637f89c26fc7fadb746eaa3674dbfcd434c71bab From 86404333db1e8be49754e43266b0801f4c9f0cfa Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Mon, 8 Jul 2024 17:03:45 -0400 Subject: [PATCH 06/15] update submodule --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index 637f89c2..549f6f8a 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 637f89c26fc7fadb746eaa3674dbfcd434c71bab +Subproject commit 549f6f8a783b586291df82f1c7b14eacaf66014a From 8abe22040dd10f9c23625d759074015c83ceef93 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 18:52:39 -0400 Subject: [PATCH 07/15] update dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 997584b9..03f706e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM rust:1.73.0-bullseye as builder +FROM rust:1.78.0-bullseye as builder RUN set -ex \ && apt-get update \ From df6ea6e71d9e65f3e74c81157cb2e8c997ed7d8e Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 19:13:46 -0400 Subject: [PATCH 08/15] update edition --- Cargo.lock | 287 +++++++++++++++++------------------------------------ Cargo.toml | 9 +- 2 files changed, 97 insertions(+), 199 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca65d873..c1f5f930 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,6 +224,12 @@ dependencies = [ "rustc-demangle", ] +[[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.0" @@ -257,7 +263,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", "generic-array", ] @@ -270,12 +275,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "blocking" version = "0.4.7" @@ -312,9 +311,9 @@ checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -445,41 +444,33 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.2.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "cfg-if 1.0.0", "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-bigint" -version = "0.2.5" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -507,16 +498,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curve25519-dalek" version = "4.0.0" @@ -565,12 +546,6 @@ dependencies = [ "libc", ] -[[package]] -name = "der" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2" - [[package]] name = "der" version = "0.7.8" @@ -609,6 +584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] @@ -635,14 +611,15 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.12.4" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der 0.4.4", + "der", + "digest 0.10.7", "elliptic-curve", - "hmac 0.11.0", - "signature 1.3.2", + "rfc6979", + "signature", ] [[package]] @@ -652,21 +629,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" dependencies = [ "pkcs8", - "signature 2.0.0", + "signature", ] [[package]] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", "rand_core 0.6.4", "serde", - "sha2 0.10.7", - "signature 2.0.0", + "sha2 0.10.8", + "signature", + "subtle", "zeroize", ] @@ -678,15 +656,18 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "elliptic-curve" -version = "0.10.4" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ + "base16ct", "crypto-bigint", + "digest 0.10.7", "ff", "generic-array", "group", "rand_core 0.6.4", + "sec1", "subtle", "zeroize", ] @@ -708,9 +689,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.10.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core 0.6.4", "subtle", @@ -867,12 +848,13 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -913,9 +895,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "group" -version = "0.10.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", @@ -1084,29 +1066,13 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "hmac" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - -[[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", + "crypto-mac", "digest 0.9.0", ] @@ -1254,21 +1220,16 @@ dependencies = [ [[package]] name = "k256" -version = "0.9.5" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b0281ca8032567c9711cd48631781c15228301860a39b32deb28d63125e46" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if 1.0.0", "ecdsa", "elliptic-curve", + "sha2 0.10.8", ] -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" - [[package]] name = "lazy_static" version = "1.4.0" @@ -1281,24 +1242,11 @@ version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" -[[package]] -name = "libpaillier" -version = "0.2.1" -source = "git+https://github.com/axelarnetwork/paillier-rs#2d965b16d89de6f5d15b054fd5874d0c017c4747" -dependencies = [ - "digest 0.9.0", - "rand 0.8.4", - "serde", - "serde_bare", - "unknown_order", - "zeroize", -] - [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -1348,15 +1296,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" -[[package]] -name = "memoffset" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" -dependencies = [ - "autocfg", -] - [[package]] name = "miniz_oxide" version = "0.4.4" @@ -1436,7 +1375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -1447,16 +1386,7 @@ checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -1505,7 +1435,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" dependencies = [ - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -1542,9 +1472,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if 1.0.0", "instant", @@ -1571,7 +1501,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" dependencies = [ - "crypto-mac 0.8.0", + "crypto-mac", ] [[package]] @@ -1644,7 +1574,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.8", + "der", "spki", ] @@ -1908,23 +1838,23 @@ dependencies = [ ] [[package]] -name = "rpassword" -version = "5.0.1" +name = "rfc6979" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "libc", - "winapi", + "hmac 0.12.1", + "subtle", ] [[package]] -name = "rust-gmp" -version = "0.5.0" +name = "rpassword" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ddf28998d5730b96a9fe188557953de503d77ff403ae175ad1417921e5d906" +checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" dependencies = [ "libc", - "num-traits 0.1.43", + "winapi", ] [[package]] @@ -1971,9 +1901,9 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scrypt" @@ -1984,7 +1914,20 @@ dependencies = [ "password-hash", "pbkdf2 0.12.2", "salsa20", - "sha2 0.10.7", + "sha2 0.10.8", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", ] [[package]] @@ -2008,15 +1951,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_bare" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adbd09b1e0b45fadbc163e4ea1f4224b451146ba4f01963c69975780c33215fa" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" version = "1.0.130" @@ -2050,18 +1984,18 @@ dependencies = [ "cpufeatures", "digest 0.9.0", "opaque-debug", - "sha2-asm", ] [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", "digest 0.10.7", + "sha2-asm", ] [[package]] @@ -2073,18 +2007,6 @@ dependencies = [ "cc", ] -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] - [[package]] name = "sharded-slab" version = "0.1.4" @@ -2113,16 +2035,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.4", -] - [[package]] name = "signature" version = "2.0.0" @@ -2130,6 +2042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" dependencies = [ "digest 0.10.7", + "rand_core 0.6.4", ] [[package]] @@ -2227,7 +2140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", - "der 0.7.8", + "der", ] [[package]] @@ -2357,22 +2270,21 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tofn" -version = "0.1.0" -source = "git+https://github.com/axelarnetwork/tofn?branch=main#18dc9c3449b6af4fd50c29971d3cd095cd126e41" +version = "0.3.0" +source = "git+https://github.com/axelarnetwork/tofn?branch=update-deps#a469cdd5693f6929f27119150c34f326b345d52b" dependencies = [ "bincode", - "der 0.7.8", + "crypto-bigint", + "der", "ecdsa", "ed25519", "ed25519-dalek", - "hmac 0.11.0", + "hmac 0.12.1", "k256", - "libpaillier", "rand 0.8.4", "rand_chacha 0.3.1", "serde", - "sha2 0.9.8", - "sha3", + "sha2 0.10.8", "tracing", "zeroize", ] @@ -2731,19 +2643,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "unknown_order" -version = "0.2.3" -source = "git+https://github.com/axelarnetwork/unknown_order#0f841f810f8bfe440d7768501da186b2426b7afa" -dependencies = [ - "digest 0.9.0", - "hex", - "rand 0.8.4", - "rust-gmp", - "serde", - "zeroize", -] - [[package]] name = "uom" version = "0.30.0" @@ -2751,7 +2650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e76503e636584f1e10b9b3b9498538279561adcef5412927ba00c2b32c4ce5ed" dependencies = [ "num-rational", - "num-traits 0.2.14", + "num-traits", "typenum", ] @@ -2949,9 +2848,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zeroize" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 70b5eeb2..4ab2d905 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,14 +2,12 @@ name = "tofnd" version = "0.11.0" authors = ["Gus Gutoski ", "Stelios Daveas "] -edition = "2018" +edition = "2021" license = "MIT OR Apache-2.0" [dependencies] tonic = "0.6" -tofn = { git = "https://github.com/axelarnetwork/tofn", branch = "main"} -# tofn = { path = "../tofn" } -sled = {version = "0.34", default-features = false} +tofn = { git = "https://github.com/axelarnetwork/tofn", branch = "update-deps"} # logging log = {version = "0.4",default-features = false } @@ -21,6 +19,7 @@ atty = {version = "0.2", default-features = false} clap = {version = "3.0", default-features = false, features = ["std", "cargo", "env"]} # sled dependency +sled = {version = "0.34", default-features = false} serde = { version = "1.0", features = ["derive"], default-features = false } # sled encryption chacha20poly1305 = { version = "0.9", features = ["alloc"], default-features = false } @@ -37,7 +36,7 @@ futures-util = {version = "0.3", default-features = false} # mnemonic tiny-bip39 = { version = "0.8.2", default-features = false} -zeroize = { version = "1.4", features = ["zeroize_derive"], default-features = false} +zeroize = { version = "1.8", features = ["zeroize_derive"], default-features = false} #error handling thiserror = { version = "1.0", default-features = false } From 8b635598c30f5fddf745de6c8dea243524c074d4 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 19:13:54 -0400 Subject: [PATCH 09/15] change imports --- Cargo.lock | 51 ++++++++++++++++--------------------- src/mnemonic/cmd_handler.rs | 5 +--- src/multisig/keypair.rs | 2 +- src/multisig/sign.rs | 2 +- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1f5f930..6e2d957e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation" @@ -500,16 +500,15 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if 1.0.0", "cpufeatures", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "platforms 3.0.2", "rustc_version", "subtle", "zeroize", @@ -517,9 +516,9 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", @@ -548,9 +547,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "der_derive", @@ -624,9 +623,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", @@ -699,9 +698,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.1.20" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fixedbitset" @@ -1001,7 +1000,7 @@ dependencies = [ "log", "mach", "ntapi", - "platforms 0.2.1", + "platforms", "winapi", ] @@ -1584,12 +1583,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e" -[[package]] -name = "platforms" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" - [[package]] name = "polling" version = "2.1.0" @@ -1932,9 +1925,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "semver-parser" @@ -2000,9 +1993,9 @@ dependencies = [ [[package]] name = "sha2-asm" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea" +checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" dependencies = [ "cc", ] @@ -2037,9 +2030,9 @@ dependencies = [ [[package]] name = "signature" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -2135,9 +2128,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -2271,7 +2264,7 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tofn" version = "0.3.0" -source = "git+https://github.com/axelarnetwork/tofn?branch=update-deps#a469cdd5693f6929f27119150c34f326b345d52b" +source = "git+https://github.com/axelarnetwork/tofn?branch=update-deps#ce461b8d02aedac378a9bea31b1ee5585056d1cd" dependencies = [ "bincode", "crypto-bigint", diff --git a/src/mnemonic/cmd_handler.rs b/src/mnemonic/cmd_handler.rs index d82bedd8..da5f7dd8 100644 --- a/src/mnemonic/cmd_handler.rs +++ b/src/mnemonic/cmd_handler.rs @@ -11,10 +11,7 @@ use crate::kv_manager::{ error::{InnerKvError, KvError}, KeyReservation, KvManager, }; -use tofn::{ - gg20::keygen::SecretRecoveryKey, - sdk::api::{deserialize, serialize}, -}; +use tofn::sdk::api::{deserialize, serialize, SecretRecoveryKey}; use rpassword::read_password; use std::convert::TryInto; diff --git a/src/multisig/keypair.rs b/src/multisig/keypair.rs index 39bcd5cb..e407665d 100644 --- a/src/multisig/keypair.rs +++ b/src/multisig/keypair.rs @@ -2,7 +2,7 @@ use crate::{proto::Algorithm, TofndResult}; use anyhow::anyhow; use tofn::{ ecdsa, ed25519, - multisig::{keygen::SecretRecoveryKey, sign::MessageDigest}, + sdk::api::{MessageDigest, SecretRecoveryKey}, }; pub enum KeyPair { diff --git a/src/multisig/sign.rs b/src/multisig/sign.rs index d56d39a8..46f486d5 100644 --- a/src/multisig/sign.rs +++ b/src/multisig/sign.rs @@ -5,7 +5,7 @@ use crate::{ }; use anyhow::anyhow; use std::convert::TryInto; -use tofn::multisig::keygen::SecretRecoveryKey; +use tofn::sdk::api::SecretRecoveryKey; impl MultisigService { pub(super) async fn handle_sign(&self, request: &SignRequest) -> TofndResult> { From 9f446ef8a1002dbeed580210d19ea806d61ac3d5 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 20:46:57 -0400 Subject: [PATCH 10/15] update clap --- Cargo.lock | 26 ++++++++++++++++---------- Cargo.toml | 2 +- src/config/mod.rs | 26 ++++++++++++-------------- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e2d957e..26274350 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -391,17 +391,26 @@ dependencies = [ [[package]] name = "clap" -version = "3.0.5" +version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f34b09b9ee8c7c7b400fe2f8df39cafc9538b03d6ba7f4ae13e4cb90bfbb7d" +checksum = "8e538f9ee5aa3b3963f09a997035f883677966ed50fce0292611927ce6f6d8c6" dependencies = [ "bitflags", + "clap_lex", "indexmap", "lazy_static", - "os_str_bytes", "textwrap", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -1439,12 +1448,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.0.0" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "parking" @@ -2194,9 +2200,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.14.2" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" [[package]] name = "thiserror" diff --git a/Cargo.toml b/Cargo.toml index 4ab2d905..bfd5cf3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ tracing-subscriber= {version = "0.3", features = ["json", "env-filter"]} atty = {version = "0.2", default-features = false} # config -clap = {version = "3.0", default-features = false, features = ["std", "cargo", "env"]} +clap = {version = "3.2", default-features = false, features = ["std", "cargo", "env"]} # sled dependency sled = {version = "0.34", default-features = false} diff --git a/src/config/mod.rs b/src/config/mod.rs index f73344ff..3c6d4900 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use clap::{crate_version, App, Arg}; +use clap::{builder::PossibleValuesParser, crate_version, Arg, Command}; // error handling use crate::{encrypted_sled::PasswordMethod, mnemonic::Cmd, TofndResult}; @@ -40,7 +40,7 @@ pub fn parse_args() -> TofndResult { .to_str() .ok_or_else(|| anyhow!("can't convert default dir to str"))?; - let app = App::new("tofnd") + let app = Command::new("tofnd") .about("A cryptographic signing service") .version(crate_version!()) .arg( @@ -73,7 +73,8 @@ pub fn parse_args() -> TofndResult { .short('m') .required(false) .default_value(DEFAULT_MNEMONIC_CMD) - .possible_values(AVAILABLE_MNEMONIC_CMDS), + .value_parser(PossibleValuesParser::new(AVAILABLE_MNEMONIC_CMDS)) + .takes_value(true), ) .arg( Arg::new("directory") @@ -87,23 +88,20 @@ pub fn parse_args() -> TofndResult { let matches = app.get_matches(); let ip = matches - .value_of("ip") - .ok_or_else(|| anyhow!("ip value"))? - .to_string(); + .get_one::("ip") + .ok_or_else(|| anyhow!("ip value"))?.clone(); let port = matches - .value_of("port") + .get_one::("port") .ok_or_else(|| anyhow!("port value"))? .parse::()?; - let mnemonic_cmd = matches - .value_of("mnemonic") - .ok_or_else(|| anyhow!("cmd value"))? - .to_string(); - let mnemonic_cmd = Cmd::from_string(&mnemonic_cmd)?; + let mnemonic_cmd = Cmd::from_string(matches + .get_one::("mnemonic") + .ok_or_else(|| anyhow!("cmd value"))?)?; let tofnd_path = matches - .value_of("directory") + .get_one::("directory") .ok_or_else(|| anyhow!("directory value"))? .into(); - let password_method = match matches.is_present("no-password") { + let password_method = match matches.contains_id("no-password") { true => PasswordMethod::NoPassword, false => PasswordMethod::Prompt, }; From 478dee4f5ab9d41e091ae7898f295ebf96f23370 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Sat, 6 Jul 2024 19:34:20 -0400 Subject: [PATCH 11/15] update deps --- Cargo.lock | 1593 +++++++++++----------------------- Cargo.toml | 55 +- README.md | 5 +- build.rs | 5 +- src/config/mod.rs | 11 +- src/encrypted_sled/kv.rs | 2 +- src/encrypted_sled/tests.rs | 4 +- src/main.rs | 8 +- src/multisig/key_presence.rs | 9 +- src/multisig/keygen.rs | 9 +- src/multisig/keypair.rs | 15 +- src/multisig/service.rs | 10 +- src/multisig/sign.rs | 16 +- src/multisig/tests.rs | 5 +- src/tests/tofnd_party.rs | 8 +- 15 files changed, 613 insertions(+), 1142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26274350..3a276bb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,18 +19,19 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ + "crypto-common", "generic-array", ] [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -46,152 +47,43 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" - -[[package]] -name = "async-channel" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task 4.0.3", - "concurrent-queue", - "fastrand", - "futures-lite 1.12.0", - "once_cell", - "slab", -] - -[[package]] -name = "async-fs" -version = "1.5.0" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3ca4f8ff117c37c278a2f7415ce9be55560b846b5bc4412aaa5d29c1c3dae2" -dependencies = [ - "async-lock", - "blocking 1.0.2", - "futures-lite 1.12.0", -] - -[[package]] -name = "async-io" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" -dependencies = [ - "concurrent-queue", - "futures-lite 1.12.0", - "libc", - "log", - "once_cell", - "parking 2.0.0", - "polling", - "slab", - "socket2 0.4.2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-net" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5373304df79b9b4395068fb080369ec7178608827306ce4d081cba51cac551df" -dependencies = [ - "async-io", - "blocking 1.0.2", - "futures-lite 1.12.0", -] - -[[package]] -name = "async-process" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b21b63ab5a0db0369deb913540af2892750e42d949faacc7a61495ac418a1692" -dependencies = [ - "async-io", - "blocking 1.0.2", - "cfg-if 1.0.0", - "event-listener", - "futures-lite 1.12.0", - "libc", - "once_cell", - "signal-hook", - "winapi", -] +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "async-stream" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite", ] [[package]] name = "async-stream-impl" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 2.0.32", ] -[[package]] -name = "async-task" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" - -[[package]] -name = "async-task" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" - [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 2.0.32", ] -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - [[package]] name = "atty" version = "0.2.14" @@ -217,7 +109,7 @@ checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -232,9 +124,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64ct" @@ -258,13 +150,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "block-buffer" -version = "0.9.0" +name = "bitflags" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -275,34 +164,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blocking" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2468ff7bf85066b4a3678fede6fe66db31846d753ff0adfbfab2c6a6e81612b" -dependencies = [ - "async-channel", - "atomic-waker", - "futures-lite 0.1.11", - "once_cell", - "parking 1.0.6", - "waker-fn", -] - -[[package]] -name = "blocking" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" -dependencies = [ - "async-channel", - "async-task 4.0.3", - "atomic-waker", - "fastrand", - "futures-lite 1.12.0", - "once_cell", -] - [[package]] name = "bumpalo" version = "3.8.0" @@ -322,22 +183,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] -name = "cache-padded" -version = "1.1.1" +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +dependencies = [ + "serde", +] [[package]] -name = "cc" -version = "1.0.71" +name = "cargo_metadata" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] [[package]] -name = "cfg-if" -version = "0.1.10" +name = "cc" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" [[package]] name = "cfg-if" @@ -347,38 +227,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if 1.0.0", - "cipher 0.3.0", + "cfg-if", + "cipher", "cpufeatures", - "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", - "cipher 0.3.0", + "cipher", "poly1305", "zeroize", ] -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.4.4" @@ -387,6 +257,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -395,9 +266,9 @@ version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e538f9ee5aa3b3963f09a997035f883677966ed50fce0292611927ce6f6d8c6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_lex", - "indexmap", + "indexmap 1.7.0", "lazy_static", "textwrap", ] @@ -411,31 +282,12 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "core-foundation" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -457,7 +309,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -482,7 +334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -497,26 +349,16 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest 0.10.7", + "digest", "fiat-crypto", "rustc_version", "subtle", @@ -531,27 +373,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", -] - -[[package]] -name = "darwin-libproc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb90051930c9a0f09e585762152048e23ac74d20c10590ef7cf01c0343c3046" -dependencies = [ - "darwin-libproc-sys", - "libc", - "memchr", -] - -[[package]] -name = "darwin-libproc-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cebb5bde66eecdd30ddc4b9cd208238b15db4982ccc72db59d699ea10867c1" -dependencies = [ - "libc", + "syn 2.0.32", ] [[package]] @@ -573,16 +395,7 @@ checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", + "syn 2.0.32", ] [[package]] @@ -591,7 +404,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", "crypto-common", "subtle", @@ -599,22 +412,23 @@ dependencies = [ [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -624,7 +438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest 0.10.7", + "digest", "elliptic-curve", "rfc6979", "signature", @@ -648,9 +462,9 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.6.4", + "rand_core", "serde", - "sha2 0.10.8", + "sha2", "signature", "subtle", "zeroize", @@ -670,29 +484,30 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.7", + "digest", "ff", "generic-array", "group", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", ] [[package]] -name = "event-listener" -version = "2.5.1" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "fastrand" -version = "1.5.0" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "instant", + "libc", + "windows-sys 0.52.0", ] [[package]] @@ -701,7 +516,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -723,16 +538,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - [[package]] name = "fs2" version = "0.4.3" @@ -743,20 +548,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "futures" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.17" @@ -764,7 +555,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -773,47 +563,11 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" -[[package]] -name = "futures-io" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" - -[[package]] -name = "futures-lite" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97999970129b808f0ccba93211201d431fcc12d7e1ffae03a61b5cedd1a7ced2" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking 2.0.0", - "pin-project-lite 0.1.12", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking 2.0.0", - "pin-project-lite 0.2.7", - "waker-fn", -] - [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" @@ -821,12 +575,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" -[[package]] -name = "futures-timer" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" - [[package]] name = "futures-util" version = "0.3.17" @@ -834,15 +582,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg", - "futures-channel", "futures-core", - "futures-io", - "futures-sink", "futures-task", - "memchr", - "pin-project-lite 0.2.7", + "pin-project-lite", "pin-utils", - "slab", ] [[package]] @@ -865,26 +608,13 @@ dependencies = [ "zeroize", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - [[package]] name = "getrandom" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] @@ -895,12 +625,6 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - [[package]] name = "group" version = "0.13.0" @@ -908,15 +632,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] [[package]] name = "h2" -version = "0.3.7" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -924,10 +648,10 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.2.6", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.11", "tracing", ] @@ -937,6 +661,12 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.3.3" @@ -946,125 +676,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "heim" -version = "0.1.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1014732324a9baf5a691525faabb33909bf6f40dcc2b03c8f2fb07bb01e7e3f" -dependencies = [ - "heim-common", - "heim-process", - "heim-runtime", -] - -[[package]] -name = "heim-common" -version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767e6e47cf88abe7c9a5ebb4df82f180d30d9c0ba0269b6d166482461765834" -dependencies = [ - "cfg-if 1.0.0", - "core-foundation", - "futures-core", - "futures-util", - "lazy_static", - "libc", - "mach", - "nix 0.19.1", - "pin-utils", - "uom", - "winapi", -] - -[[package]] -name = "heim-cpu" -version = "0.1.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b1442359831aa671aa931f0a084aab210e77b1330ded78f1e60cc305abc4bb" -dependencies = [ - "cfg-if 0.1.10", - "futures", - "glob", - "heim-common", - "heim-runtime", - "lazy_static", - "libc", - "mach", - "ntapi", - "smol 0.1.18", - "winapi", -] - -[[package]] -name = "heim-host" -version = "0.1.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cce3ce658bd45e510ff0a2fb5c668cbe1a7368929fd1db123741c99fd6902e" -dependencies = [ - "cfg-if 0.1.10", - "heim-common", - "heim-runtime", - "lazy_static", - "libc", - "log", - "mach", - "ntapi", - "platforms", - "winapi", -] - -[[package]] -name = "heim-net" -version = "0.1.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59da1108e732afcda77e1429b5d0ce648b9a31d1f8cf385108b83bea4cf91342" -dependencies = [ - "bitflags", - "cfg-if 0.1.10", - "heim-common", - "heim-runtime", - "libc", - "macaddr", - "nix 0.17.0", -] - -[[package]] -name = "heim-process" -version = "0.1.1-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd969deb2a89a488b6a9bf18a65923ae4cdef6b128fa2dedb74ef5c694deb5ae" -dependencies = [ - "async-trait", - "cfg-if 0.1.10", - "darwin-libproc", - "futures", - "heim-common", - "heim-cpu", - "heim-host", - "heim-net", - "heim-runtime", - "lazy_static", - "libc", - "mach", - "memchr", - "ntapi", - "ordered-float", - "smol 0.1.18", - "winapi", -] - -[[package]] -name = "heim-runtime" -version = "0.1.0-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "906dd26ed2eb6b9f5f0dc3dfc04caeb82785ccc05a3b3326e4c841613451acc7" -dependencies = [ - "futures", - "futures-timer", - "smol 0.1.18", - "version-sync", -] - [[package]] name = "hermit-abi" version = "0.1.19" @@ -1076,62 +687,61 @@ dependencies = [ [[package]] name = "hmac" -version = "0.8.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "crypto-mac", - "digest 0.9.0", + "digest", ] [[package]] -name = "hmac" -version = "0.12.1" +name = "home" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "digest 0.10.7", + "windows-sys 0.52.0", ] [[package]] name = "http" -version = "0.2.5" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 1.0.11", ] [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.7", + "pin-project-lite", ] [[package]] name = "httparse" -version = "1.5.1" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.14" +version = "0.14.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" dependencies = [ "bytes", "futures-channel", @@ -1142,9 +752,9 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", - "pin-project-lite 0.2.7", - "socket2 0.4.2", + "itoa 1.0.11", + "pin-project-lite", + "socket2", "tokio", "tower-service", "tracing", @@ -1158,30 +768,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ "hyper", - "pin-project-lite 0.2.7", + "pin-project-lite", "tokio", "tokio-io-timeout", ] [[package]] -name = "idna" -version = "0.2.3" +name = "indexmap" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", + "autocfg", + "hashbrown 0.11.2", ] [[package]] name = "indexmap" -version = "1.7.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "autocfg", - "hashbrown", + "equivalent", + "hashbrown 0.14.5", ] [[package]] @@ -1199,7 +808,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1217,6 +826,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.55" @@ -1232,55 +847,56 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", - "sha2 0.10.8", + "sha2", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.105" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] -name = "lock_api" -version = "0.4.6" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "scopeguard", + "bitflags 2.6.0", + "libc", ] [[package]] -name = "log" +name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] -name = "macaddr" -version = "1.0.1" +name = "lock_api" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baee0bbc17ce759db233beb01648088061bf678383130602a298e6998eedb2d8" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] [[package]] -name = "mach" -version = "0.3.2" +name = "log" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "libc", + "cfg-if", ] [[package]] @@ -1292,12 +908,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "memchr" version = "2.4.1" @@ -1316,24 +926,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.14" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", ] [[package]] @@ -1342,70 +941,15 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "nix" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" -dependencies = [ - "bitflags", - "cc", - "cfg-if 0.1.10", - "libc", - "void", -] - -[[package]] -name = "nix" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" -dependencies = [ - "bitflags", - "cc", - "cfg-if 1.0.0", - "libc", -] - [[package]] name = "ntapi" -version = "0.3.6" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ "winapi", ] -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - [[package]] name = "num_cpus" version = "1.13.0" @@ -1427,9 +971,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -1438,13 +982,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "ordered-float" -version = "1.0.2" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" -dependencies = [ - "num-traits", -] +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "os_str_bytes" @@ -1452,18 +993,6 @@ version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" -[[package]] -name = "parking" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c" - -[[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - [[package]] name = "parking_lot" version = "0.11.2" @@ -1481,7 +1010,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -1496,17 +1025,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle", ] [[package]] name = "pbkdf2" -version = "0.4.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "crypto-mac", + "digest", ] [[package]] @@ -1515,15 +1044,15 @@ 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", + "digest", + "hmac", ] [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" @@ -1532,40 +1061,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.7.0", ] [[package]] name = "pin-project" -version = "1.0.8" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.8" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 2.0.32", ] [[package]] name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - -[[package]] -name = "pin-project-lite" -version = "0.2.7" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1583,30 +1106,11 @@ dependencies = [ "spki", ] -[[package]] -name = "platforms" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e" - -[[package]] -name = "polling" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug", @@ -1668,7 +1172,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 1.0.80", + "syn 1.0.109", ] [[package]] @@ -1681,17 +1185,6 @@ dependencies = [ "prost", ] -[[package]] -name = "pulldown-cmark" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - [[package]] name = "quote" version = "1.0.32" @@ -1702,84 +1195,33 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "rand_hc 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" +name = "rand" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "getrandom 0.2.3", + "libc", + "rand_chacha", + "rand_core", ] [[package]] -name = "rand_hc" -version = "0.2.0" +name = "rand_chacha" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ - "rand_core 0.5.1", + "ppv-lite86", + "rand_core", ] [[package]] -name = "rand_hc" -version = "0.3.1" +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "rand_core 0.6.4", + "getrandom", ] [[package]] @@ -1788,24 +1230,25 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.3", - "redox_syscall", + "getrandom", + "libredox", + "thiserror", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -1842,18 +1285,29 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac 0.12.1", + "hmac", "subtle", ] [[package]] name = "rpassword" -version = "5.0.1" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", - "winapi", + "rtoolbox", + "windows-sys 0.48.0", +] + +[[package]] +name = "rtoolbox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +dependencies = [ + "libc", + "windows-sys 0.48.0", ] [[package]] @@ -1877,6 +1331,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "ryu" version = "1.0.5" @@ -1889,15 +1356,9 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" dependencies = [ - "cipher 0.4.4", + "cipher", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "scopeguard" version = "1.2.0" @@ -1913,7 +1374,7 @@ dependencies = [ "password-hash", "pbkdf2 0.12.2", "salsa20", - "sha2 0.10.8", + "sha2", ] [[package]] @@ -1931,34 +1392,31 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "semver-parser" -version = "0.9.0" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46e1121e8180c12ff69a742aabc4f310542b6ccb69f1691689ac17fdf8618aa" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] [[package]] name = "serde" -version = "1.0.130" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 2.0.32", ] [[package]] @@ -1967,33 +1425,20 @@ version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ - "itoa", + "itoa 0.4.8", "ryu", "serde", ] -[[package]] -name = "sha2" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", "sha2-asm", ] @@ -2015,16 +1460,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -2040,15 +1475,18 @@ 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", + "digest", + "rand_core", ] [[package]] name = "slab" -version = "0.4.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] [[package]] name = "sled" @@ -2072,64 +1510,14 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" -[[package]] -name = "smol" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5" -dependencies = [ - "async-task 3.0.0", - "blocking 0.4.7", - "concurrent-queue", - "fastrand", - "futures-io", - "futures-util", - "libc", - "once_cell", - "scoped-tls", - "slab", - "socket2 0.3.19", - "wepoll-sys-stjepang", - "winapi", -] - -[[package]] -name = "smol" -version = "1.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cf3b5351f3e783c1d79ab5fc604eeed8b8ae9abd36b166e8b87a089efd85e4" -dependencies = [ - "async-channel", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-net", - "async-process", - "blocking 1.0.2", - "futures-lite 1.12.0", - "once_cell", -] - -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi", -] - [[package]] name = "socket2" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -2150,35 +1538,49 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.80" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] name = "syn" -version = "2.0.28" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sysinfo" +version = "0.26.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c18a6156d1f27a9592ee18c1a846ca8dd5c258b7179fc193ae87c74ebb666f5" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "winapi", +] + [[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "rand 0.8.4", + "rand", "redox_syscall", "remove_dir_all", "winapi", @@ -2186,15 +1588,15 @@ dependencies = [ [[package]] name = "testdir" -version = "0.4.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c13a556e110c7d373db3c12464a80e4d24ed25942381242b17aad43aee98085" +checksum = "ee79e927b64d193f5abb60d20a0eb56be0ee5a242fdeb8ce3bf054177006de52" dependencies = [ "anyhow", "backtrace", - "heim", + "cargo_metadata", "once_cell", - "smol 1.2.5", + "sysinfo", "whoami", ] @@ -2206,22 +1608,22 @@ checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 2.0.32", ] [[package]] @@ -2235,17 +1637,17 @@ dependencies = [ [[package]] name = "tiny-bip39" -version = "0.8.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" dependencies = [ "anyhow", - "hmac 0.8.1", + "hmac", "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", + "pbkdf2 0.11.0", + "rand", "rustc-hash", - "sha2 0.9.8", + "sha2", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -2278,19 +1680,19 @@ dependencies = [ "ecdsa", "ed25519", "ed25519-dalek", - "hmac 0.12.1", + "hmac", "k256", - "rand 0.8.4", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "serde", - "sha2 0.10.8", + "sha2", "tracing", "zeroize", ] [[package]] name = "tofnd" -version = "0.11.0" +version = "1.0.0" dependencies = [ "anyhow", "atty", @@ -2301,7 +1703,7 @@ dependencies = [ "lazy_static", "log", "prost", - "rand 0.8.4", + "rand", "rpassword", "scrypt", "serde", @@ -2322,76 +1724,79 @@ dependencies = [ [[package]] name = "tokio" -version = "1.12.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", "num_cpus", - "once_cell", - "pin-project-lite 0.2.7", + "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "tokio-io-timeout" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90c49f106be240de154571dd31fbe48acb10ba6c6dd6f6517ad603abffa42de9" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" dependencies = [ - "pin-project-lite 0.2.7", + "pin-project-lite", "tokio", ] [[package]] name = "tokio-macros" -version = "1.5.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 2.0.32", ] [[package]] name = "tokio-stream" -version = "0.1.7" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", - "pin-project-lite 0.2.7", + "pin-project-lite", "tokio", ] [[package]] name = "tokio-util" -version = "0.6.8" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ "bytes", "futures-core", "futures-sink", "log", - "pin-project-lite 0.2.7", + "pin-project-lite", "tokio", ] [[package]] -name = "toml" -version = "0.5.8" +name = "tokio-util" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ - "serde", + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", ] [[package]] @@ -2417,7 +1822,7 @@ dependencies = [ "prost-derive", "tokio", "tokio-stream", - "tokio-util", + "tokio-util 0.6.10", "tower", "tower-layer", "tower-service", @@ -2434,25 +1839,24 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 1.0.80", + "syn 1.0.109", ] [[package]] name = "tower" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00e500fff5fa1131c866b246041a6bf96da9c965f8fe4128cb1421f23e93c00" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.7.0", "pin-project", - "pin-project-lite 0.2.7", - "rand 0.8.4", + "pin-project-lite", + "rand", "slab", "tokio", - "tokio-stream", - "tokio-util", + "tokio-util 0.7.11", "tower-layer", "tower-service", "tracing", @@ -2460,47 +1864,48 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", - "pin-project-lite 0.2.7", + "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 2.0.32", ] [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "lazy_static", + "once_cell", + "valuable", ] [[package]] @@ -2575,14 +1980,14 @@ checksum = "4801dca35e4e2cee957c469bd4a1c370fadb7894c0d50721a40eba3523e6e91c" dependencies = [ "lazy_static", "quote", - "syn 1.0.80", + "syn 1.0.109", ] [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -2590,21 +1995,6 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" - [[package]] name = "unicode-ident" version = "1.0.11" @@ -2622,63 +2012,25 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - -[[package]] -name = "unicode-xid" -version = "0.2.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array", + "crypto-common", "subtle", ] [[package]] -name = "uom" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e76503e636584f1e10b9b3b9498538279561adcef5412927ba00c2b32c4ce5ed" -dependencies = [ - "num-rational", - "num-traits", - "typenum", -] - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "version-sync" -version = "0.9.3" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a3e43f07cfb6ad1a7f6fedaf1144e59750b728c04a24a053035379b2e4584d" -dependencies = [ - "proc-macro2", - "pulldown-cmark", - "regex", - "semver-parser", - "syn 1.0.80", - "toml", - "url", -] +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" @@ -2686,39 +2038,26 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" @@ -2726,7 +2065,7 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -2741,7 +2080,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 1.0.80", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -2763,7 +2102,7 @@ checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.80", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2784,33 +2123,16 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - -[[package]] -name = "wepoll-sys-stjepang" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fdfbb03f290ca0b27922e8d48a0997b4ceea12df33269b9f75e713311eb178d" -dependencies = [ - "cc", -] - [[package]] name = "which" -version = "4.2.2" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", - "lazy_static", - "libc", + "home", + "once_cell", + "rustix", ] [[package]] @@ -2845,6 +2167,145 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "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.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "zeroize" version = "1.8.1" @@ -2862,5 +2323,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.32", ] diff --git a/Cargo.toml b/Cargo.toml index bfd5cf3d..64c59953 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,58 +1,59 @@ [package] name = "tofnd" -version = "0.11.0" +version = "1.0.0" authors = ["Gus Gutoski ", "Stelios Daveas "] edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -tonic = "0.6" tofn = { git = "https://github.com/axelarnetwork/tofn", branch = "update-deps"} # logging -log = {version = "0.4",default-features = false } -tracing = {version = "0.1", default-features = false} -tracing-subscriber= {version = "0.3", features = ["json", "env-filter"]} -atty = {version = "0.2", default-features = false} +log = { version = "0.4",default-features = false } +tracing = { version = "0.1", default-features = false } +tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } +atty = { version = "0.2", default-features = false } -# config -clap = {version = "3.2", default-features = false, features = ["std", "cargo", "env"]} +# CLI args +clap = { version = "3.2", default-features = false, features = ["std", "cargo", "env"] } -# sled dependency -sled = {version = "0.34", default-features = false} +# kv store +sled = { version = "0.34", default-features = false } serde = { version = "1.0", features = ["derive"], default-features = false } -# sled encryption -chacha20poly1305 = { version = "0.9", features = ["alloc"], default-features = false } -rand = {version = "0.8", default-features = false } +dirs = { version = "5.0", default-features = false } -rpassword = { version = "5.0", default-features = false } +# kv store encryption +chacha20poly1305 = { version = "0.10", features = ["alloc"], default-features = false } +rand = { version = "0.8", default-features = false } +rpassword = { version = "7.3", default-features = false } scrypt = { version = "0.11", default-features = false, features = ["std"] } -# tonic dependencies -prost = {version = "0.9", default-features = false} -tokio = { version = "1.8", features = ["rt-multi-thread", "macros", "signal", "net", "sync"], default-features = false } -tokio-stream = {version = "0.1.7", features = ["net"], default-features = false} -futures-util = {version = "0.3", default-features = false} +# gRPC server +tonic = { version = "0.6" } # ensure tonic-build version matches this +prost = { version = "0.9" } + +# async runtime +tokio = { version = "1.38", features = ["rt-multi-thread", "macros", "signal", "net", "sync"], default-features = false } +tokio-stream = { version = "0.1.15", features = ["net"], default-features = false } +futures-util = { version = "0.3", default-features = false } # mnemonic -tiny-bip39 = { version = "0.8.2", default-features = false} +tiny-bip39 = { version = "1.0.0", default-features = false} zeroize = { version = "1.8", features = ["zeroize_derive"], default-features = false} -#error handling +# error handling thiserror = { version = "1.0", default-features = false } anyhow = { version = "1.0", default-features = false } -dirs = { version = "4.0", default-features = false } - [build-dependencies] -tonic-build = {version = "0.6"} +tonic-build = { version = "0.6" } [dev-dependencies] -lazy_static = { version = "1.4", default-features = false} +lazy_static = { version = "1.5", default-features = false} # enable logging for tests -tracing-test = {version = "0.2", default-features = false} +tracing-test = { version = "0.2", default-features = false } -testdir = {version = "0.4", default-features = false} +testdir = { version = "0.9", default-features = false } # Don't abort in case there is a panic to clean up data [profile.dev] diff --git a/README.md b/README.md index acce6f5a..d45575e7 100644 --- a/README.md +++ b/README.md @@ -91,12 +91,13 @@ OPTIONS: -a, --address [default: 0.0.0.0] -d, --directory [env: TOFND_HOME=] [default: .tofnd] -m, --mnemonic [default: existing] [possible values: existing, create, import, export] - -p, --port [default: 50051]] + -p, --port [default: 50051] ``` ## Docker -### Setup +### Docker Setup + To setup a `tofnd` container, use the `create` mnemonic command: ```bash diff --git a/build.rs b/build.rs index 7986f24e..26f232c7 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,5 @@ fn main() -> Result<(), Box> { - // Use [`compile_protos`] only if you don't need to tweak anything - // tonic_build::compile_protos("proto/tofnd.proto")?; - - // client build needed only for tests https://github.com/rust-lang/cargo/issues/1581 + // TODO: client build is needed only for tests https://github.com/rust-lang/cargo/issues/1581 tonic_build::configure() // .build_client(false) // .out_dir(".") // if you want to peek at the generated code diff --git a/src/config/mod.rs b/src/config/mod.rs index 3c6d4900..0f72df95 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -89,14 +89,17 @@ pub fn parse_args() -> TofndResult { let ip = matches .get_one::("ip") - .ok_or_else(|| anyhow!("ip value"))?.clone(); + .ok_or_else(|| anyhow!("ip value"))? + .clone(); let port = matches .get_one::("port") .ok_or_else(|| anyhow!("port value"))? .parse::()?; - let mnemonic_cmd = Cmd::from_string(matches - .get_one::("mnemonic") - .ok_or_else(|| anyhow!("cmd value"))?)?; + let mnemonic_cmd = Cmd::from_string( + matches + .get_one::("mnemonic") + .ok_or_else(|| anyhow!("cmd value"))?, + )?; let tofnd_path = matches .get_one::("directory") .ok_or_else(|| anyhow!("directory value"))? diff --git a/src/encrypted_sled/kv.rs b/src/encrypted_sled/kv.rs index 5fb12b0c..739322c8 100644 --- a/src/encrypted_sled/kv.rs +++ b/src/encrypted_sled/kv.rs @@ -6,7 +6,7 @@ use std::convert::TryInto; -use chacha20poly1305::aead::{AeadInPlace, NewAead}; +use chacha20poly1305::aead::{AeadInPlace, KeyInit}; use chacha20poly1305::{self, XChaCha20Poly1305}; use rand::RngCore; diff --git a/src/encrypted_sled/tests.rs b/src/encrypted_sled/tests.rs index d4ea703d..51897822 100644 --- a/src/encrypted_sled/tests.rs +++ b/src/encrypted_sled/tests.rs @@ -3,7 +3,7 @@ use testdir::testdir; #[test] fn test_encrypted_sled() { - let db_path = testdir!("encrypted_db"); + let db_path = testdir!("encrypted_sled"); let db = EncryptedDb::open(db_path, get_test_password()).unwrap(); // insert -> returns None @@ -45,7 +45,7 @@ fn test_encrypted_sled() { #[test] fn test_use_existing_salt() { - let db_path = testdir!("encrypted_db"); + let db_path = testdir!("use_existing_salt"); let db = EncryptedDb::open(&db_path, get_test_password()).unwrap(); drop(db); // open existing db diff --git a/src/main.rs b/src/main.rs index 86f15870..047e0762 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use multisig::service::MultisigService; +use proto::multisig_server::MultisigServer; use std::net::SocketAddr; use tokio::net::TcpListener; use tokio_stream::wrappers::TcpListenerStream; @@ -56,14 +58,12 @@ async fn main() -> TofndResult<()> { .handle_mnemonic(&cfg.mnemonic_cmd) .await?; - let multisig_service = multisig::service::new_service(kv_manager); - if cmd.exit_after_cmd() { info!("Tofnd exited after using command <{:?}>. Run `./tofnd -m existing` to execute gRPC daemon.", cmd); return Ok(()); } - let multisig_service = proto::multisig_server::MultisigServer::new(multisig_service); + let service = MultisigServer::new(MultisigService::new(kv_manager)); let incoming = TcpListener::bind(socket_address).await?; info!( @@ -72,7 +72,7 @@ async fn main() -> TofndResult<()> { ); tonic::transport::Server::builder() - .add_service(multisig_service) + .add_service(service) .serve_with_incoming_shutdown(TcpListenerStream::new(incoming), shutdown_signal()) .await?; diff --git a/src/multisig/key_presence.rs b/src/multisig/key_presence.rs index 36ae1635..b1efa9de 100644 --- a/src/multisig/key_presence.rs +++ b/src/multisig/key_presence.rs @@ -18,10 +18,13 @@ impl MultisigService { &self, request: proto::KeyPresenceRequest, ) -> TofndResult { - // check if mnemonic is available - let algorithm = Algorithm::from_i32(request.algorithm) - .ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?; + let algorithm = match request.algorithm { + 0 => Algorithm::Ecdsa, + 1 => Algorithm::Ed25519, + _ => return Err(anyhow!("Invalid algorithm: {}", request.algorithm)), + }; + // check if mnemonic is available let _ = self .find_matching_seed(&request.key_uid, &request.pub_key, algorithm) .await?; diff --git a/src/multisig/keygen.rs b/src/multisig/keygen.rs index a5a470f6..f26436b5 100644 --- a/src/multisig/keygen.rs +++ b/src/multisig/keygen.rs @@ -7,12 +7,15 @@ use anyhow::anyhow; impl MultisigService { pub(super) async fn handle_keygen(&self, request: &KeygenRequest) -> TofndResult> { - let algorithm = Algorithm::from_i32(request.algorithm) - .ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?; + let algorithm = match request.algorithm { + 0 => Algorithm::Ecdsa, + 1 => Algorithm::Ed25519, + _ => return Err(anyhow!("Invalid algorithm: {}", request.algorithm)), + }; let secret_recovery_key = self.kv_manager.seed().await?; Ok( - KeyPair::generate(&secret_recovery_key, request.key_uid.as_bytes(), algorithm)? + KeyPair::new(&secret_recovery_key, request.key_uid.as_bytes(), algorithm)? .encoded_verifying_key(), ) } diff --git a/src/multisig/keypair.rs b/src/multisig/keypair.rs index e407665d..e653bf7d 100644 --- a/src/multisig/keypair.rs +++ b/src/multisig/keypair.rs @@ -11,7 +11,8 @@ pub enum KeyPair { } impl KeyPair { - pub fn generate( + /// Create a new `KeyPair` from the provided `SecretRecoveryKey` and `session_nonce` deterministically, for the given `algorithm`. + pub fn new( secret_recovery_key: &SecretRecoveryKey, session_nonce: &[u8], algorithm: Algorithm, @@ -35,18 +36,16 @@ impl KeyPair { pub fn encoded_verifying_key(&self) -> Vec { match self { - Self::Ecdsa(key_pair) => key_pair.encoded_verifying_key().to_vec(), - Self::Ed25519(key_pair) => key_pair.encoded_verifying_key().to_vec(), + Self::Ecdsa(key_pair) => key_pair.encoded_verifying_key().into(), + Self::Ed25519(key_pair) => key_pair.encoded_verifying_key().into(), } } pub fn sign(&self, msg_to_sign: &MessageDigest) -> TofndResult> { match self { - Self::Ecdsa(key_pair) => ecdsa::sign(key_pair.signing_key(), msg_to_sign) - .map_err(|_| anyhow!("signing failed")), - Self::Ed25519(key_pair) => { - ed25519::sign(key_pair, msg_to_sign).map_err(|_| anyhow!("signing failed")) - } + Self::Ecdsa(key_pair) => ecdsa::sign(key_pair.signing_key(), msg_to_sign), + Self::Ed25519(key_pair) => ed25519::sign(key_pair, msg_to_sign), } + .map_err(|_| anyhow!("signing failed")) } } diff --git a/src/multisig/service.rs b/src/multisig/service.rs index 7e3989e0..e7162110 100644 --- a/src/multisig/service.rs +++ b/src/multisig/service.rs @@ -6,15 +6,17 @@ use crate::proto; use tracing::{error, info}; -/// Gg20Service +/// `MultisigService` is a gRPC service wrapper around tofn's keygen and signing functions #[derive(Clone)] pub struct MultisigService { pub(super) kv_manager: KvManager, } -/// create a new Multisig gRPC server -pub fn new_service(kv_manager: KvManager) -> impl proto::multisig_server::Multisig { - MultisigService { kv_manager } +/// Create a new Multisig gRPC server +impl MultisigService { + pub fn new(kv_manager: KvManager) -> Self { + Self { kv_manager } + } } #[tonic::async_trait] diff --git a/src/multisig/sign.rs b/src/multisig/sign.rs index 46f486d5..85422a36 100644 --- a/src/multisig/sign.rs +++ b/src/multisig/sign.rs @@ -9,17 +9,19 @@ use tofn::sdk::api::SecretRecoveryKey; impl MultisigService { pub(super) async fn handle_sign(&self, request: &SignRequest) -> TofndResult> { - // re-generate secret key from seed, then sign - let algorithm = Algorithm::from_i32(request.algorithm) - .ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?; + let algorithm = match request.algorithm { + 0 => Algorithm::Ecdsa, + 1 => Algorithm::Ed25519, + _ => return Err(anyhow!("Invalid algorithm: {}", request.algorithm)), + }; + // re-generate secret key from seed, then sign let secret_recovery_key = self .find_matching_seed(&request.key_uid, &request.pub_key, algorithm) .await?; - let key_pair = - KeyPair::generate(&secret_recovery_key, request.key_uid.as_bytes(), algorithm) - .map_err(|_| anyhow!("key re-generation failed"))?; + let key_pair = KeyPair::new(&secret_recovery_key, request.key_uid.as_bytes(), algorithm) + .map_err(|_| anyhow!("key re-generation failed"))?; let signature = key_pair .sign(&request.msg_to_sign.as_slice().try_into()?) @@ -53,7 +55,7 @@ impl MultisigService { for seed_key in seed_key_iter { let secret_recovery_key = self.kv_manager.get_seed(&seed_key).await?; - let key_pair = KeyPair::generate(&secret_recovery_key, key_uid.as_bytes(), algorithm) + let key_pair = KeyPair::new(&secret_recovery_key, key_uid.as_bytes(), algorithm) .map_err(|_| anyhow!("key re-generation failed"))?; if pub_key == key_pair.encoded_verifying_key() { diff --git a/src/multisig/tests.rs b/src/multisig/tests.rs index 675ed66e..659d9918 100644 --- a/src/multisig/tests.rs +++ b/src/multisig/tests.rs @@ -13,7 +13,7 @@ use tokio::{ use tokio_stream::wrappers::TcpListenerStream; use tonic::transport::Channel; -use super::service::new_service; +use super::service::MultisigService; use testdir::testdir; use tracing::error; @@ -40,8 +40,7 @@ async fn spin_test_service_and_client() -> (MultisigClient, Sender<()>) .unwrap(); // create service - let service = new_service(kv_manager); - let service = MultisigServer::new(service); + let service = MultisigServer::new(MultisigService::new(kv_manager)); // create incoming tcp server for service let incoming = TcpListener::bind(addr(DEFAULT_TEST_IP, DEFAULT_TEST_PORT).unwrap()) diff --git a/src/tests/tofnd_party.rs b/src/tests/tofnd_party.rs index 59ed9fe7..e0283a03 100644 --- a/src/tests/tofnd_party.rs +++ b/src/tests/tofnd_party.rs @@ -5,7 +5,8 @@ use crate::{ encrypted_sled::{get_test_password, PasswordMethod}, kv_manager::KvManager, mnemonic::Cmd, - multisig, proto, + multisig::service::MultisigService, + proto::{self, multisig_server::MultisigServer}, tests::SLEEP_TIME, }; @@ -74,13 +75,12 @@ impl TofndParty { }; let kv_manager = kv_manager.handle_mnemonic(&cfg.mnemonic_cmd).await.unwrap(); - let my_service = multisig::service::new_service(kv_manager); + let service = MultisigServer::new(MultisigService::new(kv_manager)); - let proto_service = proto::multisig_server::MultisigServer::new(my_service); // let (startup_sender, startup_receiver) = tokio::sync::oneshot::channel::<()>(); let server_handle = tokio::spawn(async move { tonic::transport::Server::builder() - .add_service(proto_service) + .add_service(service) .serve_with_incoming_shutdown(TcpListenerStream::new(incoming), async { shutdown_receiver.await.unwrap(); }) From dd84d95e28e6087d29a2d9b8aac4e0d7394186a6 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Mon, 8 Jul 2024 17:06:22 -0400 Subject: [PATCH 12/15] use ubuntu runner --- .github/workflows/format.yaml | 5 ++--- .github/workflows/lint.yaml | 3 +-- .github/workflows/test.yaml | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/format.yaml b/.github/workflows/format.yaml index ef560801..625dbdc0 100644 --- a/.github/workflows/format.yaml +++ b/.github/workflows/format.yaml @@ -8,8 +8,7 @@ jobs: strategy: matrix: os: - # - ubuntu-latest - - macos-latest + - ubuntu-latest runs-on: ${{ matrix.os }} steps: - name: Checkout code @@ -23,7 +22,7 @@ jobs: profile: minimal toolchain: 1.78.0 override: true - components: rustfmt, clippy + components: rustfmt - name: Run cargo fmt uses: actions-rs/cargo@v1 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index abe81278..2128cc9f 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -8,8 +8,7 @@ jobs: strategy: matrix: os: - # - ubuntu-latest - - macos-latest + - ubuntu-latest runs-on: ${{ matrix.os }} steps: - name: Checkout code and submodule diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2307cd81..fcb1e18f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -8,8 +8,7 @@ jobs: strategy: matrix: os: - # - ubuntu-latest - - macos-latest + - ubuntu-latest runs-on: ${{ matrix.os }} steps: - name: Checkout code and submodule @@ -23,6 +22,7 @@ jobs: profile: minimal toolchain: 1.78.0 override: true + components: rustfmt - name: Run cargo test run: cargo test --release --all-features From 243dd1af0c6b13726c6368c1034901143584b715 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Mon, 8 Jul 2024 18:53:07 -0400 Subject: [PATCH 13/15] revert runner change --- .github/workflows/format.yaml | 3 ++- .github/workflows/lint.yaml | 3 ++- .github/workflows/test.yaml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/format.yaml b/.github/workflows/format.yaml index 625dbdc0..b0910c5d 100644 --- a/.github/workflows/format.yaml +++ b/.github/workflows/format.yaml @@ -8,7 +8,8 @@ jobs: strategy: matrix: os: - - ubuntu-latest + # - ubuntu-latest + - macos-latest runs-on: ${{ matrix.os }} steps: - name: Checkout code diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 2128cc9f..abe81278 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -8,7 +8,8 @@ jobs: strategy: matrix: os: - - ubuntu-latest + # - ubuntu-latest + - macos-latest runs-on: ${{ matrix.os }} steps: - name: Checkout code and submodule diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index fcb1e18f..d9c6c7b7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -8,7 +8,8 @@ jobs: strategy: matrix: os: - - ubuntu-latest + # - ubuntu-latest + - macos-latest runs-on: ${{ matrix.os }} steps: - name: Checkout code and submodule From 8eaef4f20ca359fe4fa10045d1f031891a7909d5 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Wed, 10 Jul 2024 02:17:26 -0400 Subject: [PATCH 14/15] cast from proto enum --- src/multisig/key_presence.rs | 7 ++----- src/multisig/keygen.rs | 7 ++----- src/multisig/sign.rs | 7 ++----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/multisig/key_presence.rs b/src/multisig/key_presence.rs index b1efa9de..a614adde 100644 --- a/src/multisig/key_presence.rs +++ b/src/multisig/key_presence.rs @@ -18,11 +18,8 @@ impl MultisigService { &self, request: proto::KeyPresenceRequest, ) -> TofndResult { - let algorithm = match request.algorithm { - 0 => Algorithm::Ecdsa, - 1 => Algorithm::Ed25519, - _ => return Err(anyhow!("Invalid algorithm: {}", request.algorithm)), - }; + let algorithm = Algorithm::from_i32(request.algorithm) + .ok_or_else(|| anyhow!("Invalid algorithm: {}", request.algorithm))?; // check if mnemonic is available let _ = self diff --git a/src/multisig/keygen.rs b/src/multisig/keygen.rs index f26436b5..f1dac365 100644 --- a/src/multisig/keygen.rs +++ b/src/multisig/keygen.rs @@ -7,11 +7,8 @@ use anyhow::anyhow; impl MultisigService { pub(super) async fn handle_keygen(&self, request: &KeygenRequest) -> TofndResult> { - let algorithm = match request.algorithm { - 0 => Algorithm::Ecdsa, - 1 => Algorithm::Ed25519, - _ => return Err(anyhow!("Invalid algorithm: {}", request.algorithm)), - }; + let algorithm = Algorithm::from_i32(request.algorithm) + .ok_or_else(|| anyhow!("Invalid algorithm: {}", request.algorithm))?; let secret_recovery_key = self.kv_manager.seed().await?; Ok( diff --git a/src/multisig/sign.rs b/src/multisig/sign.rs index 85422a36..6a79446d 100644 --- a/src/multisig/sign.rs +++ b/src/multisig/sign.rs @@ -9,11 +9,8 @@ use tofn::sdk::api::SecretRecoveryKey; impl MultisigService { pub(super) async fn handle_sign(&self, request: &SignRequest) -> TofndResult> { - let algorithm = match request.algorithm { - 0 => Algorithm::Ecdsa, - 1 => Algorithm::Ed25519, - _ => return Err(anyhow!("Invalid algorithm: {}", request.algorithm)), - }; + let algorithm = Algorithm::from_i32(request.algorithm) + .ok_or_else(|| anyhow!("Invalid algorithm: {}", request.algorithm))?; // re-generate secret key from seed, then sign let secret_recovery_key = self From e8673554e977cb97dc83a21bc4ca3ce1c44bfad9 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Wed, 10 Jul 2024 02:24:49 -0400 Subject: [PATCH 15/15] update manifest and readme --- Cargo.toml | 4 +++- README.md | 7 +------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 259b3c0b..51404c5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "tofnd" version = "1.0.0" -authors = ["Gus Gutoski ", "Stelios Daveas "] +authors = ["Interoplabs Eng "] edition = "2021" license = "MIT OR Apache-2.0" +description = "A cryptographic signing service, used by the Axelar network" +keywords = ["cryptography", "blockchain", "axelar", "ecdsa", "ed25519"] [dependencies] tofn = { version = "1.0" } diff --git a/README.md b/README.md index d45575e7..85ed5c30 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Tofnd: A gRPC threshold signature scheme daemon +# tofnd: A cryptographic signing service Tofnd is a [gRPC](https://grpc.io/) server written in Rust that wraps the [tofn](https://github.com/axelarnetwork/tofn) cryptography library. @@ -165,7 +165,6 @@ We use the [zeroize](https://docs.rs/zeroize/1.1.1/zeroize/) crate to clear sens 1. entropy 2. passwords -3. passphrases Note that, [tiny-bip39](https://docs.rs/crate/tiny-bip39) also uses `zeroize` internally. @@ -175,10 +174,6 @@ To persist information between different gRPCs (i.e. _keygen_ and _sign_), we us `Tofnd` uses an encrypted mnemonic KV Store which stores the entropy of a mnemonic passphrase. This entropy is used to derive user's keys. The KV Store is encrypted with a password provided by the user. The password is used to derive a key that encrypts the KV Store. -## Security - -**Important note**: Currently, the `mnemonic KV Store` is **not** encrypted. The mnemonic entropy is stored in clear text on disk. Our current security model assumes secure device access. - ## Threshold cryptography For an implementation of the [GG20](https://eprint.iacr.org/2020/540.pdf) threshold-ECDSA protocol,