diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index 15f4e01d..41b6b234 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -89,7 +89,7 @@ async fn main() -> Result<()> { let (bitcoin_wallet, monero_wallet) = init_wallets( config.clone(), &wallet_data_dir, - seed.extended_private_key(BITCOIN_NETWORK)?, + seed.derive_extended_private_key(BITCOIN_NETWORK)?, ) .await?; diff --git a/swap/src/bin/swap_cli.rs b/swap/src/bin/swap_cli.rs index 9e0da9ec..9fded67e 100644 --- a/swap/src/bin/swap_cli.rs +++ b/swap/src/bin/swap_cli.rs @@ -256,7 +256,7 @@ async fn init_bitcoin_wallet( config.bitcoin.electrum_http_url, bitcoin_network, bitcoin_wallet_data_dir, - seed.extended_private_key(bitcoin_network)?, + seed.derive_extended_private_key(bitcoin_network)?, ) .await?; diff --git a/swap/src/network.rs b/swap/src/network.rs index 917b9977..27c898b9 100644 --- a/swap/src/network.rs +++ b/swap/src/network.rs @@ -2,10 +2,8 @@ pub mod peer_tracker; pub mod request_response; pub mod transport; -use crate::seed::SEED_LENGTH; -use bitcoin::hashes::{sha256, Hash, HashEngine}; use futures::prelude::*; -use libp2p::{core::Executor, identity::ed25519}; +use libp2p::core::Executor; use std::pin::Pin; use tokio::runtime::Handle; @@ -19,35 +17,3 @@ impl Executor for TokioExecutor { let _ = self.handle.spawn(future); } } - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct Seed([u8; SEED_LENGTH]); - -impl Seed { - /// prefix "NETWORK" to the provided seed and apply sha256 - pub fn new(seed: crate::seed::Seed) -> Self { - let mut engine = sha256::HashEngine::default(); - - engine.input(&seed.bytes()); - engine.input(b"NETWORK"); - - let hash = sha256::Hash::from_engine(engine); - Self(hash.into_inner()) - } - - fn bytes(&self) -> [u8; SEED_LENGTH] { - self.0 - } - - pub fn derive_libp2p_identity(&self) -> libp2p::identity::Keypair { - let mut engine = sha256::HashEngine::default(); - - engine.input(&self.bytes()); - engine.input(b"LIBP2P_IDENTITY"); - - let hash = sha256::Hash::from_engine(engine); - let key = - ed25519::SecretKey::from_bytes(hash.into_inner()).expect("we always pass 32 bytes"); - libp2p::identity::Keypair::Ed25519(key.into()) - } -} diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index 403f6ecf..3716d2cf 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -5,7 +5,6 @@ use crate::{ execution_params::ExecutionParams, monero, monero::{Amount, BalanceTooLow}, - network, network::{transport, TokioExecutor}, protocol::{ alice, @@ -113,7 +112,7 @@ where rate_service: RS, max_sell: Amount, ) -> Result<(Self, mpsc::Receiver>>)> { - let identity = network::Seed::new(seed).derive_libp2p_identity(); + let identity = seed.derive_libp2p_identity(); let behaviour = Behaviour::default(); let transport = transport::build(&identity)?; let peer_id = PeerId::from(identity.public()); diff --git a/swap/src/protocol/bob.rs b/swap/src/protocol/bob.rs index ff815260..3b4b8954 100644 --- a/swap/src/protocol/bob.rs +++ b/swap/src/protocol/bob.rs @@ -4,7 +4,7 @@ use crate::{ bitcoin, database::Database, execution_params::ExecutionParams, - monero, network, + monero, network::peer_tracker::{self, PeerTracker}, protocol::{alice, alice::TransferProof, bob}, seed::Seed, @@ -79,7 +79,7 @@ impl Builder { alice_peer_id: PeerId, execution_params: ExecutionParams, ) -> Self { - let identity = network::Seed::new(seed).derive_libp2p_identity(); + let identity = seed.derive_libp2p_identity(); Self { swap_id, diff --git a/swap/src/seed.rs b/swap/src/seed.rs index ebcf6135..39235b8d 100644 --- a/swap/src/seed.rs +++ b/swap/src/seed.rs @@ -2,6 +2,8 @@ use crate::fs::ensure_directory_exists; use ::bitcoin::secp256k1::{self, constants::SECRET_KEY_SIZE, SecretKey}; use anyhow::Result; use bdk::bitcoin::util::bip32::ExtendedPrivKey; +use bitcoin::hashes::{sha256, Hash, HashEngine}; +use libp2p::identity; use pem::{encode, Pem}; use rand::prelude::*; use std::{ @@ -28,13 +30,21 @@ impl Seed { Ok(Seed(bytes)) } - pub fn extended_private_key(&self, network: bitcoin::Network) -> Result { - let private_key = ExtendedPrivKey::new_master(network, &self.bytes())?; + pub fn derive_extended_private_key( + &self, + network: bitcoin::Network, + ) -> Result { + let seed = self.derive(b"BITCOIN_EXTENDED_PRIVATE_KEY").bytes(); + let private_key = ExtendedPrivKey::new_master(network, &seed)?; + Ok(private_key) } - pub fn bytes(&self) -> [u8; SEED_LENGTH] { - self.0 + pub fn derive_libp2p_identity(&self) -> identity::Keypair { + let bytes = self.derive(b"NETWORK").derive(b"LIBP2P_IDENTITY").bytes(); + let key = identity::ed25519::SecretKey::from_bytes(bytes).expect("we always pass 32 bytes"); + + identity::Keypair::Ed25519(key.into()) } pub fn from_file_or_generate(data_dir: &Path) -> Result { @@ -53,6 +63,26 @@ impl Seed { Ok(random_seed) } + /// Derive a new seed using the given scope. + /// + /// This function is purposely kept private because it is only a helper + /// function for deriving specific secret material from the root seed + /// like the libp2p identity or the seed for the Bitcoin wallet. + fn derive(&self, scope: &[u8]) -> Self { + let mut engine = sha256::HashEngine::default(); + + engine.input(&self.bytes()); + engine.input(scope); + + let hash = sha256::Hash::from_engine(engine); + + Self(hash.into_inner()) + } + + fn bytes(&self) -> [u8; SEED_LENGTH] { + self.0 + } + fn from_file(seed_file: D) -> Result where D: AsRef, diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index 697c28c9..b6494605 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -606,7 +606,7 @@ async fn init_test_wallets( electrum_http_url, bitcoin::Network::Regtest, datadir, - seed.extended_private_key(bitcoin::Network::Regtest) + seed.derive_extended_private_key(bitcoin::Network::Regtest) .expect("Could not create extended private key from seed"), ) .await