nam_tiny_hderive/
bip44.rs1use super::Error;
2
3use std::ops::Deref;
4use std::str::FromStr;
5
6const HARDENED_BIT: u32 = 1 << 31;
7
8#[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}