1#[cfg(feature = "alloc")]
5use alloc::string::String;
6use core::num::NonZeroU32;
7
8use minicbor::{
9 bytes::DecodeBytes, data::Tag, data::Type, decode::Error, encode::Write, Decode, Decoder,
10 Encode, Encoder,
11};
12
13#[cfg(feature = "alloc")]
14use crate::registry::Keypath;
15use crate::registry::{CoinInfo, KeypathRef};
16
17#[doc(alias("hd-key"))]
19#[derive(Debug, Clone, PartialEq)]
20pub enum HDKeyRef<'a> {
21 MasterKey(MasterKey),
23 DerivedKey(DerivedKeyRef<'a>),
25}
26
27impl<'a> HDKeyRef<'a> {
28 pub const TAG: Tag = Tag::new(303);
30}
31
32#[cfg(feature = "bitcoin")]
33impl<'a> TryFrom<&'a bitcoin::bip32::Xpriv> for HDKeyRef<'a> {
34 type Error = InterpretExtendedKeyError;
35
36 fn try_from(xprv: &'a bitcoin::bip32::Xpriv) -> Result<Self, Self::Error> {
37 use crate::registry::CoinType;
38
39 if xprv.depth == 0 {
40 Ok(Self::MasterKey(MasterKey {
41 key_data: xprv.private_key.secret_bytes(),
42 chain_code: xprv.chain_code.to_bytes(),
43 }))
44 } else {
45 let mut key_data = [0u8; 33];
46 key_data[0] = 0;
47 key_data[1..].copy_from_slice(&xprv.private_key.secret_bytes());
48
49 Ok(Self::DerivedKey(DerivedKeyRef {
50 is_private: true,
51 key_data,
52 chain_code: Some(xprv.chain_code.to_bytes()),
53 use_info: Some(CoinInfo::new(
54 CoinType::BTC,
55 match xprv.network {
56 bitcoin::Network::Bitcoin => CoinInfo::NETWORK_MAINNET,
57 bitcoin::Network::Testnet => CoinInfo::NETWORK_BTC_TESTNET,
58 _ => return Err(InterpretExtendedKeyError),
59 },
60 )),
61 origin: None,
62 children: None,
63 parent_fingerprint: NonZeroU32::new(u32::from_be_bytes(
64 xprv.parent_fingerprint.to_bytes(),
65 )),
66 name: None,
67 note: None,
68 }))
69 }
70 }
71}
72
73#[cfg(feature = "bitcoin")]
74impl<'a> TryFrom<&'a bitcoin::bip32::Xpub> for HDKeyRef<'a> {
75 type Error = InterpretExtendedKeyError;
76
77 fn try_from(xpub: &'a bitcoin::bip32::Xpub) -> Result<Self, Self::Error> {
78 use crate::registry::CoinType;
79
80 Ok(Self::DerivedKey(DerivedKeyRef {
81 is_private: false,
82 key_data: xpub.public_key.serialize(),
83 chain_code: Some(xpub.chain_code.to_bytes()),
84 use_info: Some(CoinInfo::new(
85 CoinType::BTC,
86 match xpub.network {
87 bitcoin::Network::Bitcoin => CoinInfo::NETWORK_MAINNET,
88 bitcoin::Network::Testnet => CoinInfo::NETWORK_BTC_TESTNET,
89 _ => return Err(InterpretExtendedKeyError),
90 },
91 )),
92 origin: None,
93 children: None,
94 parent_fingerprint: NonZeroU32::new(u32::from_be_bytes(
95 xpub.parent_fingerprint.to_bytes(),
96 )),
97 name: None,
98 note: None,
99 }))
100 }
101}
102
103#[cfg(feature = "bitcoin")]
104#[derive(Debug)]
105pub struct InterpretExtendedKeyError;
106
107impl<'b, C> Decode<'b, C> for HDKeyRef<'b> {
108 fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Self, Error> {
109 if MasterKey::decode(&mut d.probe(), ctx).is_ok() {
110 return Ok(HDKeyRef::MasterKey(MasterKey::decode(d, ctx)?));
111 }
112
113 if DerivedKeyRef::decode(&mut d.probe(), ctx).is_ok() {
114 return Ok(HDKeyRef::DerivedKey(DerivedKeyRef::decode(d, ctx)?));
115 }
116
117 Err(Error::message(
118 "couldn't decode as master-key or derived-key",
119 ))
120 }
121}
122
123impl<'a, C> Encode<C> for HDKeyRef<'a> {
124 fn encode<W: Write>(
125 &self,
126 e: &mut Encoder<W>,
127 ctx: &mut C,
128 ) -> Result<(), minicbor::encode::Error<W::Error>> {
129 match self {
130 HDKeyRef::MasterKey(master_key) => master_key.encode(e, ctx),
131 HDKeyRef::DerivedKey(derived_key) => derived_key.encode(e, ctx),
132 }
133 }
134}
135
136#[doc(alias("hd-key"))]
138#[cfg(feature = "alloc")]
139#[derive(Debug, Clone, PartialEq)]
140pub enum HDKey {
141 MasterKey(MasterKey),
142 DerivedKey(DerivedKey),
143}
144
145#[cfg(feature = "alloc")]
146impl<'a> From<HDKeyRef<'a>> for HDKey {
147 fn from(hdkey: HDKeyRef<'a>) -> Self {
148 match hdkey {
149 HDKeyRef::MasterKey(m) => Self::MasterKey(m),
150 HDKeyRef::DerivedKey(d) => Self::DerivedKey(DerivedKey::from(d)),
151 }
152 }
153}
154
155#[cfg(feature = "alloc")]
156impl<'b, C> Decode<'b, C> for HDKey {
157 fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Self, Error> {
158 HDKeyRef::decode(d, ctx).map(HDKey::from)
159 }
160}
161
162#[doc(alias("master-key"))]
164#[derive(Debug, Clone, Eq, PartialEq)]
165pub struct MasterKey {
166 pub key_data: [u8; 32],
168 pub chain_code: [u8; 32],
170}
171
172impl<'b, C> Decode<'b, C> for MasterKey {
173 fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Self, Error> {
174 let mut is_master = None;
175 let mut key_data = None;
176 let mut chain_code = None;
177
178 let mut len = d.map()?;
179 loop {
180 match len {
181 Some(0) => break,
182 Some(n) => len = Some(n - 1),
183 None => {
184 if d.datatype()? == Type::Break {
185 break;
186 }
187 }
188 }
189
190 match d.u32()? {
191 1 => is_master = Some(d.bool()?),
192 3 => {
193 let mut data = [0; 32];
194
195 let bytes: [u8; 33] = DecodeBytes::decode_bytes(d, ctx)?;
196 data.copy_from_slice(&bytes[..32]);
197 key_data = Some(data)
198 }
199 4 => chain_code = Some(DecodeBytes::decode_bytes(d, ctx)?),
200 _ => return Err(Error::message("unknown map entry")),
201 }
202 }
203
204 match is_master {
205 Some(true) => (),
206 Some(false) => return Err(Error::message("is-master is false")),
207 None => return Err(Error::message("is-master is not present")),
208 }
209
210 Ok(Self {
211 key_data: key_data.ok_or_else(|| Error::message("key-data is not present"))?,
212 chain_code: chain_code.ok_or_else(|| Error::message("chain-code is not present"))?,
213 })
214 }
215}
216
217impl<C> Encode<C> for MasterKey {
218 fn encode<W: Write>(
219 &self,
220 e: &mut Encoder<W>,
221 _ctx: &mut C,
222 ) -> Result<(), minicbor::encode::Error<W::Error>> {
223 let mut key_data = [0; 33];
224 key_data[0] = 0;
225 key_data[1..].copy_from_slice(&self.key_data);
226
227 e.map(3)?
228 .u8(1)?
229 .bool(true)?
230 .u8(3)?
231 .bytes(&key_data)?
232 .u8(4)?
233 .bytes(&self.chain_code)?;
234
235 Ok(())
236 }
237}
238
239#[doc(alias("derived-key"))]
241#[derive(Debug, Clone, PartialEq)]
242pub struct DerivedKeyRef<'a> {
243 pub is_private: bool,
245 pub key_data: [u8; 33],
247 pub chain_code: Option<[u8; 32]>,
249 pub use_info: Option<CoinInfo>,
251 pub origin: Option<KeypathRef<'a>>,
253 pub children: Option<KeypathRef<'a>>,
255 pub parent_fingerprint: Option<NonZeroU32>,
257 pub name: Option<&'a str>,
259 pub note: Option<&'a str>,
261}
262
263impl<'b, C> Decode<'b, C> for DerivedKeyRef<'b> {
264 fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Self, Error> {
265 let mut is_private = false;
266 let mut key_data = None;
267 let mut chain_code = None;
268 let mut use_info = None;
269 let mut origin = None;
270 let mut children = None;
271 let mut parent_fingerprint = None;
272 let mut name = None;
273 let mut note = None;
274
275 let mut len = d.map()?;
276 loop {
277 match len {
278 Some(0) => break,
279 Some(n) => len = Some(n - 1),
280 None => {
281 if d.datatype()? == Type::Break {
282 break;
283 }
284 }
285 }
286
287 const TAGGED_COININFO: Tag = Tag::new(40305);
288 const TAGGED_KEYPATH: Tag = Tag::new(40304);
289
290 match d.u32()? {
291 2 => is_private = d.bool()?,
292 3 => key_data = Some(DecodeBytes::decode_bytes(d, ctx)?),
293 4 => chain_code = Some(DecodeBytes::decode_bytes(d, ctx)?),
294 5 => match d.tag()? {
295 TAGGED_COININFO => use_info = Some(CoinInfo::decode(d, ctx)?),
296 _ => return Err(Error::message("invalid tag for coininfo")),
297 },
298 6 => match d.tag()? {
299 TAGGED_KEYPATH => origin = Some(KeypathRef::decode(d, ctx)?),
300 _ => return Err(Error::message("invalid tag for keypath")),
301 },
302 7 => match d.tag()? {
303 TAGGED_KEYPATH => children = Some(KeypathRef::decode(d, ctx)?),
304 _ => return Err(Error::message("invalid tag for keypath")),
305 },
306 8 => {
307 parent_fingerprint = Some(
308 NonZeroU32::new(d.u32()?)
309 .ok_or_else(|| Error::message("parent-fingerprint is zero"))?,
310 )
311 }
312 9 => name = Some(d.str()?),
313 10 => note = Some(d.str()?),
314 _ => return Err(Error::message("unknown map entry")),
315 }
316 }
317
318 Ok(Self {
319 is_private,
320 key_data: key_data.ok_or_else(|| Error::message("key-data is not present"))?,
321 chain_code,
322 use_info,
323 origin,
324 children,
325 parent_fingerprint,
326 name,
327 note,
328 })
329 }
330}
331
332impl<'a, C> Encode<C> for DerivedKeyRef<'a> {
333 fn encode<W: Write>(
334 &self,
335 e: &mut Encoder<W>,
336 ctx: &mut C,
337 ) -> Result<(), minicbor::encode::Error<W::Error>> {
338 let len = self.is_private as u64
339 + 1
340 + self.chain_code.is_some() as u64
341 + self.use_info.is_some() as u64
342 + self.origin.is_some() as u64
343 + self.children.is_some() as u64
344 + self.parent_fingerprint.is_some() as u64
345 + self.name.is_some() as u64
346 + self.note.is_some() as u64;
347
348 e.map(len)?;
349
350 if self.is_private {
351 e.u8(2)?.bool(self.is_private)?;
352 }
353
354 e.u8(3)?.bytes(&self.key_data)?;
355
356 if let Some(ref chain_code) = self.chain_code {
357 e.u8(4)?.bytes(chain_code)?;
358 }
359
360 if let Some(ref use_info) = self.use_info {
361 e.u8(5)?.tag(Tag::new(40305))?;
362 use_info.encode(e, ctx)?;
363 }
364
365 if let Some(ref origin) = self.origin {
366 e.u8(6)?.tag(Tag::new(40304))?;
367 origin.encode(e, ctx)?;
368 }
369
370 if let Some(ref children) = self.children {
371 e.u8(7)?.tag(Tag::new(40304))?;
372 children.encode(e, ctx)?;
373 }
374
375 if let Some(parent_fingerprint) = self.parent_fingerprint {
376 e.u8(8)?.u32(parent_fingerprint.get())?;
377 }
378
379 if let Some(name) = self.name {
380 e.u8(9)?.str(name)?;
381 }
382
383 if let Some(note) = self.note {
384 e.u8(10)?.str(note)?;
385 }
386
387 Ok(())
388 }
389}
390
391#[doc(alias("derived-key"))]
393#[cfg(feature = "alloc")]
394#[derive(Debug, Clone, PartialEq)]
395pub struct DerivedKey {
396 pub is_private: bool,
398 pub key_data: [u8; 33],
400 pub chain_code: Option<[u8; 32]>,
402 pub use_info: Option<CoinInfo>,
404 pub origin: Option<Keypath>,
406 pub children: Option<Keypath>,
408 pub parent_fingerprint: Option<NonZeroU32>,
410 pub name: Option<String>,
412 pub note: Option<String>,
414}
415
416#[cfg(feature = "alloc")]
417impl<'a> From<DerivedKeyRef<'a>> for DerivedKey {
418 fn from(derived_key: DerivedKeyRef<'a>) -> Self {
419 Self {
420 is_private: derived_key.is_private,
421 key_data: derived_key.key_data,
422 chain_code: derived_key.chain_code,
423 use_info: derived_key.use_info,
424 origin: derived_key.origin.map(Keypath::from),
425 children: derived_key.children.map(Keypath::from),
426 parent_fingerprint: derived_key.parent_fingerprint,
427 name: derived_key.name.map(String::from),
428 note: derived_key.note.map(String::from),
429 }
430 }
431}