// Because all algorithms make use of wildcard matching #![allow(clippy::match_wildcard_for_single_variants)] use crate::{ extended_key::private_key::Error as XPrvError, DerivationPath, ExtendedPrivateKey, PrivateKey, }; use keyfork_mnemonic_util::{Mnemonic, MnemonicGenerationError}; use serde::{Deserialize, Serialize}; #[derive(Debug, thiserror::Error)] pub enum DerivationError { #[error("algorithm not supported")] Algorithm, #[error("Unable to create seed from mnemonic: {0}")] Mnemonic(#[from] MnemonicGenerationError), #[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: path.clone(), } } pub fn path(&self) -> &DerivationPath { &self.path } pub fn derive_with_mnemonic(&self, mnemonic: &Mnemonic) -> Result { // TODO: passphrase support and/or store passphrase within mnemonic self.derive_with_master_seed(mnemonic.seed(None)?) } 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(), } } } #[derive(Debug, thiserror::Error)] pub enum TryFromDerivationResponseError { #[error("incorrect algorithm provided")] Algorithm, #[error("{0}")] ExtendedPrivateKey(#[from] XPrvError), } #[cfg(feature = "secp256k1")] impl TryFrom<&DerivationResponse> for ExtendedPrivateKey { type Error = TryFromDerivationResponseError; fn try_from(value: &DerivationResponse) -> std::result::Result { match value.algorithm { DerivationAlgorithm::Secp256k1 => { Self::new_from_parts(&value.data, value.depth, value.chain_code).map_err(From::from) } _ => Err(Self::Error::Algorithm), } } } #[cfg(feature = "secp256k1")] impl TryFrom for ExtendedPrivateKey { type Error = TryFromDerivationResponseError; fn try_from(value: DerivationResponse) -> std::result::Result { ExtendedPrivateKey::::try_from(&value) } } #[cfg(feature = "ed25519")] impl TryFrom<&DerivationResponse> for ExtendedPrivateKey { type Error = TryFromDerivationResponseError; fn try_from(value: &DerivationResponse) -> std::result::Result { match value.algorithm { DerivationAlgorithm::Ed25519 => { Self::new_from_parts(&value.data, value.depth, value.chain_code).map_err(From::from) } _ => Err(Self::Error::Algorithm), } } } #[cfg(feature = "ed25519")] impl TryFrom for ExtendedPrivateKey { type Error = TryFromDerivationResponseError; fn try_from(value: DerivationResponse) -> std::result::Result { ExtendedPrivateKey::::try_from(&value) } }