use generic_ec::{curves, Point, Scalar};
use hmac::Mac;
use crate::{
DeriveShift, DerivedShift, ExtendedKeyPair, ExtendedPublicKey, HardenedIndex, NonHardenedIndex,
};
type HmacSha512 = hmac::Hmac<sha2::Sha512>;
pub struct Stark;
impl DeriveShift<curves::Stark> for Stark {
fn derive_public_shift(
parent_public_key: &ExtendedPublicKey<curves::Stark>,
child_index: NonHardenedIndex,
) -> DerivedShift<curves::Stark> {
let hmac = HmacSha512::new_from_slice(&parent_public_key.chain_code)
.expect("this never fails: hmac can handle keys of any size");
let i0 = hmac
.clone()
.chain_update([0x00])
.chain_update(parent_public_key.public_key.to_bytes(true))
.chain_update(child_index.to_be_bytes())
.finalize()
.into_bytes();
let i1 = hmac
.chain_update([0x01])
.chain_update(parent_public_key.public_key.to_bytes(true))
.chain_update(child_index.to_be_bytes())
.finalize()
.into_bytes();
Self::calculate_shift(parent_public_key, i0, i1)
}
fn derive_hardened_shift(
parent_key: &ExtendedKeyPair<curves::Stark>,
child_index: HardenedIndex,
) -> DerivedShift<curves::Stark> {
let hmac = HmacSha512::new_from_slice(parent_key.chain_code())
.expect("this never fails: hmac can handle keys of any size");
let i0 = hmac
.clone()
.chain_update([0x00])
.chain_update([0x00])
.chain_update(parent_key.secret_key.secret_key.as_ref().to_be_bytes())
.chain_update(child_index.to_be_bytes())
.finalize()
.into_bytes();
let i1 = hmac
.chain_update([0x01])
.chain_update([0x00])
.chain_update(parent_key.secret_key.secret_key.as_ref().to_be_bytes())
.chain_update(child_index.to_be_bytes())
.finalize()
.into_bytes();
Self::calculate_shift(&parent_key.public_key, i0, i1)
}
}
impl Stark {
fn calculate_shift(
parent_public_key: &ExtendedPublicKey<curves::Stark>,
i0: hmac::digest::Output<HmacSha512>,
i1: hmac::digest::Output<HmacSha512>,
) -> DerivedShift<curves::Stark> {
let i = generic_array::sequence::Concat::concat(i0, i1);
let (shift, chain_code) = split(&i);
let shift = Scalar::from_be_bytes_mod_order(shift);
let child_pk = parent_public_key.public_key + Point::generator() * shift;
DerivedShift {
shift,
child_public_key: ExtendedPublicKey {
public_key: child_pk,
chain_code: (*chain_code).into(),
},
}
}
}
fn split(
i: &generic_array::GenericArray<u8, generic_array::typenum::U128>,
) -> (
&generic_array::GenericArray<u8, generic_array::typenum::U96>,
&generic_array::GenericArray<u8, generic_array::typenum::U32>,
) {
generic_array::sequence::Split::split(i)
}
super::create_aliases!(Stark, stark, hd_wallet::curves::Stark);