From 0d6753ef4735a087538d38e2007a23426a70c6cf Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 7 Sep 2023 13:24:07 -0500 Subject: [PATCH] keyforkd, keyfork-derive-util: add some tests, fix algo switcharound --- Cargo.lock | 1 + keyfork-derive-util/src/request.rs | 26 ++++++++-------- keyfork-derive-util/src/tests.rs | 50 ++++++++++++++++++------------ keyforkd/Cargo.toml | 3 ++ keyforkd/src/service.rs | 47 ++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e04d43a..bbc5e82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,6 +453,7 @@ name = "keyforkd" version = "0.1.0" dependencies = [ "bincode", + "hex-literal", "keyfork-derive-util", "keyfork-frame", "keyfork-mnemonic-util", diff --git a/keyfork-derive-util/src/request.rs b/keyfork-derive-util/src/request.rs index 7c95f19..bad236b 100644 --- a/keyfork-derive-util/src/request.rs +++ b/keyfork-derive-util/src/request.rs @@ -1,4 +1,4 @@ -use crate::{extended_key::private_key::Error as XPrvError, DerivationPath, ExtendedPrivateKey}; +use crate::{extended_key::private_key::Error as XPrvError, DerivationPath, ExtendedPrivateKey, PrivateKey}; use keyfork_mnemonic_util::Mnemonic; use serde::{Deserialize, Serialize}; @@ -24,20 +24,20 @@ impl DerivationAlgorithm { match self { #[cfg(feature = "ed25519")] Self::Ed25519 => { - let key = ExtendedPrivateKey::::new(seed)?; - let derived_key = key.derive_path(path)?; - Ok(DerivationResponse { - algorithm: self.clone(), - data: derived_key.private_key.to_bytes().to_vec(), - }) - } - #[cfg(feature = "secp256k1")] - Self::Secp256k1 => { let key = ExtendedPrivateKey::::new(seed)?; let derived_key = key.derive_path(path)?; Ok(DerivationResponse { algorithm: self.clone(), - data: derived_key.private_key.to_bytes().to_vec(), + data: PrivateKey::to_bytes(&derived_key.private_key).to_vec(), + }) + } + #[cfg(feature = "secp256k1")] + Self::Secp256k1 => { + let key = ExtendedPrivateKey::::new(seed)?; + let derived_key = key.derive_path(path)?; + Ok(DerivationResponse { + algorithm: self.clone(), + data: PrivateKey::to_bytes(&derived_key.private_key).to_vec(), }) } #[allow(unreachable_patterns)] @@ -68,6 +68,6 @@ impl DerivationRequest { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct DerivationResponse { - algorithm: DerivationAlgorithm, - data: Vec, + pub algorithm: DerivationAlgorithm, + pub data: Vec, } diff --git a/keyfork-derive-util/src/tests.rs b/keyfork-derive-util/src/tests.rs index d310cf2..b4a74a3 100644 --- a/keyfork-derive-util/src/tests.rs +++ b/keyfork-derive-util/src/tests.rs @@ -1,4 +1,4 @@ -use crate::*; +use crate::{request::*, *}; use hex_literal::hex; use std::str::FromStr; @@ -65,6 +65,9 @@ fn secp256k1() { assert_eq!(derived_key.chain_code, chain_code); assert_eq!(derived_key.private_key.to_bytes().as_slice(), private_key); assert_eq!(derived_key.public_key().to_bytes(), public_key); + let request = DerivationRequest::new(DerivationAlgorithm::Secp256k1, chain); + let response = request.derive_with_master_seed(seed.to_vec()).unwrap(); + assert_eq!(response.data, private_key); } } @@ -74,30 +77,37 @@ fn ed25519() { use ed25519_dalek::SigningKey; // seed, chain, chain code, private, public - let tests = [( - &hex!("000102030405060708090a0b0c0d0e0f")[..], - DerivationPath::from_str("m").unwrap(), - hex!("90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), - hex!("2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), - hex!("00a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), - ), ( - &hex!("000102030405060708090a0b0c0d0e0f")[..], - DerivationPath::from_str("m/0'").unwrap(), - hex!("8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), - hex!("68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), - hex!("008c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), - ), ( - &hex!("000102030405060708090a0b0c0d0e0f")[..], - DerivationPath::from_str("m/0'/1'/2'/2'/1000000000'").unwrap(), - hex!("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), - hex!("8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), - hex!("003c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), - )]; + let tests = [ + ( + &hex!("000102030405060708090a0b0c0d0e0f")[..], + DerivationPath::from_str("m").unwrap(), + hex!("90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), + hex!("2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), + hex!("00a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), + ), + ( + &hex!("000102030405060708090a0b0c0d0e0f")[..], + DerivationPath::from_str("m/0'").unwrap(), + hex!("8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), + hex!("68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), + hex!("008c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), + ), + ( + &hex!("000102030405060708090a0b0c0d0e0f")[..], + DerivationPath::from_str("m/0'/1'/2'/2'/1000000000'").unwrap(), + hex!("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), + hex!("8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), + hex!("003c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), + ), + ]; for (seed, chain, chain_code, private_key, public_key) in tests { let xkey = ExtendedPrivateKey::::new(seed).unwrap(); let derived_key = xkey.derive_path(&chain).unwrap(); assert_eq!(derived_key.chain_code, chain_code); assert_eq!(PrivateKey::to_bytes(&derived_key.private_key), private_key); assert_eq!(PublicKey::to_bytes(&derived_key.public_key()), public_key); + let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, chain); + let response = request.derive_with_master_seed(seed.to_vec()).unwrap(); + assert_eq!(response.data, private_key); } } diff --git a/keyforkd/Cargo.toml b/keyforkd/Cargo.toml index 5d05c85..bf2ee86 100644 --- a/keyforkd/Cargo.toml +++ b/keyforkd/Cargo.toml @@ -28,3 +28,6 @@ tower = { version = "0.4.13", features = ["tokio", "util"] } # Personally audited thiserror = "1.0.47" serde = { version = "1.0.186", features = ["derive"] } + +[dev-dependencies] +hex-literal = "0.4.1" diff --git a/keyforkd/src/service.rs b/keyforkd/src/service.rs index 66a62fc..9362338 100644 --- a/keyforkd/src/service.rs +++ b/keyforkd/src/service.rs @@ -40,3 +40,50 @@ impl Service for Keyforkd { Box::pin(async { req.derive_with_mnemonic(&mnemonic) }) } } + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + use keyfork_derive_util::{request::*, DerivationPath}; + use keyfork_mnemonic_util::Wordlist; + use std::str::FromStr; + use tower::ServiceExt; + + #[tokio::test] + async fn properly_derives_data() { + // Pulled from keyfork-derive-util's tests, which is more extensively tested. + let tests = [ + ( + &hex!("000102030405060708090a0b0c0d0e0f")[..], + DerivationPath::from_str("m").unwrap(), + hex!("90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb"), + hex!("2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7"), + hex!("00a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed"), + ), + ( + &hex!("000102030405060708090a0b0c0d0e0f")[..], + DerivationPath::from_str("m/0'").unwrap(), + hex!("8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69"), + hex!("68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3"), + hex!("008c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c"), + ), + ( + &hex!("000102030405060708090a0b0c0d0e0f")[..], + DerivationPath::from_str("m/0'/1'/2'/2'/1000000000'").unwrap(), + hex!("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230"), + hex!("8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793"), + hex!("003c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a"), + ), + ]; + let wordlist = Wordlist::default().arc(); + for (seed, path, _, private_key, _) in tests { + let mnemonic = Mnemonic::from_entropy(&seed[..], wordlist.clone()).unwrap(); + assert_eq!(mnemonic.seed(), seed); + let req = DerivationRequest::new(DerivationAlgorithm::Ed25519, path); + let mut keyforkd = Keyforkd::new(mnemonic); + let response = keyforkd.ready().await.unwrap().call(req).await.unwrap(); + assert_eq!(response.data, private_key) + } + } +}