diff --git a/Cargo.lock b/Cargo.lock index 39ba73f..669e511 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -893,6 +893,13 @@ dependencies = [ "thiserror", ] +[[package]] +name = "keyfork-derive-path-data" +version = "0.1.0" +dependencies = [ + "keyfork-derive-util", +] + [[package]] name = "keyfork-derive-util" version = "0.1.0" @@ -954,6 +961,7 @@ version = "0.1.0" dependencies = [ "bincode", "hex-literal", + "keyfork-derive-path-data", "keyfork-derive-util", "keyfork-frame", "keyfork-mnemonic-util", diff --git a/Cargo.toml b/Cargo.toml index 5f07474..6852632 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,10 @@ resolver = "2" members = [ "keyfork", - "keyfork-derive-util", "keyfork-derive-key", "keyfork-derive-openpgp", + "keyfork-derive-path-data", + "keyfork-derive-util", "keyfork-frame", "keyfork-mnemonic-util", "keyfork-plumbing", diff --git a/keyfork-derive-path-data/Cargo.toml b/keyfork-derive-path-data/Cargo.toml new file mode 100644 index 0000000..4b3c4f3 --- /dev/null +++ b/keyfork-derive-path-data/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "keyfork-derive-path-data" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util", default-features = false } diff --git a/keyfork-derive-path-data/src/lib.rs b/keyfork-derive-path-data/src/lib.rs new file mode 100644 index 0000000..1b89174 --- /dev/null +++ b/keyfork-derive-path-data/src/lib.rs @@ -0,0 +1,26 @@ +use keyfork_derive_util::{DerivationPath, DerivationIndex}; + +pub static OPENPGP: DerivationIndex = DerivationIndex::new_unchecked(7366512, true); + +pub enum Target { + OpenPGP(DerivationIndex), +} + +impl std::fmt::Display for Target { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::OpenPGP(account) => { + write!(f, "OpenPGP key (account {account})") + } + } + } +} + +/// Determine the closest [`Target`] for the given path. This method is intended to be used by +/// `keyforkd` to provide an optional textual prompt to what a client is attempting to derive. +pub fn guess_target(path: &DerivationPath) -> Option { + Some(match Vec::from_iter(path.iter())[..] { + [t, index] if t == &OPENPGP => Target::OpenPGP(index.clone()), + _ => return None, + }) +} diff --git a/keyfork-derive-util/src/index.rs b/keyfork-derive-util/src/index.rs index 71ba6f0..15254f9 100644 --- a/keyfork-derive-util/src/index.rs +++ b/keyfork-derive-util/src/index.rs @@ -25,11 +25,16 @@ impl DerivationIndex { /// # Errors /// /// Returns an error if the index is larger than the hardened flag. - pub fn new(index: u32, hardened: bool) -> Result { + pub const fn new(index: u32, hardened: bool) -> Result { if index & (0b1 << 31) > 0 { return Err(Error::IndexTooLarge(index)); } - Ok(Self(index | (u32::from(hardened) << 31))) + Ok(Self(index | ((hardened as u32) << 31))) + } + + #[doc(hidden)] + pub const fn new_unchecked(index: u32, hardened: bool) -> Self { + Self(index | ((hardened as u32) << 31)) } /* @@ -39,6 +44,10 @@ impl DerivationIndex { } */ + pub fn inner(&self) -> u32 { + self.0 + } + pub(crate) fn to_bytes(&self) -> [u8; 4] { self.0.to_be_bytes() } diff --git a/keyfork-mnemonic-util/src/lib.rs b/keyfork-mnemonic-util/src/lib.rs index f446b5d..726b227 100644 --- a/keyfork-mnemonic-util/src/lib.rs +++ b/keyfork-mnemonic-util/src/lib.rs @@ -207,7 +207,7 @@ impl Mnemonic { bits[index * 11 + bit] = (word & (1 << (10 - bit))) > 0; } } - + // remove checksum bits bits.truncate(bits.len() - bits.len() % 32); diff --git a/keyforkd/Cargo.toml b/keyforkd/Cargo.toml index e1afadc..005414d 100644 --- a/keyforkd/Cargo.toml +++ b/keyforkd/Cargo.toml @@ -28,6 +28,7 @@ tower = { version = "0.4.13", features = ["tokio", "util"] } # Personally audited thiserror = "1.0.47" serde = { version = "1.0.186", features = ["derive"] } +keyfork-derive-path-data = { version = "0.1.0", path = "../keyfork-derive-path-data" } [dev-dependencies] hex-literal = "0.4.1" diff --git a/keyforkd/src/service.rs b/keyforkd/src/service.rs index a550bb9..c13fc24 100644 --- a/keyforkd/src/service.rs +++ b/keyforkd/src/service.rs @@ -1,7 +1,9 @@ use std::{future::Future, pin::Pin, sync::Arc, task::Poll}; use keyfork_derive_util::request::{DerivationError, DerivationRequest, DerivationResponse}; +use keyfork_derive_path_data::guess_target; use tower::Service; +use tracing::info; // NOTE: All values implemented in Keyforkd must implement Clone with low overhead, either by // using an Arc or by having a small signature. This is because Service takes &mut self. @@ -50,6 +52,14 @@ impl Service for Keyforkd { if len < 2 { return Err(KeyforkdRequestError::InvalidDerivationLength(len)); } + + #[cfg(feature = "tracing")] + if let Some(target) = guess_target(req.path()) { + info!("Deriving path: {target}"); + } else { + info!("Deriving path: {}", req.path()); + } + req.derive_with_master_seed((*seed).clone()) .map_err(KeyforkdRequestError::from) })