use hmac::{Hmac, Mac};
use sha2::Sha512;
use zeroize::Zeroize;
mod private;
mod public;
pub use self::{private::ExtendedPrivateKey, public::ExtendedPublicKey};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct ExtendedKeyMetadata {
pub(crate) depth: u8,
pub(crate) parent_fingerprint: [u8; 4],
pub(crate) child_number: u32,
pub(crate) chain_code: [u8; 32],
}
impl Zeroize for ExtendedKeyMetadata {
fn zeroize(&mut self) {
self.depth = 0;
self.parent_fingerprint = [0u8; 4];
self.child_number = 0;
self.chain_code.zeroize();
}
}
impl Drop for ExtendedKeyMetadata {
fn drop(&mut self) {
self.zeroize();
}
}
pub(crate) fn key_fingerprint(public_key_bytes: &[u8]) -> [u8; 4] {
use sha2::Digest;
let hash = sha2::Sha256::digest(public_key_bytes);
let identifier = ripemd::Ripemd160::digest(hash);
let mut out = [0u8; 4];
out.copy_from_slice(&identifier[..4]);
out
}
pub(crate) fn derive_master_key_parts(seed: &[u8], domain: &[u8]) -> ([u8; 32], [u8; 32]) {
hmac_sha512_split(domain, |mac| mac.update(seed))
}
pub(crate) fn hmac_sha512_split(
key: &[u8],
f: impl FnOnce(&mut Hmac<Sha512>),
) -> ([u8; 32], [u8; 32]) {
let mut mac = Hmac::<Sha512>::new_from_slice(key)
.expect("HMAC-SHA512 must accept the provided key length");
f(&mut mac);
let output = mac.finalize().into_bytes();
debug_assert_eq!(output.len(), 64, "HMAC-SHA512 should produce a 64-byte output");
let mut left = [0u8; 32];
let mut right = [0u8; 32];
left.copy_from_slice(&output[..32]);
right.copy_from_slice(&output[32..]);
(left, right)
}