Skip to content

Commit

Permalink
feat: mnemonic rotation (#281)
Browse files Browse the repository at this point in the history
* feat: add mnemonic rotation support

* feat: sign by mnemonic matching pub key

* chore: update proto commit temporarily

* typo, tweak, comment

* replace vec[0;0] with vec[]

* add rotation test and make pub_key optional

* reverted to mandatory pub key

* fmt

* lint rust 1.60

* updated proto

Co-authored-by: Gus Gutoski <[email protected]>
  • Loading branch information
milapsheth and ggutoski authored Apr 22, 2022
1 parent 5f680da commit 3d29a1e
Show file tree
Hide file tree
Showing 17 changed files with 379 additions and 65 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tofnd"
version = "0.9.1"
version = "0.10.0"
authors = ["Gus Gutoski <[email protected]>", "Stelios Daveas <[email protected]>"]
edition = "2018"
license = "MIT OR Apache-2.0"
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ For more information, see on mnemonic options, see [Mnemonic](#mnemonic).
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

USAGE:
tofnd [FLAGS] [OPTIONS]

Expand Down
2 changes: 1 addition & 1 deletion proto
Submodule proto updated 2 files
+1 −0 common.proto
+1 −0 multisig.proto
4 changes: 2 additions & 2 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const TOFND_HOME_ENV_VAR: &str = "TOFND_HOME";
const DEFAULT_MNEMONIC_CMD: &str = "existing";
const DEFAULT_IP: &str = "0.0.0.0";
const DEFAULT_PORT: u16 = 50051;
const AVAILABLE_MNEMONIC_CMDS: [&str; 4] = ["existing", "create", "import", "export"];
const AVAILABLE_MNEMONIC_CMDS: &[&str] = &["existing", "create", "import", "export", "rotate"];

#[cfg(feature = "malicious")]
mod malicious;
Expand Down Expand Up @@ -92,7 +92,7 @@ pub fn parse_args() -> TofndResult<Config> {
.short('m')
.required(false)
.default_value(DEFAULT_MNEMONIC_CMD)
.possible_values(&AVAILABLE_MNEMONIC_CMDS),
.possible_values(AVAILABLE_MNEMONIC_CMDS),
)
.arg(
Arg::new("directory")
Expand Down
10 changes: 4 additions & 6 deletions src/gg20/recover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ impl Gg20Service {
.recover_secret_key_shares(&secret_recovery_key, &keygen_init, &keygen_output)
.map_err(|err| anyhow!("Failed to acquire secret key share {}", err))?;

Ok(self
.update_share_kv_store(keygen_init, secret_key_shares)
.await?)
self.update_share_kv_store(keygen_init, secret_key_shares)
.await
}

/// get recovered secret key shares from serilized share recovery info
Expand Down Expand Up @@ -162,11 +161,10 @@ impl Gg20Service {
keygen_init_sanitized.my_index,
);
// try writing the data to the kv-store
Ok(self
.kv_manager
self.kv_manager
.kv()
.put(reservation, kv_data.try_into()?)
.await
.map_err(|err| anyhow!("failed to update kv store: {}", err))?)
.map_err(|err| anyhow!("failed to update kv store: {}", err))
}
}
2 changes: 2 additions & 0 deletions src/kv_manager/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub enum KvError {
PutErr(InnerKvError),
#[error("Get Error: {0}")]
GetErr(InnerKvError),
#[error("Delete Error: {0}")]
DeleteErr(InnerKvError),
#[error("Exits Error: {0}")]
ExistsErr(InnerKvError),
}
Expand Down
20 changes: 19 additions & 1 deletion src/kv_manager/kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::encrypted_sled::{self, Password};

use super::{
error::{KvError::*, KvResult},
sled_bindings::{handle_exists, handle_get, handle_put, handle_reserve},
sled_bindings::{handle_delete, handle_exists, handle_get, handle_put, handle_reserve},
types::{
Command::{self, *},
KeyReservation, DEFAULT_KV_NAME, DEFAULT_KV_PATH,
Expand Down Expand Up @@ -94,6 +94,19 @@ where
resp_rx.await?.map_err(GetErr)
}

/// Deletes an unreserved key
/// Returns [DeleteErr] or [SendErr] on failure.
pub async fn delete(&self, key: &str) -> KvResult<()> {
let (resp_tx, resp_rx) = oneshot::channel();
self.sender
.send(Delete {
key: key.to_string(),
resp: resp_tx,
})
.map_err(|e| SendErr(e.to_string()))?;
resp_rx.await?.map_err(DeleteErr)
}

/// Checks if a key exists in the kvstore
/// Returns [ExistsErr] or [SendErr] on failure.
pub async fn exists(&self, key: &str) -> KvResult<bool> {
Expand Down Expand Up @@ -176,6 +189,11 @@ async fn kv_cmd_handler<V: 'static>(
warn!("receiver dropped");
}
}
Delete { key, resp } => {
if resp.send(handle_delete(&kv, key)).is_err() {
warn!("receiver dropped");
}
}
}
}
info!("kv_manager stop");
Expand Down
28 changes: 24 additions & 4 deletions src/kv_manager/sled_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use serde::{de::DeserializeOwned, Serialize};
use tofn::sdk::api::{deserialize, serialize};

