use crate::error::{Error, Result}; use hmac::{Hmac, Mac}; use sha2::Sha512; pub trait MasterKey<'a> { /// Return the textual content used to derive the master key, as specified in BIP 0032 and SLIP /// 0010. For example, a secp256k1 master key would use the textual content "Bitcoin seed", to /// ensure compatibility with BIP 0032, despite the key being used for more functionality than /// purely Bitcoin. fn key() -> &'static str; /// Some key algorithms, such as Ed25519, allow 0 as a valid private key. Those algorithhms /// should override this method to indicate as such. fn is_zero_valid_private_key() -> bool { false } /// Return the seed used to derive the Master Key, with a size between 128 to 512 bits. Most /// seeds should be 256 bits, the largest size available from a BIP-0039 mnemonic. fn seed(&self) -> &'a [u8]; } type HmacSha512 = Hmac; /// Generate a Master Secret Key and Chain Code (what is this used for?). /// /// # Errors /// /// An error may be returned if: /// * The `HmacSha512` key returned by `T::key()` is invalid. This should never happen. /// * The generated master key is all zeroes. This has a cosmically small chance of happening. pub fn generate<'a, T: MasterKey<'a>>(generator: &T) -> Result<(Vec, Vec)> { let seed = generator.seed(); let len = seed.len(); if len * 8 % 32 != 0 { return Err(Error::BadSeedLength(len)); } let mut hmac = HmacSha512::new_from_slice(&T::key().bytes().collect::>())?; hmac.update(seed); let result = hmac.finalize().into_bytes(); let left = &result[..32]; let right = &result[32..]; if left.iter().all(|n| n == &0) { // Wow. Impressive. // NOTE: SLIP-0010 says to retry if this happens, but uses some weird terminology to do so. // I do not trust it. BIP-0032 says this key is "invalid", with no instructions to retry. // This is a low enough chance I am fine with it being freak-of-nature error. return Err(Error::HashedSeedIsZero); } Ok((left.to_vec(), right.to_vec())) }