#![no_std]
extern crate alloc;
pub mod path;
pub use crate::path::BIP32Path;
use alloc::vec::Vec;
use core::convert::TryInto;
use core::fmt;
use ed25519_dalek::{PublicKey, SecretKey};
use hmac::{crypto_mac::Output, Hmac, Mac, NewMac};
use sha2::Sha512;
pub(crate) const HARDEND: u32 = 1 << 31;
#[derive(Debug)]
pub enum Error {
InvalidIndex,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidIndex => "Invalid index provided".fmt(f),
}
}
}
type HmacSha256 = Hmac<Sha512>;
pub fn derive_key_from_path(seed: &[u8], curve: Curve, path: &BIP32Path) -> Result<Key, Error> {
let master: Result<Key, Error> = Ok(Key::new(seed, curve));
path.0.iter().fold(master, |key, index| match key {
Ok(k) => Ok(k.generate_child_key(*index)?),
Err(e) => Err(e),
})
}
#[derive(Clone, Copy, Debug)]
pub enum Curve {
Ed25519,
}
impl Curve {
fn seedkey(&self) -> &[u8] {
match self {
Curve::Ed25519 => b"ed25519 seed",
}
}
fn validate_child_index(&self, index: u32) -> bool {
match self {
Curve::Ed25519 => index < HARDEND,
}
}
fn public_key(&self, key: &[u8; 32]) -> Vec<u8> {
match self {
Curve::Ed25519 => {
let public: PublicKey = (&SecretKey::from_bytes(key).unwrap()).into();
let mut result = Vec::new();
result.push(0);
public.to_bytes().iter().for_each(|i| result.push(*i));
result
}
}
}
}
pub struct Key {
pub key: [u8; 32],
pub chain_code: [u8; 32],
pub curve: Curve,
}
impl Key {
pub fn new(seed: &[u8], curve: Curve) -> Self {
let inter = hmac_sha256(curve.seedkey(), seed).into_bytes();
let key: [u8; 32] = inter[..32].try_into().unwrap();
let chain_code: [u8; 32] = inter[32..].try_into().unwrap();
Self {
key,
chain_code,
curve,
}
}
pub fn public_key(&self) -> [u8; 33] {
let mut key = [0u8; 33];
key.copy_from_slice(&self.curve.public_key(&self.key));
key
}
fn generate_child_key(&self, index: u32) -> Result<Key, Error> {
if self.curve.validate_child_index(index) {
return Err(Error::InvalidIndex);
}
let inter = self.get_intermediary(index).into_bytes();
let key: [u8; 32] = inter[..32].try_into().unwrap();
let chain_code: [u8; 32] = inter[32..].try_into().unwrap();
Ok(Key {
key,
chain_code,
curve: self.curve,
})
}
fn get_intermediary(&self, index: u32) -> Output<HmacSha256> {
let mut data = Vec::new();
if index < HARDEND {
data.append(&mut self.curve.public_key(&self.key));
} else {
data.push(0u8);
self.key.iter().for_each(|i| data.push(*i));
}
index.to_be_bytes().iter().for_each(|i| data.push(*i));
hmac_sha256(&self.chain_code, &data)
}
}
fn hmac_sha256(key: &[u8], data: &[u8]) -> Output<HmacSha256> {
let mut mac = HmacSha256::new_varkey(key).expect("HMAC can take key of any size");
mac.update(data);
let result = mac.finalize();
result
}