use super::error::{InnerKvError::*, InnerKvResult};
use super::types::{KeyReservation, DEFAULT_RESERV};
use super::types::{KeyReservation, DEFAULT_RESERVE};

use crate::encrypted_sled;

/// Reserves a key. New's key value is [DEFAULT_RESERV].
/// Reserves a key. New key's value is [DEFAULT_RESERVE].
/// Returns [SledErr] of [LogicalErr] on failure.
pub(super) fn handle_reserve(
kv: &encrypted_sled::Db,
Expand All @@ -24,12 +24,32 @@ pub(super) fn handle_reserve(
}

// try to insert the new key with default value
kv.insert(&key, DEFAULT_RESERV)?;
kv.insert(&key, DEFAULT_RESERVE)?;

// return key reservation
Ok(KeyReservation { key })
}

/// Deletes an unreserved key if it exists.
/// Returns [SledErr] of [LogicalErr] on failure.
pub(super) fn handle_delete(kv: &encrypted_sled::Db, key: String) -> InnerKvResult<()> {
if !kv.contains_key(&key)? {
return Ok(());
}

// check if key holds the default reserve value. If yes, can't delete it.
if kv.get(&key)? == Some(sled::IVec::from(DEFAULT_RESERVE)) {
return Err(LogicalErr(format!(
"can't delete reserved key <{}> in kv store.",
key
)));
}

kv.remove(&key)?;

Ok(())
}

/// Inserts a value to an existing key.
/// Returns [SledErr] of [LogicalErr] on failure.
pub(super) fn handle_put<V>(
Expand All @@ -44,7 +64,7 @@ where
// Explanation of code ugliness: that's the standard way to compare a
// sled retrieved value with a local value:
// https://docs.rs/sled/0.34.6/sled/struct.Tree.html#examples-4
if kv.get(&reservation.key)? != Some(sled::IVec::from(DEFAULT_RESERV)) {
if kv.get(&reservation.key)? != Some(sled::IVec::from(DEFAULT_RESERVE)) {
return Err(LogicalErr(format!(
"did not find reservation for key <{}> in kv store.",
reservation.key
Expand Down
4 changes: 2 additions & 2 deletions src/kv_manager/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use super::{
error::InnerKvError::LogicalErr,
sled_bindings::{handle_exists, handle_get, handle_put, handle_reserve},
types::{KeyReservation, DEFAULT_RESERV},
types::{KeyReservation, DEFAULT_RESERVE},
};
use crate::encrypted_sled;

Expand Down Expand Up @@ -42,7 +42,7 @@ fn reserve_success() {
// get bytes
let default_reserv = kv.get(&key).unwrap().unwrap();
// convert to value type
assert!(default_reserv == DEFAULT_RESERV);
assert!(default_reserv == DEFAULT_RESERVE);

clean_up(kv_name.to_str().unwrap(), kv);
}
Expand Down
6 changes: 5 additions & 1 deletion src/kv_manager/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub const DEFAULT_KV_NAME: &str = "kv";
pub(super) const DEFAULT_KV_PATH: &str = "kvstore";

/// default value for reserved key
pub(super) const DEFAULT_RESERV: &str = "";
pub(super) const DEFAULT_RESERVE: &str = "";

/// Returned from a successful `ReserveKey` command
#[derive(Debug)] // disallow derive Clone, Copy
Expand Down Expand Up @@ -49,4 +49,8 @@ pub(super) enum Command<V> {
key: String, // TODO should be &str except lifetimes...
resp: Responder<bool>,
},
Delete {
key: String,
resp: Responder<()>,
},
}
Loading

0 comments on commit 3d29a1e

Please sign in to comment.