keyforkd, keyfork-derive-util: add some tests, fix algo switcharound

This commit is contained in:
Ryan Heywood 2023-09-07 13:24:07 -05:00
parent c39d8343c7
commit 0d6753ef47
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
5 changed files with 94 additions and 33 deletions

1
Cargo.lock generated
View File

@ -453,6 +453,7 @@ name = "keyforkd"
version = "0.1.0"
dependencies = [
"bincode",
"hex-literal",
"keyfork-derive-util",
"keyfork-frame",
"keyfork-mnemonic-util",

View File

@ -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::<k256::SecretKey>::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::<ed25519_dalek::SigningKey>::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::<k256::SecretKey>::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<u8>,
pub algorithm: DerivationAlgorithm,
pub data: Vec<u8>,
}

View File

@ -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::<SigningKey>::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);
}
}

View File

@ -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"

View File

@ -40,3 +40,50 @@ impl Service<DerivationRequest> 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)
}
}
}