diff --git a/Cargo.lock b/Cargo.lock index 6b6887c..1c816a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,7 +241,7 @@ dependencies = [ [[package]] name = "anychain-kms" -version = "0.1.13" +version = "0.1.14" dependencies = [ "anyhow", "bs58 0.4.0", diff --git a/crates/anychain-kms/Cargo.toml b/crates/anychain-kms/Cargo.toml index 67e97c1..056f223 100644 --- a/crates/anychain-kms/Cargo.toml +++ b/crates/anychain-kms/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "anychain-kms" description = "A Rust library providing Key Management Schema for AnyChain. Handles general security and signature algorithms." -version = "0.1.13" +version = "0.1.14" keywords = ["cryptography", "security", "signature", "algorithm"] categories = ["cryptography::cryptocurrencies"] 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..a3a51f1 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,7 +8,7 @@ use core::{ fmt::{self, Debug}, str::FromStr, }; -//use hmac::{Mac, NewMac}; +use curve25519_dalek::scalar::Scalar; use hmac::Mac; use subtle::{Choice, ConstantTimeEq}; use zeroize::Zeroize; @@ -24,9 +24,12 @@ const BIP39_DOMAIN_SEPARATOR: [u8; 12] = [ 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x20, 0x73, 0x65, 0x65, 0x64, ]; -/// Extended private secp256k1 ECDSA signing key. +/// Extended private secp256k1 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/extended_key/extended_public_key.rs b/crates/anychain-kms/src/bip32/extended_key/extended_public_key.rs index 9ad7f04..b1f5b55 100644 --- a/crates/anychain-kms/src/bip32/extended_key/extended_public_key.rs +++ b/crates/anychain-kms/src/bip32/extended_key/extended_public_key.rs @@ -96,7 +96,12 @@ where attrs: self.attrs.clone(), key_bytes: { let mut key_bytes = [0u8; KEY_SIZE + 1]; - key_bytes.copy_from_slice(&self.to_bytes()); + let bytes = self.to_bytes(); + let bytes = match bytes.len() { + KEY_SIZE => [vec![0u8], bytes].concat(), + _ => bytes, + }; + key_bytes.copy_from_slice(&bytes); key_bytes }, } 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() + ); + } }