From 7fcfffd171b2c254121378d39ca696a31836ba9c Mon Sep 17 00:00:00 2001 From: Janus Date: Thu, 30 Sep 2021 19:26:19 -0400 Subject: [PATCH] Add secp256k1 keypair type for btc --- src/bin/cashierd.rs | 35 ++++++++-------- src/service/btc.rs | 98 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 110 insertions(+), 23 deletions(-) diff --git a/src/bin/cashierd.rs b/src/bin/cashierd.rs index c6f140d94..aa5fd1bad 100644 --- a/src/bin/cashierd.rs +++ b/src/bin/cashierd.rs @@ -415,24 +415,27 @@ impl Cashierd { #[cfg(feature = "btc")] NetworkName::Bitcoin => { debug!(target: "CASHIER DAEMON", "Add btc network"); - //use drk::service::btc::{BtcClient, BitcoinKeys}; + use drk::service::btc::{BtcClient, Keypair}; - //let _btc_client = BtcClient::new("testnet")?; - // NOTE bitcoin is not implemented yet - //let _main_keypair: BitcoinKeys; + let main_keypair: Keypair; - let _main_keypairs = - self.cashier_wallet.get_main_keys(&NetworkName::Bitcoin)?; - // if main_keypairs.is_empty() { - // //main_keypair = BitcoinKeys::new(bitcoin::network::constants::Network::Testnet)?; - // } else { - // //main_keypair = deserialize(&main_keypairs[0].0)?; - // } - // - // TODO check if there is main_keypair inside - // cashierdb before generating new one - // - //bridge2.add_clients("btc".into(), btc_client).await?; + let main_keypairs = self.cashier_wallet.get_main_keys(&NetworkName::Bitcoin)?; + + if main_keypairs.is_empty() { + main_keypair = Keypair::new(); + self.cashier_wallet.put_main_keys( + &serialize(&main_keypair), + &serialize(&main_keypair.pubkey()), + &NetworkName::Bitcoin, + )?; + + } else { + main_keypair = deserialize(&main_keypairs[0].0)?; + } + + let btc_client = BtcClient::new(serialize(&main_keypair), &chain).await?; + + bridge2.add_clients(NetworkName::Bitcoin, btc_client).await?; } } } diff --git a/src/service/btc.rs b/src/service/btc.rs index a8ea2119e..3c4c1f2f7 100644 --- a/src/service/btc.rs +++ b/src/service/btc.rs @@ -1,7 +1,7 @@ use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion}; -use crate::serial::{serialize, Decodable, Encodable}; +use crate::serial::{serialize, deserialize, Decodable, Encodable}; use crate::{Error, Result}; - +use std::convert::From; use async_trait::async_trait; use bitcoin::blockdata::script::Script; use bitcoin::hash_types::{PubkeyHash as BtcPubKeyHash, Txid}; @@ -12,6 +12,7 @@ use electrum_client::{Client as ElectrumClient, ElectrumApi}; use log::*; use secp256k1::key::{PublicKey, SecretKey}; +use secp256k1::constants::{SECRET_KEY_SIZE, PUBLIC_KEY_SIZE}; use secp256k1::{rand::rngs::OsRng, Secp256k1}; use async_std::sync::Arc; @@ -22,8 +23,47 @@ pub type PubAddress = Address; pub type PubKey = BtcPubKey; pub type PrivKey = BtcPrivKey; +const KEYPAIR_LENGTH: usize = SECRET_KEY_SIZE + PUBLIC_KEY_SIZE; + +pub struct Keypair { + secret: SecretKey, + public: PublicKey, +} +impl Keypair { + pub fn new() -> Self { + let secp = Secp256k1::new(); + let mut rng = OsRng::new().expect("OsRng"); + + let (secret, public) = secp.generate_keypair(&mut rng); + Self { + secret, + public, + } + } + pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] { + let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; + + bytes[..SECRET_KEY_SIZE].copy_from_slice(self.secret.as_ref()); + bytes[SECRET_KEY_SIZE..].copy_from_slice(&self.public.serialize()); + bytes + + } + pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { + if bytes.len() != KEYPAIR_LENGTH { + return Err(Error::BtcFailed("Not right size".to_string())); + } + //TODO: Map to errors properly + let secret = SecretKey::from_slice(&bytes[..SECRET_KEY_SIZE]).unwrap(); + let public = PublicKey::from_slice(&bytes[SECRET_KEY_SIZE..]).unwrap(); + + Ok(Keypair{ secret: secret, public: public }) + } + pub fn pubkey(&self) -> PublicKey { + self.public + } +} pub struct BitcoinKeys { - secret_key: SecretKey, + _secret_key: SecretKey, public_key: PublicKey, _context: Secp256k1, btc_privkey: BtcPrivKey, @@ -42,7 +82,7 @@ impl BitcoinKeys { let btc_pubkey = btc_privkey.public_key(&secp); Ok(Arc::new(BitcoinKeys { - secret_key, + _secret_key: secret_key, public_key, _context: secp, btc_privkey, @@ -74,11 +114,13 @@ impl BitcoinKeys { pub struct BtcClient { client: Arc, network: Network, - keypair: BitcoinKeys, + keypair: Keypair, } impl BtcClient { - pub fn new(network: &str, keypair: BitcoinKeys) -> Result> { + pub async fn new(keypair: Vec, network: &str) -> Result> { + let keypair: Keypair = deserialize(&keypair)?; + let (network, url) = match network { "mainnet" => (Network::Bitcoin, "ssl://electrum.blockstream.info:50002"), "testnet" => (Network::Testnet, "ssl://electrum.blockstream.info:60002"), @@ -246,6 +288,40 @@ impl Decodable for bitcoin::PrivateKey { Ok(key) } } +impl Encodable for secp256k1::key::PublicKey { + fn encode(&self, s: S) -> Result { + let key: Vec = self.serialize().to_vec(); + let len = key.encode(s)?; + Ok(len) + } +} +impl Decodable for secp256k1::key::PublicKey { + fn decode(mut d: D) -> Result { + let key: Vec = Decodable::decode(&mut d)?; + let key = secp256k1::key::PublicKey::from_slice(&key) + .map_err(|err| crate::Error::from(BtcFailed::from(err)))?; + Ok(key) + } +} +impl Encodable for Keypair { + fn encode(&self, s: S) -> Result { + let key: Vec = self.to_bytes().to_vec(); + let len = key.encode(s)?; + Ok(len) + } +} + +impl Decodable for Keypair { + fn decode(mut d: D) -> Result { + let key: Vec = Decodable::decode(&mut d)?; + let key = Keypair::from_bytes(key.as_slice()).map_err(|_| { + crate::Error::from(BtcFailed::DecodeAndEncodeError( + "load keypair from slice".into(), + )) + })?; + Ok(key) + } +} #[derive(Debug)] pub enum BtcFailed { @@ -254,6 +330,7 @@ pub enum BtcFailed { ElectrumError(String), BtcError(String), DecodeAndEncodeError(String), + KeypairError(String) } impl std::error::Error for BtcFailed {} @@ -271,6 +348,9 @@ impl std::fmt::Display for BtcFailed { BtcFailed::DecodeAndEncodeError(ref err) => { write!(f, "Decode and decode keys error: {}", err) } + BtcFailed::KeypairError(ref err) => { + write!(f, "Keypair error from Secp256k1: {}", err) + } BtcFailed::BtcError(i) => { write!(f, "BtcFailed: {}", i) } @@ -283,7 +363,11 @@ impl From for BtcFailed { BtcFailed::BtcError(err.to_string()) } } - +impl From for BtcFailed { + fn from(err: secp256k1::Error) -> BtcFailed { + BtcFailed::KeypairError(err.to_string()) + } +} impl From for BtcFailed { fn from(err: bitcoin::util::address::Error) -> BtcFailed { BtcFailed::BadBtcAddress(err.to_string())