iop_keyvault/ed25519/
ext_sk.rs

1use super::*;
2
3/// Implementation of Ed25519::ExtendedPrivateKey
4#[derive(Clone)]
5pub struct EdExtPrivateKey {
6    chain_code: ChainCode,
7    sk: EdPrivateKey,
8}
9
10impl EdExtPrivateKey {
11    /// Borrows the chain code of the extended private key
12    pub fn chain_code(&self) -> &ChainCode {
13        &self.chain_code
14    }
15
16    pub(crate) fn cook_new<F: Fn(&mut HmacSha512)>(salt: &[u8], recipe: F) -> Self {
17        // This unwrap would only panic if the digest algorithm had some inconsistent
18        // generic parameters, but the SHA512 we use is consistent with itself
19        let mut hasher = <HmacSha512 as KeyInit>::new_from_slice(salt).unwrap();
20
21        recipe(&mut hasher);
22
23        let hash_bytes = hasher.finalize().into_bytes();
24
25        let sk_bytes = &hash_bytes[..PRIVATE_KEY_SIZE];
26        let cc_bytes = &hash_bytes[PRIVATE_KEY_SIZE..];
27
28        let chain_code = ChainCode::from_bytes(cc_bytes).unwrap();
29        let sk = EdPrivateKey::from_bytes(sk_bytes).unwrap();
30
31        Self { chain_code, sk }
32    }
33}
34
35impl ExtendedPrivateKey<Ed25519> for EdExtPrivateKey {
36    fn derive_normal_child(&self, _idx: i32) -> Result<EdExtPrivateKey> {
37        bail!("Normal derivation of Ed25519 is invalid based on SLIP-0010.")
38    }
39    /// There is a potential [vulnerability](https://forum.web3.foundation/t/key-recovery-attack-on-bip32-ed25519/44) in
40    /// that might affect all SLIP-0010 compatible Ed25519 wallets. We should never assume that there is only 1
41    /// public key that can verify a given signature. Actually, there are 8 public keys.
42    fn derive_hardened_child(&self, idx: i32) -> Result<EdExtPrivateKey> {
43        ensure!(idx >= 0, "Derivation index cannot be negative");
44        let idx = idx as u32;
45
46        let xprv = EdExtPrivateKey::cook_new(&self.chain_code.to_bytes(), |hasher| {
47            hasher.update(&[0x00u8]);
48            hasher.update(&self.sk.to_bytes());
49            hasher.update(&(0x8000_0000u32 + idx).to_be_bytes());
50        });
51
52        Ok(xprv)
53    }
54    fn neuter(&self) -> EdPublicKey {
55        self.sk.public_key()
56    }
57    fn private_key(&self) -> EdPrivateKey {
58        self.sk.clone()
59    }
60}