nam_tiny_hderive/
bip44.rs

1use super::Error;
2
3use std::ops::Deref;
4use std::str::FromStr;
5
6const HARDENED_BIT: u32 = 1 << 31;
7
8/// A child number for a derived key
9#[derive(Copy, Clone, PartialEq, Eq, Debug)]
10pub struct ChildNumber(u32);
11
12impl ChildNumber {
13    pub fn is_hardened(&self) -> bool {
14        self.0 & HARDENED_BIT == HARDENED_BIT
15    }
16
17    pub fn is_normal(&self) -> bool {
18        self.0 & HARDENED_BIT == 0
19    }
20
21    pub fn to_bytes(&self) -> [u8; 4] {
22        self.0.to_be_bytes()
23    }
24
25    pub fn hardened_from_u32(index: u32) -> Self {
26        ChildNumber(index | HARDENED_BIT)
27    }
28
29    pub fn non_hardened_from_u32(index: u32) -> Self {
30        ChildNumber(index)
31    }
32}
33
34impl FromStr for ChildNumber {
35    type Err = Error;
36
37    fn from_str(child: &str) -> Result<ChildNumber, Error> {
38        let (child, mask) = if let Some(child) = child.strip_suffix('\'') {
39            (child, HARDENED_BIT)
40        } else {
41            (child, 0)
42        };
43
44        let index: u32 = child.parse().map_err(|_| Error::InvalidChildNumber)?;
45
46        if index & HARDENED_BIT == 0 {
47            Ok(ChildNumber(index | mask))
48        } else {
49            Err(Error::InvalidChildNumber)
50        }
51    }
52}
53
54#[derive(Clone, PartialEq, Eq, Debug, Default)]
55pub struct DerivationPath {
56    path: Vec<ChildNumber>,
57}
58
59impl FromStr for DerivationPath {
60    type Err = Error;
61
62    fn from_str(path: &str) -> Result<DerivationPath, Error> {
63        let mut path = path.split('/');
64
65        if path.next() != Some("m") {
66            return Err(Error::InvalidDerivationPath);
67        }
68
69        Ok(DerivationPath {
70            path: path
71                .map(str::parse)
72                .collect::<Result<Vec<ChildNumber>, Error>>()?,
73        })
74    }
75}
76
77impl Deref for DerivationPath {
78    type Target = [ChildNumber];
79
80    fn deref(&self) -> &Self::Target {
81        &self.path
82    }
83}
84
85impl<T> AsRef<T> for DerivationPath
86where
87    T: ?Sized,
88    <DerivationPath as Deref>::Target: AsRef<T>,
89{
90    fn as_ref(&self) -> &T {
91        self.deref().as_ref()
92    }
93}
94
95impl DerivationPath {
96    pub fn iter(&self) -> impl Iterator<Item = &ChildNumber> {
97        self.path.iter()
98    }
99}
100
101pub trait IntoDerivationPath {
102    fn into(self) -> Result<DerivationPath, Error>;
103}
104
105impl IntoDerivationPath for DerivationPath {
106    fn into(self) -> Result<DerivationPath, Error> {
107        Ok(self)
108    }
109}
110
111impl IntoDerivationPath for &str {
112    fn into(self) -> Result<DerivationPath, Error> {
113        self.parse()
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn derive_path() {
123        let path: DerivationPath = "m/44'/60'/0'/0".parse().unwrap();
124
125        assert_eq!(
126            path,
127            DerivationPath {
128                path: vec![
129                    ChildNumber(44 | HARDENED_BIT),
130                    ChildNumber(60 | HARDENED_BIT),
131                    ChildNumber(0 | HARDENED_BIT),
132                    ChildNumber(0),
133                ],
134            }
135        );
136    }
137}