Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update deps #331

Merged
merged 17 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,029 changes: 748 additions & 1,281 deletions Cargo.lock

Large diffs are not rendered by default.

64 changes: 33 additions & 31 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,59 +1,61 @@
[package]
name = "tofnd"
version = "0.11.0"
authors = ["Gus Gutoski <gus@axelar.network>", "Stelios Daveas <stelios@axelar.network>"]
edition = "2018"
version = "1.0.0"
authors = ["Interoplabs Eng <eng@interoplabs.io>"]
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]
tonic = "0.6"
tofn = { version = "1.0" }
# tofn = { path = "../tofn" }
sled = {version = "0.34", default-features = false}

# 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.0", default-features = false, features = ["std", "cargo", "env"]}
# CLI args
clap = { version = "3.2", default-features = false, features = ["std", "cargo", "env"] }

# sled dependency
# 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}
zeroize = { version = "1.4", features = ["zeroize_derive"], 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]
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -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 \
Expand Down
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -91,12 +91,13 @@ OPTIONS:
-a, --address <ip> [default: 0.0.0.0]
-d, --directory <directory> [env: TOFND_HOME=] [default: .tofnd]
-m, --mnemonic <mnemonic> [default: existing] [possible values: existing, create, import, export]
-p, --port <port> [default: 50051]]
-p, --port <port> [default: 50051]
```

## Docker

### Setup
### Docker Setup

To setup a `tofnd` container, use the `create` mnemonic command:

```bash
Expand Down Expand Up @@ -164,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.

Expand All @@ -174,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,
Expand Down
5 changes: 1 addition & 4 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 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
Expand Down
27 changes: 14 additions & 13 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -40,7 +40,7 @@ pub fn parse_args() -> TofndResult<Config> {
.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(
Expand Down Expand Up @@ -73,7 +73,8 @@ pub fn parse_args() -> TofndResult<Config> {
.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")
Expand All @@ -87,23 +88,23 @@ pub fn parse_args() -> TofndResult<Config> {
let matches = app.get_matches();

let ip = matches
.value_of("ip")
.get_one::<String>("ip")
.ok_or_else(|| anyhow!("ip value"))?
.to_string();
.clone();
let port = matches
.value_of("port")
.get_one::<String>("port")
.ok_or_else(|| anyhow!("port value"))?
.parse::<u16>()?;
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::<String>("mnemonic")
.ok_or_else(|| anyhow!("cmd value"))?,
)?;
let tofnd_path = matches
.value_of("directory")
.get_one::<String>("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,
};
Expand Down
2 changes: 1 addition & 1 deletion src/encrypted_sled/kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions src/encrypted_sled/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 <key: value> -> returns None
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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!(
Expand All @@ -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?;

Expand Down
4 changes: 2 additions & 2 deletions src/multisig/key_presence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ impl MultisigService {
&self,
request: proto::KeyPresenceRequest,
) -> TofndResult<proto::key_presence_response::Response> {
// check if mnemonic is available
let algorithm = Algorithm::from_i32(request.algorithm)
.ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?;
.ok_or_else(|| anyhow!("Invalid algorithm: {}", request.algorithm))?;

// check if mnemonic is available
let _ = self
.find_matching_seed(&request.key_uid, &request.pub_key, algorithm)
.await?;
Expand Down
4 changes: 2 additions & 2 deletions src/multisig/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ use anyhow::anyhow;
impl MultisigService {
pub(super) async fn handle_keygen(&self, request: &KeygenRequest) -> TofndResult<Vec<u8>> {
let algorithm = Algorithm::from_i32(request.algorithm)
.ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?;
.ok_or_else(|| 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(),
)
}
Expand Down
15 changes: 7 additions & 8 deletions src/multisig/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -35,18 +36,16 @@ impl KeyPair {

pub fn encoded_verifying_key(&self) -> Vec<u8> {
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<Vec<u8>> {
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"))
}
}
10 changes: 6 additions & 4 deletions src/multisig/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
11 changes: 5 additions & 6 deletions src/multisig/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ use tofn::sdk::api::SecretRecoveryKey;

impl MultisigService {
pub(super) async fn handle_sign(&self, request: &SignRequest) -> TofndResult<Vec<u8>> {
// re-generate secret key from seed, then sign
let algorithm = Algorithm::from_i32(request.algorithm)
.ok_or(anyhow!("Invalid algorithm: {}", request.algorithm))?;
.ok_or_else(|| 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()?)
Expand Down Expand Up @@ -53,7 +52,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() {
Expand Down
Loading
Loading