1use generic_ec::{curves, Point, Scalar};
10use hmac::Mac;
11
12use crate::{
13 DeriveShift, DerivedShift, ExtendedKeyPair, ExtendedPublicKey, HardenedIndex, NonHardenedIndex,
14};
15
16type HmacSha512 = hmac::Hmac<sha2::Sha512>;
17
18pub struct Edwards;
43
44impl DeriveShift<curves::Ed25519> for Edwards {
45 fn derive_public_shift(
46 parent_public_key: &ExtendedPublicKey<curves::Ed25519>,
47 child_index: NonHardenedIndex,
48 ) -> DerivedShift<curves::Ed25519> {
49 let hmac = HmacSha512::new_from_slice(&parent_public_key.chain_code)
50 .expect("this never fails: hmac can handle keys of any size");
51 let i = hmac
52 .chain_update(parent_public_key.public_key.to_bytes(true))
53 .chain_update([0x00])
55 .chain_update(child_index.to_be_bytes())
56 .finalize()
57 .into_bytes();
58 Self::calculate_shift(parent_public_key, i)
59 }
60
61 fn derive_hardened_shift(
62 parent_key: &ExtendedKeyPair<curves::Ed25519>,
63 child_index: HardenedIndex,
64 ) -> DerivedShift<curves::Ed25519> {
65 let hmac = HmacSha512::new_from_slice(parent_key.chain_code())
66 .expect("this never fails: hmac can handle keys of any size");
67 let i = hmac
68 .chain_update([0x00])
69 .chain_update(parent_key.secret_key.secret_key.as_ref().to_be_bytes())
70 .chain_update(child_index.to_be_bytes())
71 .finalize()
72 .into_bytes();
73 Self::calculate_shift(&parent_key.public_key, i)
74 }
75}
76
77impl Edwards {
78 fn calculate_shift(
79 parent_public_key: &ExtendedPublicKey<curves::Ed25519>,
80 i: hmac::digest::Output<HmacSha512>,
81 ) -> DerivedShift<curves::Ed25519> {
82 let (i_left, i_right) = split_into_two_halves(&i);
83
84 let shift = Scalar::from_be_bytes_mod_order(i_left);
85 let child_pk = parent_public_key.public_key + Point::generator() * shift;
86
87 DerivedShift {
88 shift,
89 child_public_key: ExtendedPublicKey {
90 public_key: child_pk,
91 chain_code: (*i_right).into(),
92 },
93 }
94 }
95}
96
97fn split_into_two_halves(
99 i: &generic_array::GenericArray<u8, generic_array::typenum::U64>,
100) -> (
101 &generic_array::GenericArray<u8, generic_array::typenum::U32>,
102 &generic_array::GenericArray<u8, generic_array::typenum::U32>,
103) {
104 generic_array::sequence::Split::split(i)
105}
106
107super::create_aliases!(Edwards, edwards, hd_wallet::curves::Ed25519);