1use crate::keys::slip10::{self, Segment};
5
6#[cfg(feature = "ed25519")]
7pub mod ed25519 {
8 use super::*;
9 use crate::signatures::ed25519;
10
11 impl slip10::ToChain<Bip44> for ed25519::SecretKey {
12 type Chain = [slip10::Hardened; 5];
13 fn to_chain(bip44_chain: &Bip44) -> [slip10::Hardened; 5] {
14 [
15 Bip44::PURPOSE.harden(),
16 bip44_chain.coin_type.harden(),
17 bip44_chain.account.harden(),
18 bip44_chain.change.harden(),
19 bip44_chain.address_index.harden(),
20 ]
21 }
22 }
23}
24
25#[cfg(feature = "secp256k1")]
26pub mod secp256k1 {
27 use super::*;
28 use crate::signatures::secp256k1_ecdsa;
29
30 impl slip10::ToChain<Bip44> for secp256k1_ecdsa::SecretKey {
31 type Chain = [u32; 5];
32 fn to_chain(bip44_chain: &Bip44) -> [u32; 5] {
33 [
34 Bip44::PURPOSE.harden().into(),
35 bip44_chain.coin_type.harden().into(),
36 bip44_chain.account.harden().into(),
37 bip44_chain.change,
38 bip44_chain.address_index,
39 ]
40 }
41 }
42}
43
44#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53pub struct Bip44 {
54 pub coin_type: u32,
55 pub account: u32,
56 pub change: u32,
57 pub address_index: u32,
58}
59
60impl Bip44 {
61 pub const PURPOSE: u32 = 44;
62
63 pub fn new(coin_type: u32) -> Self {
64 Self {
65 coin_type,
66 account: 0,
67 change: 0,
68 address_index: 0,
69 }
70 }
71
72 pub fn with_coin_type(mut self, s: u32) -> Self {
73 self.coin_type = s;
74 self
75 }
76
77 pub fn with_account(mut self, s: u32) -> Self {
78 self.account = s;
79 self
80 }
81
82 pub fn with_change(mut self, s: u32) -> Self {
83 self.change = s;
84 self
85 }
86
87 pub fn with_address_index(mut self, s: u32) -> Self {
88 self.address_index = s;
89 self
90 }
91
92 pub fn to_chain<K: slip10::ToChain<Self>>(&self) -> <K as slip10::ToChain<Self>>::Chain {
93 K::to_chain(self)
94 }
95
96 pub fn derive<K>(&self, mk: &slip10::Slip10<K>) -> slip10::Slip10<K>
97 where
98 K: slip10::Derivable
99 + slip10::WithSegment<<<K as slip10::ToChain<Bip44>>::Chain as IntoIterator>::Item>
100 + slip10::ToChain<Bip44>,
101 <K as slip10::ToChain<Bip44>>::Chain: IntoIterator,
102 <<K as slip10::ToChain<Bip44>>::Chain as IntoIterator>::Item: Segment,
103 {
104 mk.derive(self.to_chain::<K>().into_iter())
105 }
106
107 pub fn derive_from_seed<K, S>(&self, seed: &S) -> slip10::Slip10<K>
108 where
109 K: slip10::IsSecretKey
110 + slip10::WithSegment<<<K as slip10::ToChain<Bip44>>::Chain as IntoIterator>::Item>
111 + slip10::ToChain<Bip44>,
112 <K as slip10::ToChain<Bip44>>::Chain: IntoIterator,
113 <<K as slip10::ToChain<Bip44>>::Chain as IntoIterator>::Item: Segment,
114 S: AsRef<[u8]>,
115 {
116 self.derive(&slip10::Slip10::from_seed(seed))
117 }
118
119 pub fn derive_address_range<K, S>(
130 &self,
131 m: &slip10::Slip10<K>,
132 address_count: usize,
133 ) -> impl ExactSizeIterator<Item = slip10::Slip10<K>>
134 where
135 K: slip10::Derivable + slip10::WithSegment<S> + slip10::ToChain<Bip44, Chain = [S; 5]>,
136 S: Segment + TryFrom<u32>,
137 <S as TryFrom<u32>>::Error: core::fmt::Debug,
138 {
139 let chain: [_; 5] = self.to_chain::<K>();
140
141 let address_count = core::cmp::min(1 << 31, address_count) as u32;
143
144 let address_start = chain[4];
146 let hardening_bit: u32 = address_start.into() & slip10::HARDEN_MASK;
147 let unhardened_start: u32 = address_start.unharden().into();
149 let unhardened_end: u32 = core::cmp::min(1_u32 << 31, unhardened_start + address_count);
151
152 let child_segments = (unhardened_start..unhardened_end).map(move |unhardened_address_index| -> S {
154 let address_index = hardening_bit | unhardened_address_index;
155 address_index.try_into().unwrap()
158 });
159
160 let mk = if child_segments.len() > 0 {
161 m.derive(chain[..4].iter().copied())
162 } else {
163 slip10::Slip10::new()
165 };
166 mk.children(child_segments)
167 }
168}
169
170#[derive(Clone, Copy, Debug, Eq, PartialEq)]
171#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
172pub struct BadPurpose;
173
174impl From<BadPurpose> for crate::Error {
175 fn from(inner: BadPurpose) -> Self {
176 crate::Error::Bip44Error(inner)
177 }
178}
179
180impl TryFrom<[u32; 5]> for Bip44 {
181 type Error = BadPurpose;
182 fn try_from(segments: [u32; 5]) -> Result<Self, Self::Error> {
183 if let [Bip44::PURPOSE, coin_type, account, change, address_index] = segments {
184 Ok(Self {
185 coin_type,
186 account,
187 change,
188 address_index,
189 })
190 } else {
191 Err(BadPurpose)
192 }
193 }
194}
195
196impl From<[u32; 4]> for Bip44 {
197 fn from(segments: [u32; 4]) -> Self {
198 let [coin_type, account, change, address_index] = segments;
199 Self {
200 coin_type,
201 account,
202 change,
203 address_index,
204 }
205 }
206}
207
208impl From<&Bip44> for [u32; 5] {
209 fn from(bip44_chain: &Bip44) -> [u32; 5] {
210 [
211 Bip44::PURPOSE,
212 bip44_chain.coin_type,
213 bip44_chain.account,
214 bip44_chain.change,
215 bip44_chain.address_index,
216 ]
217 }
218}
219
220impl IntoIterator for Bip44 {
221 type Item = u32;
222 type IntoIter = core::array::IntoIter<u32, 5>;
223 fn into_iter(self) -> Self::IntoIter {
224 <[u32; 5]>::from(&self).into_iter()
225 }
226}