1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::{
fmt,
fmt::{Debug, Display},
str::FromStr,
};
pub trait DerivationPath: Clone + Debug + Display + FromStr + Send + Sync + 'static + Eq + Sized {}
#[derive(Debug, Fail, PartialEq, Eq)]
pub enum DerivationPathError {
#[fail(display = "expected BIP44 path")]
ExpectedBIP44Path,
#[fail(display = "expected hardened path")]
ExpectedHardenedPath,
#[fail(display = "expected normal path")]
ExpectedNormalPath,
#[fail(display = "invalid child number: {}", _0)]
InvalidChildNumber(u32),
#[fail(display = "invalid child number format")]
InvalidChildNumberFormat,
#[fail(display = "invalid derivation path: {}", _0)]
InvalidDerivationPath(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ChildIndex {
Normal(u32),
Hardened(u32),
}
impl ChildIndex {
pub fn from_normal(index: u32) -> Result<Self, DerivationPathError> {
if index & (1 << 31) == 0 {
Ok(ChildIndex::Normal(index))
} else {
Err(DerivationPathError::InvalidChildNumber(index))
}
}
pub fn from_hardened(index: u32) -> Result<Self, DerivationPathError> {
if index & (1 << 31) == 0 {
Ok(ChildIndex::Hardened(index))
} else {
Err(DerivationPathError::InvalidChildNumber(index))
}
}
pub fn is_normal(&self) -> bool {
!self.is_hardened()
}
pub fn is_hardened(&self) -> bool {
match *self {
ChildIndex::Hardened(_) => true,
ChildIndex::Normal(_) => false,
}
}
pub fn to_index(&self) -> u32 {
match self {
&ChildIndex::Hardened(i) => i + (1 << 31),
&ChildIndex::Normal(i) => i,
}
}
}
impl From<u32> for ChildIndex {
fn from(number: u32) -> Self {
if number & (1 << 31) != 0 {
ChildIndex::Hardened(number ^ (1 << 31))
} else {
ChildIndex::Normal(number)
}
}
}
impl From<ChildIndex> for u32 {
fn from(index: ChildIndex) -> Self {
match index {
ChildIndex::Normal(number) => number,
ChildIndex::Hardened(number) => number | (1 << 31),
}
}
}
impl FromStr for ChildIndex {
type Err = DerivationPathError;
fn from_str(inp: &str) -> Result<Self, Self::Err> {
Ok(match inp.chars().last().map_or(false, |l| l == '\'' || l == 'h') {
true => Self::from_hardened(
inp[0..inp.len() - 1]
.parse()
.map_err(|_| DerivationPathError::InvalidChildNumberFormat)?,
)?,
false => Self::from_normal(inp.parse().map_err(|_| DerivationPathError::InvalidChildNumberFormat)?)?,
})
}
}
impl fmt::Display for ChildIndex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ChildIndex::Hardened(number) => write!(f, "{}'", number),
ChildIndex::Normal(number) => write!(f, "{}", number),
}
}
}