From 23cbee842f6534960bfdf21c8d85f692b140040a Mon Sep 17 00:00:00 2001 From: rishflab Date: Tue, 9 Feb 2021 17:23:13 +1100 Subject: [PATCH] Derive bitcoin private key from seed --- swap/src/bitcoin/wallet.rs | 4 +--- swap/src/main.rs | 9 +++++++++ swap/src/seed.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 7873b7ac..42f45a01 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -13,7 +13,6 @@ use backoff::{backoff::Constant as ConstantBackoff, tokio::retry}; use bdk::{ blockchain::{noop_progress, Blockchain, ElectrumBlockchain}, electrum_client::{Client, ElectrumApi}, - keys::GeneratableDefaultOptions, FeeRate, }; use reqwest::{Method, Url}; @@ -36,6 +35,7 @@ impl Wallet { electrum_http_url: Url, network: bitcoin::Network, datadir: &Path, + p_key: bitcoin::PrivateKey, ) -> Result { // todo: Implement conversion to anyhow::error so we can use ? let client = @@ -43,8 +43,6 @@ impl Wallet { let db = bdk::sled::open(datadir)?.open_tree(SLED_TREE_NAME)?; - // todo: make key generation configurable using a descriptor - let p_key = ::bitcoin::PrivateKey::generate_default()?; let bdk_wallet = bdk::Wallet::new( bdk::template::P2WPKH(p_key), None, diff --git a/swap/src/main.rs b/swap/src/main.rs index e81790a8..af67dc98 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -19,6 +19,7 @@ use crate::{ }, execution_params::GetExecutionParams, protocol::bob::cancel::CancelError, + seed::Seed, }; use anyhow::{Context, Result}; use database::Database; @@ -97,6 +98,7 @@ async fn main() -> Result<()> { bitcoin_network, &wallet_data_dir, monero_network, + seed, ) .await?; @@ -139,6 +141,7 @@ async fn main() -> Result<()> { bitcoin_network, &wallet_data_dir, monero_network, + seed, ) .await?; @@ -188,6 +191,7 @@ async fn main() -> Result<()> { bitcoin_network, &wallet_data_dir, monero_network, + seed, ) .await?; @@ -216,6 +220,7 @@ async fn main() -> Result<()> { bitcoin_network, &wallet_data_dir, monero_network, + seed, ) .await?; @@ -247,6 +252,7 @@ async fn main() -> Result<()> { bitcoin_network, &wallet_data_dir, monero_network, + seed, ) .await?; @@ -297,6 +303,7 @@ async fn main() -> Result<()> { bitcoin_network, &wallet_data_dir, monero_network, + seed, ) .await?; @@ -334,6 +341,7 @@ async fn init_wallets( bitcoin_network: bitcoin::Network, bitcoin_wallet_data_dir: &Path, monero_network: monero::Network, + seed: Seed, ) -> Result<(bitcoin::Wallet, monero::Wallet)> { let config_path = if let Some(config_path) = config_path { config_path @@ -354,6 +362,7 @@ async fn init_wallets( config.bitcoin.electrum_http_url, bitcoin_network, bitcoin_wallet_data_dir, + seed.root_private_key(bitcoin_network), ) .await?; let bitcoin_balance = bitcoin_wallet.balance().await?; diff --git a/swap/src/seed.rs b/swap/src/seed.rs index 382f64da..5dbfa8cb 100644 --- a/swap/src/seed.rs +++ b/swap/src/seed.rs @@ -1,4 +1,8 @@ use ::bitcoin::secp256k1::{self, constants::SECRET_KEY_SIZE, SecretKey}; +use bitcoin::{ + hashes::{sha512, Hash, HashEngine, Hmac, HmacEngine}, + PrivateKey, +}; use rand::prelude::*; use std::fmt; @@ -18,6 +22,29 @@ impl Seed { Ok(Seed(bytes)) } + /// Return the private key and chain code to be used as root extended + /// private key for a BIP32 wallet. + pub fn root_private_key(&self, network: bitcoin::Network) -> PrivateKey { + let bytes = self.bytes(); + + // Yes, this is as per BIP32 and used in both Bitcoin and Ethereum ecosystems + let hash_key = b"Bitcoin seed"; + + let mut engine = HmacEngine::::new(hash_key); + engine.input(&bytes); + let hash = Hmac::::from_engine(engine); + let output = &hash.into_inner()[..]; + let key = &output[..32]; + + let secret_key = SecretKey::from_slice(key).expect("32 bytes array should be fine"); + + PrivateKey { + compressed: true, + network, + key: secret_key, + } + } + pub fn bytes(&self) -> [u8; SEED_LENGTH] { self.0 }