keyfork/keyfork-derive-util/src/master_key.rs

55 lines
2.1 KiB
Rust

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<Sha512>;
/// 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<u8>, Vec<u8>)> {
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::<Vec<_>>())?;
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()))
}