diff --git a/crates/anychain-kms/src/bip32/extended_key/extended_private_key.rs b/crates/anychain-kms/src/bip32/extended_key/extended_private_key.rs index e17a9b3..97c21a1 100644 --- a/crates/anychain-kms/src/bip32/extended_key/extended_private_key.rs +++ b/crates/anychain-kms/src/bip32/extended_key/extended_private_key.rs @@ -8,6 +8,7 @@ use core::{ fmt::{self, Debug}, str::FromStr, }; +use curve25519_dalek::scalar::Scalar; //use hmac::{Mac, NewMac}; use hmac::Mac; use subtle::{Choice, ConstantTimeEq}; @@ -27,6 +28,9 @@ const BIP39_DOMAIN_SEPARATOR: [u8; 12] = [ /// Extended private secp256k1 ECDSA signing key. pub type XprvSecp256k1 = ExtendedPrivateKey; +/// Extended private ed25519 signing key. +pub type XprvEd25519 = ExtendedPrivateKey; + /// Extended private keys derived using BIP32. /// /// Generic around a [`PrivateKey`] type. When the `secp256k1` feature of this diff --git a/crates/anychain-kms/src/bip32/mod.rs b/crates/anychain-kms/src/bip32/mod.rs index c1d91de..b1ace93 100644 --- a/crates/anychain-kms/src/bip32/mod.rs +++ b/crates/anychain-kms/src/bip32/mod.rs @@ -13,7 +13,7 @@ pub use extended_key::{ extended_public_key::ExtendedPublicKey, ExtendedKey, }; pub use extended_key::{ - extended_private_key::XprvSecp256k1, + extended_private_key::{XprvEd25519, XprvSecp256k1}, extended_public_key::{XpubEd25519, XpubSecp256k1}, }; pub use prefix::Prefix; diff --git a/crates/anychain-kms/src/bip32/private_key.rs b/crates/anychain-kms/src/bip32/private_key.rs index 70c2a0c..e63c46d 100644 --- a/crates/anychain-kms/src/bip32/private_key.rs +++ b/crates/anychain-kms/src/bip32/private_key.rs @@ -1,10 +1,9 @@ //! Trait for deriving child keys on a given type. -use crate::bip32::{PublicKey, Result}; +use crate::bip32::{Error, PublicKey, Result, XprvEd25519, XprvSecp256k1}; -use crate::bip32::{Error, XprvSecp256k1}; - -use libsecp256k1; +use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE as G, scalar::Scalar}; +use group::GroupEncoding; /// Trait for key types which can be derived using BIP32. pub trait PrivateKey: Sized { @@ -65,16 +64,51 @@ impl From<&XprvSecp256k1> for libsecp256k1::SecretKey { } } +impl PrivateKey for Scalar { + type PublicKey = ed25519_dalek::PublicKey; + + fn from_bytes(bytes: Vec) -> Result { + let mut sk = [0u8; 32]; + sk.copy_from_slice(&bytes); + Ok(Scalar::from_bytes_mod_order(sk)) + } + + fn to_bytes(&self) -> Vec { + self.to_bytes().to_vec() + } + + fn derive_child(&self, tweak: Vec) -> Result { + let mut _tweak = [0u8; 32]; + _tweak.copy_from_slice(&tweak); + let tweak = Scalar::from_bytes_mod_order(_tweak); + Ok(self + tweak) + } + + fn public_key(&self) -> Self::PublicKey { + let pk = (G * self).to_bytes(); + ed25519_dalek::PublicKey::from_bytes(&pk).unwrap() + } +} + +impl From for Scalar { + fn from(xprv: XprvEd25519) -> Scalar { + Scalar::from(&xprv) + } +} + +impl From<&XprvEd25519> for Scalar { + fn from(xprv: &XprvEd25519) -> Scalar { + *xprv.private_key() + } +} + #[cfg(test)] mod tests { + use super::{XprvEd25519, XprvSecp256k1}; use hex_literal::hex; - //type XprvSecp256k1 = crate::bip32::ExtendedPrivateKey; - - type XprvSecp256k1 = crate::bip32::ExtendedPrivateKey; - #[test] - fn secp256k1_derivation() { + fn test_secp256k1_derivation() { let seed = hex!( "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a2 9f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542" @@ -88,4 +122,20 @@ mod tests { "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j".parse().unwrap() ); } + + #[test] + fn test_ed25519_derivation() { + let seed = hex!( + "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a2 + 9f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542" + ); + + let path = "m/0/2147483647'/1/2147483646'/2"; + let xprv = XprvEd25519::new_from_path(seed, &path.parse().unwrap()).unwrap(); + + assert_eq!( + xprv, + "xprvA3jRL3NoAajWVMc6JWKPgQrxx5Xt6VVpgj8y6FMcBbseE4DkZEP8cfVqJQtQvyCqZpb39KZE5r7UUGwunJg9m3wksLj5x94cJv4ahGMarGU".parse().unwrap() + ); + } }