ed25519_dalek_bip32/
lib.rs

1//! A simple BIP32 implementation for ed25519 public keys. Although there exists [another very good
2//! library that does this](https://docs.rs/ed25519-bip32), this library preserves 32 byte secret
3//! keys and doesn't allow for extended public keys or "normal" child indexes, so that it can be as
4//! close to the BIP32 specifications as possible, allowing for compatibility with libraries like
5//! `trezor-crypto`
6
7#![cfg_attr(not(feature = "std"), no_std)]
8
9pub extern crate derivation_path;
10pub extern crate ed25519_dalek;
11
12pub use derivation_path::{ChildIndex, DerivationPath};
13pub use ed25519_dalek::{SigningKey, VerifyingKey};
14
15use core::fmt;
16use hmac::{Hmac, Mac};
17use sha2::Sha512;
18
19const ED25519_BIP32_NAME: &str = "ed25519 seed";
20
21/// Errors thrown while deriving secret keys
22#[derive(Debug)]
23pub enum Error {
24    Ed25519,
25    ExpectedHardenedIndex(ChildIndex),
26}
27
28impl fmt::Display for Error {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            Self::Ed25519 => f.write_str("ed25519 error"),
32            Self::ExpectedHardenedIndex(index) => {
33                f.write_fmt(format_args!("expected hardened child index: {}", index))
34            }
35        }
36    }
37}
38
39#[cfg(feature = "std")]
40impl std::error::Error for Error {}
41
42/// An expanded secret key with chain code and meta data
43#[derive(Debug)]
44pub struct ExtendedSigningKey {
45    /// How many derivations this key is from the root (0 for root)
46    pub depth: u8,
47    /// Child index of the key used to derive from parent (`Normal(0)` for root)
48    pub child_index: ChildIndex,
49    /// Signing Key
50    pub signing_key: SigningKey,
51    /// Chain code
52    pub chain_code: [u8; 32],
53}
54
55type HmacSha512 = Hmac<Sha512>;
56
57/// A convenience wrapper for a [`core::result::Result`] with an [`Error`]
58pub type Result<T, E = Error> = core::result::Result<T, E>;
59
60impl ExtendedSigningKey {
61    /// Create a new extended secret key from a seed
62    pub fn from_seed(seed: &[u8]) -> Result<Self> {
63        let mut mac = HmacSha512::new_from_slice(ED25519_BIP32_NAME.as_ref()).unwrap();
64        mac.update(seed);
65        let bytes = mac.finalize().into_bytes();
66
67        let secret_key_bytes: [u8; 32] = bytes[0..32].try_into().unwrap();
68        let signing_key = SigningKey::from_bytes(&secret_key_bytes);
69
70        let mut chain_code = [0; 32];
71        chain_code.copy_from_slice(&bytes[32..]);
72
73        Ok(Self {
74            depth: 0,
75            child_index: ChildIndex::Normal(0),
76            signing_key,
77            chain_code,
78        })
79    }
80
81    /// Derive an extended secret key fom the current using a derivation path
82    pub fn derive<P: AsRef<[ChildIndex]>>(&self, path: &P) -> Result<Self> {
83        let mut path = path.as_ref().iter();
84        let mut next = match path.next() {
85            Some(index) => self.derive_child(*index)?,
86            None => self.clone(),
87        };
88        for index in path {
89            next = next.derive_child(*index)?;
90        }
91        Ok(next)
92    }
93
94    /// Derive a child extended secret key with an index
95    pub fn derive_child(&self, index: ChildIndex) -> Result<Self> {
96        if index.is_normal() {
97            return Err(Error::ExpectedHardenedIndex(index));
98        }
99
100        let mut mac = HmacSha512::new_from_slice(&self.chain_code).unwrap();
101        mac.update(&[0u8]);
102        mac.update(self.signing_key.to_bytes().as_ref());
103        mac.update(index.to_bits().to_be_bytes().as_ref());
104        let bytes = mac.finalize().into_bytes();
105
106        let secret_key_bytes: [u8; 32] = bytes[0..32].try_into().unwrap();
107        let signing_key = SigningKey::from_bytes(&secret_key_bytes);
108
109        let mut chain_code = [0; 32];
110        chain_code.copy_from_slice(&bytes[32..]);
111
112        Ok(Self {
113            depth: self.depth + 1,
114            child_index: index,
115            signing_key,
116            chain_code,
117        })
118    }
119
120    /// Get the associated verifying key
121    #[inline]
122    pub fn verifying_key(&self) -> VerifyingKey {
123        self.signing_key.verifying_key()
124    }
125
126    #[inline]
127    fn clone(&self) -> Self {
128        Self {
129            depth: self.depth,
130            child_index: self.child_index,
131            signing_key: SigningKey::from_bytes(&self.signing_key.to_bytes()),
132            chain_code: self.chain_code,
133        }
134    }
135}
136
137impl From<ed25519_dalek::SignatureError> for Error {
138    fn from(_: ed25519_dalek::SignatureError) -> Self {
139        Self::Ed25519
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    extern crate alloc;
148    use alloc::vec::Vec;
149    use hex::FromHex;
150
151    fn hex_str(string: &str) -> Vec<u8> {
152        hex::decode(string).unwrap()
153    }
154
155    fn key_hex_str(input_str: &str) -> [u8; 32] {
156        <[u8; 32]>::from_hex(input_str).expect("Failed to convert Hex Str into Key")
157    }
158
159    fn root(seed: &str) -> ExtendedSigningKey {
160        ExtendedSigningKey::from_seed(&hex_str(seed)).unwrap()
161    }
162
163    #[test]
164    fn derivation_path() {
165        let vector1_path: DerivationPath = "m/0'/1'/2'/2'/1000000000'".parse().unwrap();
166        let vector2_path: DerivationPath = "m/0'/2147483647'/1'/2147483646'/2'".parse().unwrap();
167
168        let node = root("000102030405060708090a0b0c0d0e0f")
169            .derive(&vector1_path)
170            .unwrap();
171        assert_eq!(node.depth, 5);
172        assert_eq!(node.child_index, ChildIndex::Hardened(1000000000));
173        assert_eq!(
174            node.chain_code.as_ref(),
175            hex_str("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230")
176        );
177        let secret = SigningKey::from_bytes(&key_hex_str(
178            "8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793",
179        ));
180
181        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
182        let public = VerifyingKey::from_bytes(&key_hex_str(
183            "3c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a",
184        ))
185        .unwrap();
186        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
187
188        let node = root("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542").derive(&vector2_path).unwrap();
189        assert_eq!(node.depth, 5);
190        assert_eq!(node.child_index, ChildIndex::Hardened(2));
191        assert_eq!(
192            node.chain_code.as_ref(),
193            hex_str("5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4")
194        );
195        let secret = SigningKey::from_bytes(&key_hex_str(
196            "551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d",
197        ));
198
199        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
200        let public = VerifyingKey::from_bytes(&key_hex_str(
201            "47150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0",
202        ))
203        .unwrap();
204        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
205    }
206
207    #[test]
208    fn normal_errs() {
209        let node = root("000102030405060708090a0b0c0d0e0f");
210
211        let res = node.derive_child(ChildIndex::Normal(0));
212        assert!(matches!(
213            res,
214            Err(Error::ExpectedHardenedIndex(ChildIndex::Normal(0)))
215        ));
216
217        let res = node.derive_child(ChildIndex::Normal(100000));
218        assert!(matches!(
219            res,
220            Err(Error::ExpectedHardenedIndex(ChildIndex::Normal(100000)))
221        ));
222
223        let soft_path: DerivationPath = "m/0'/1'/2'/3/4'".parse().unwrap();
224        let res = node.derive(&soft_path);
225        assert!(matches!(
226            res,
227            Err(Error::ExpectedHardenedIndex(ChildIndex::Normal(3)))
228        ));
229    }
230
231    #[test]
232    fn vector1() {
233        // Chain m
234        let node = root("000102030405060708090a0b0c0d0e0f");
235        assert_eq!(node.depth, 0);
236        assert_eq!(node.child_index, ChildIndex::Normal(0));
237        assert_eq!(
238            node.chain_code.as_ref(),
239            hex_str("90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb")
240        );
241        let secret = SigningKey::from_bytes(&key_hex_str(
242            "2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7",
243        ));
244        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
245        let public = VerifyingKey::from_bytes(&key_hex_str(
246            "a4b2856bfec510abab89753fac1ac0e1112364e7d250545963f135f2a33188ed",
247        ))
248        .unwrap();
249        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
250
251        // Chain m/0'
252        let node = node.derive_child(ChildIndex::Hardened(0)).unwrap();
253        assert_eq!(node.depth, 1);
254        assert_eq!(node.child_index, ChildIndex::Hardened(0));
255        assert_eq!(
256            node.chain_code.as_ref(),
257            hex_str("8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69")
258        );
259        let secret = SigningKey::from_bytes(&key_hex_str(
260            "68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3",
261        ));
262        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
263        let public = VerifyingKey::from_bytes(&key_hex_str(
264            "8c8a13df77a28f3445213a0f432fde644acaa215fc72dcdf300d5efaa85d350c",
265        ))
266        .unwrap();
267        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
268
269        // Chain m/0'/1'
270        let node = node.derive_child(ChildIndex::Hardened(1)).unwrap();
271        assert_eq!(node.depth, 2);
272        assert_eq!(node.child_index, ChildIndex::Hardened(1));
273        assert_eq!(
274            node.chain_code.as_ref(),
275            hex_str("a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14")
276        );
277        let secret = SigningKey::from_bytes(&key_hex_str(
278            "b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2",
279        ));
280        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
281        let public = VerifyingKey::from_bytes(&key_hex_str(
282            "1932a5270f335bed617d5b935c80aedb1a35bd9fc1e31acafd5372c30f5c1187",
283        ))
284        .unwrap();
285        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
286
287        // Chain m/0'/1'/2'
288        let node = node.derive_child(ChildIndex::Hardened(2)).unwrap();
289        assert_eq!(node.depth, 3);
290        assert_eq!(node.child_index, ChildIndex::Hardened(2));
291        assert_eq!(
292            node.chain_code.as_ref(),
293            hex_str("2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c")
294        );
295        let secret = SigningKey::from_bytes(&key_hex_str(
296            "92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9",
297        ));
298        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
299        let public = VerifyingKey::from_bytes(&key_hex_str(
300            "ae98736566d30ed0e9d2f4486a64bc95740d89c7db33f52121f8ea8f76ff0fc1",
301        ))
302        .unwrap();
303        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
304
305        // Chain m/0'/1'/2'/2'
306        let node = node.derive_child(ChildIndex::Hardened(2)).unwrap();
307        assert_eq!(node.depth, 4);
308        assert_eq!(node.child_index, ChildIndex::Hardened(2));
309        assert_eq!(
310            node.chain_code.as_ref(),
311            hex_str("8f6d87f93d750e0efccda017d662a1b31a266e4a6f5993b15f5c1f07f74dd5cc")
312        );
313        let secret = SigningKey::from_bytes(&key_hex_str(
314            "30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662",
315        ));
316        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
317        let public = VerifyingKey::from_bytes(&key_hex_str(
318            "8abae2d66361c879b900d204ad2cc4984fa2aa344dd7ddc46007329ac76c429c",
319        ))
320        .unwrap();
321        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
322
323        // Chain m/0'/1'/2'/2'/1000000000'
324        let node = node.derive_child(ChildIndex::Hardened(1000000000)).unwrap();
325        assert_eq!(node.depth, 5);
326        assert_eq!(node.child_index, ChildIndex::Hardened(1000000000));
327        assert_eq!(
328            node.chain_code.as_ref(),
329            hex_str("68789923a0cac2cd5a29172a475fe9e0fb14cd6adb5ad98a3fa70333e7afa230")
330        );
331        let secret = SigningKey::from_bytes(&key_hex_str(
332            "8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793",
333        ));
334        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
335        let public = VerifyingKey::from_bytes(&key_hex_str(
336            "3c24da049451555d51a7014a37337aa4e12d41e485abccfa46b47dfb2af54b7a",
337        ))
338        .unwrap();
339        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
340    }
341
342    #[test]
343    fn vector2() {
344        // Chain m
345        let node = root("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542");
346        assert_eq!(node.depth, 0);
347        assert_eq!(node.child_index, ChildIndex::Normal(0));
348        assert_eq!(
349            node.chain_code.as_ref(),
350            hex_str("ef70a74db9c3a5af931b5fe73ed8e1a53464133654fd55e7a66f8570b8e33c3b")
351        );
352        let secret = SigningKey::from_bytes(&key_hex_str(
353            "171cb88b1b3c1db25add599712e36245d75bc65a1a5c9e18d76f9f2b1eab4012",
354        ));
355        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
356        let public = VerifyingKey::from_bytes(&key_hex_str(
357            "8fe9693f8fa62a4305a140b9764c5ee01e455963744fe18204b4fb948249308a",
358        ))
359        .unwrap();
360        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
361
362        // Chain m/0'
363        let node = node.derive_child(ChildIndex::Hardened(0)).unwrap();
364        assert_eq!(node.depth, 1);
365        assert_eq!(node.child_index, ChildIndex::Hardened(0));
366        assert_eq!(
367            node.chain_code.as_ref(),
368            hex_str("0b78a3226f915c082bf118f83618a618ab6dec793752624cbeb622acb562862d")
369        );
370        let secret = SigningKey::from_bytes(&key_hex_str(
371            "1559eb2bbec5790b0c65d8693e4d0875b1747f4970ae8b650486ed7470845635",
372        ));
373        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
374        let public = VerifyingKey::from_bytes(&key_hex_str(
375            "86fab68dcb57aa196c77c5f264f215a112c22a912c10d123b0d03c3c28ef1037",
376        ))
377        .unwrap();
378        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
379
380        // Chain m/0'/2147483647'
381        let node = node.derive_child(ChildIndex::Hardened(2147483647)).unwrap();
382        assert_eq!(node.depth, 2);
383        assert_eq!(node.child_index, ChildIndex::Hardened(2147483647));
384        assert_eq!(
385            node.chain_code.as_ref(),
386            hex_str("138f0b2551bcafeca6ff2aa88ba8ed0ed8de070841f0c4ef0165df8181eaad7f")
387        );
388        let secret = SigningKey::from_bytes(&key_hex_str(
389            "ea4f5bfe8694d8bb74b7b59404632fd5968b774ed545e810de9c32a4fb4192f4",
390        ));
391        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
392        let public = VerifyingKey::from_bytes(&key_hex_str(
393            "5ba3b9ac6e90e83effcd25ac4e58a1365a9e35a3d3ae5eb07b9e4d90bcf7506d",
394        ))
395        .unwrap();
396        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
397
398        // Chain m/0'/2147483647'/1'
399        let node = node.derive_child(ChildIndex::Hardened(1)).unwrap();
400        assert_eq!(node.depth, 3);
401        assert_eq!(node.child_index, ChildIndex::Hardened(1));
402        assert_eq!(
403            node.chain_code.as_ref(),
404            hex_str("73bd9fff1cfbde33a1b846c27085f711c0fe2d66fd32e139d3ebc28e5a4a6b90")
405        );
406        let secret = SigningKey::from_bytes(&key_hex_str(
407            "3757c7577170179c7868353ada796c839135b3d30554bbb74a4b1e4a5a58505c",
408        ));
409        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
410        let public = VerifyingKey::from_bytes(&key_hex_str(
411            "2e66aa57069c86cc18249aecf5cb5a9cebbfd6fadeab056254763874a9352b45",
412        ))
413        .unwrap();
414        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
415
416        // Chain m/0'/2147483647'/1'/2147483646'
417        let node = node.derive_child(ChildIndex::Hardened(2147483646)).unwrap();
418        assert_eq!(node.depth, 4);
419        assert_eq!(node.child_index, ChildIndex::Hardened(2147483646));
420        assert_eq!(
421            node.chain_code.as_ref(),
422            hex_str("0902fe8a29f9140480a00ef244bd183e8a13288e4412d8389d140aac1794825a")
423        );
424        let secret = SigningKey::from_bytes(&key_hex_str(
425            "5837736c89570de861ebc173b1086da4f505d4adb387c6a1b1342d5e4ac9ec72",
426        ));
427        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
428        let public = VerifyingKey::from_bytes(&key_hex_str(
429            "e33c0f7d81d843c572275f287498e8d408654fdf0d1e065b84e2e6f157aab09b",
430        ))
431        .unwrap();
432        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
433
434        // Chain m/0'/2147483647'/1'/2147483646'/2'
435        let node = node.derive_child(ChildIndex::Hardened(2)).unwrap();
436        assert_eq!(node.depth, 5);
437        assert_eq!(node.child_index, ChildIndex::Hardened(2));
438        assert_eq!(
439            node.chain_code.as_ref(),
440            hex_str("5d70af781f3a37b829f0d060924d5e960bdc02e85423494afc0b1a41bbe196d4")
441        );
442        let secret = SigningKey::from_bytes(&key_hex_str(
443            "551d333177df541ad876a60ea71f00447931c0a9da16f227c11ea080d7391b8d",
444        ));
445        assert_eq!(node.signing_key.to_bytes(), secret.to_bytes());
446        let public = VerifyingKey::from_bytes(&key_hex_str(
447            "47150c75db263559a70d5778bf36abbab30fb061ad69f69ece61a72b0cfa4fc0",
448        ))
449        .unwrap();
450        assert_eq!(node.verifying_key().to_bytes(), public.to_bytes());
451    }
452}