Skip to main content

emerald_hwkey/ledger/app/
mod.rs

1extern crate bitcoin as bitcoin_lib;
2
3use std::sync::{Arc, Mutex};
4use bitcoin_lib::{
5    NetworkKind,
6    bip32::{ChainCode, ChildNumber, Xpub, Fingerprint},
7    secp256k1::PublicKey
8};
9use hdpath::{CustomHDPath, HDPath, PathValue};
10use crate::{
11    errors::HWKeyError,
12    ledger::{
13        comm::LedgerTransport
14    }
15};
16
17// #[path="ethereum.rs"]
18pub mod ethereum;
19// #[path="bitcoin.rs"]
20pub mod bitcoin;
21
22pub use {
23    ethereum::EthereumApp,
24    bitcoin::BitcoinApp,
25};
26
27pub trait LedgerApp {
28    type Networks;
29
30    ///
31    /// Try to access a particular App on the Ledger.
32    /// Note that it's not guarantied that the app is actually launched, and it's even dangerous to try to use
33    /// commands specific for an app if it's not launched. Because same command may lead to different results with different apps
34    /// and sometimes Ledger may stuck (ex. waiting for some action that would never produced).
35    fn new(manager: Arc<Mutex<dyn LedgerTransport>>) -> Self;
36
37    ///
38    /// Get actual blockchain version available with the app.
39    /// An app may have a general type (ex. Bitcoin), but may provide access to different networks (Bitcoin Mainnet or Bitcoin Testnet)
40    fn is_open(&self) -> Option<Self::Networks>;
41}
42
43pub trait AsPubkey {
44    fn as_pubkey(&self) -> &PublicKey;
45}
46
47pub trait AsChainCode {
48    fn as_chaincode(&self) -> &ChainCode;
49}
50
51pub trait AsExtendedKey: AsPubkey + AsChainCode {}
52
53pub trait PubkeyAddressApp {
54
55    ///
56    /// Get key at hd path
57    fn get_extkey_at(&self, hd_path: &dyn HDPath) -> Result<Box<dyn AsExtendedKey>, HWKeyError>;
58
59    /// Get XPub at the specified hd path (usually it's a path to an account)
60    /// `network` is applicable to _Bitcoin_ blockchain, and it only affects how XPub is serialized.
61    /// For non-bitcoin blockchains `Bitcoin::Mainnet` may be used.
62    fn get_xpub(&self, hd_path: &dyn HDPath, network: NetworkKind) -> Result<Xpub, HWKeyError> {
63        let pubkey = self.get_extkey_at(hd_path)?;
64        let index = hd_path.get(hd_path.len() - 1).unwrap();
65
66        let parent_fingerprint = if hd_path.len() > 0 {
67            let mut parent_hd_path = Vec::with_capacity(hd_path.len() as usize - 1);
68            for i in 0..hd_path.len()-1 {
69                parent_hd_path.push(hd_path.get(i).unwrap());
70            }
71            let parent_hd_path = CustomHDPath::try_new(parent_hd_path)
72                .expect("No parent HD Path");
73            let parent_key = self.get_extkey_at(&parent_hd_path)?;
74            let fp = bitcoin::hash160(&parent_key.as_pubkey().serialize());
75            Fingerprint::try_from(&fp[0..4]).unwrap()
76        } else {
77            Fingerprint::default()
78        };
79
80        let result = Xpub {
81            network,
82            depth: hd_path.len(),
83            public_key: *pubkey.as_pubkey(),
84            chain_code: *pubkey.as_chaincode(),
85            child_number: match index {
86                PathValue::Hardened(i) => ChildNumber::from_hardened_idx(i).unwrap(),
87                PathValue::Normal(i) => ChildNumber::from_normal_idx(i).unwrap(),
88            },
89            parent_fingerprint,
90        };
91        Ok(result)
92    }
93}