use crate::{ extended_key::private_key::Error as XPrvError, DerivationPath, ExtendedPrivateKey, PrivateKey, }; use keyfork_mnemonic_util::Mnemonic; use serde::{Deserialize, Serialize}; #[derive(Debug, thiserror::Error)] pub enum DerivationError { #[error("algorithm not supported")] Algorithm, #[error("{0}")] ExtendedPrivateKey(#[from] XPrvError), } pub type Result = std::result::Result; #[derive(Serialize, Deserialize, Clone, Debug)] pub enum DerivationAlgorithm { Ed25519, Secp256k1, } impl DerivationAlgorithm { pub fn derive(&self, seed: Vec, path: &DerivationPath) -> Result { match self { #[cfg(feature = "ed25519")] Self::Ed25519 => { let key = ExtendedPrivateKey::::new(seed)?; let derived_key = key.derive_path(path)?; Ok(DerivationResponse::with_algo_and_xprv( self.clone(), &derived_key, )) } #[cfg(feature = "secp256k1")] Self::Secp256k1 => { let key = ExtendedPrivateKey::::new(seed)?; let derived_key = key.derive_path(path)?; Ok(DerivationResponse::with_algo_and_xprv( self.clone(), &derived_key, )) } #[allow(unreachable_patterns)] _ => Err(DerivationError::Algorithm), } } } impl std::str::FromStr for DerivationAlgorithm { type Err = DerivationError; fn from_str(s: &str) -> std::result::Result { Ok(match s { "ed25519" => Self::Ed25519, "secp256k1" => Self::Secp256k1, _ => return Err(DerivationError::Algorithm), }) } } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct DerivationRequest { algorithm: DerivationAlgorithm, path: DerivationPath, } impl DerivationRequest { pub fn new(algorithm: DerivationAlgorithm, path: DerivationPath) -> Self { Self { algorithm, path } } pub fn path(&self) -> &DerivationPath { &self.path } pub fn derive_with_mnemonic(&self, mnemonic: &Mnemonic) -> Result { self.derive_with_master_seed(mnemonic.seed()) } pub fn derive_with_master_seed(&self, seed: Vec) -> Result { self.algorithm.derive(seed, &self.path) } } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct DerivationResponse { pub algorithm: DerivationAlgorithm, pub data: Vec, pub chain_code: [u8; 32], pub depth: u8, } impl DerivationResponse { pub fn with_algo_and_xprv( algorithm: DerivationAlgorithm, xprv: &ExtendedPrivateKey, ) -> Self { Self { algorithm, data: PrivateKey::to_bytes(xprv.private_key()).to_vec(), chain_code: xprv.chain_code(), depth: xprv.depth(), } } }