From ceacc7d85f38863364cc5654c6fb081e92eff4ef Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 1 May 2021 09:29:56 +0200 Subject: [PATCH 1/3] Constructors for compressed and uncompressed ECDSA keys --- src/util/ecdsa.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index e8b2d78e..c62ac585 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -37,6 +37,23 @@ pub struct PublicKey { } impl PublicKey { + /// Constructs compressed ECDSA public key from the provided generic Secp256k1 public key + pub fn new(key: secp256k1::PublicKey) -> PublicKey { + PublicKey { + compressed: true, + key: key, + } + } + + /// Constructs uncompressed (legacy) ECDSA public key from the provided generic Secp256k1 + /// public key + pub fn new_uncompressed(key: secp256k1::PublicKey) -> PublicKey { + PublicKey { + compressed: false, + key: key, + } + } + /// Returns bitcoin 160-bit hash of the public key pub fn pubkey_hash(&self) -> PubkeyHash { if self.compressed { @@ -151,6 +168,26 @@ pub struct PrivateKey { } impl PrivateKey { + /// Constructs compressed ECDSA private key from the provided generic Secp256k1 private key + /// and the specified network + pub fn new(key: secp256k1::SecretKey, network: Network) -> PrivateKey { + PrivateKey { + compressed: true, + network: network, + key: key, + } + } + + /// Constructs uncompressed (legacy) ECDSA private key from the provided generic Secp256k1 + /// private key and the specified network + pub fn new_uncompressed(key: secp256k1::SecretKey, network: Network) -> PrivateKey { + PrivateKey { + compressed: false, + network: network, + key: key, + } + } + /// Creates a public key from this private key pub fn public_key(&self, secp: &Secp256k1) -> PublicKey { PublicKey { From 18b6bd0d153f3bae3133bdaefa401c0b0c6179e5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 1 May 2021 13:34:31 +0200 Subject: [PATCH 2/3] Adopting new ECDSA key constructors throughout the library --- src/util/address.rs | 5 +---- src/util/bip32.rs | 41 +++++++++++++++++----------------------- src/util/contracthash.rs | 24 ++++++----------------- 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/util/address.rs b/src/util/address.rs index ed082761..93c18c84 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -27,10 +27,7 @@ //! //! // Generate random key pair //! let s = Secp256k1::new(); -//! let public_key = ecdsa::PublicKey { -//! compressed: true, -//! key: s.generate_keypair(&mut thread_rng()).1, -//! }; +//! let public_key = ecdsa::PublicKey::new(s.generate_keypair(&mut thread_rng()).1); //! //! // Generate pay-to-pubkey-hash address //! let address = Address::p2pkh(&public_key, Network::Bitcoin); diff --git a/src/util/bip32.rs b/src/util/bip32.rs index 7e544d3a..0e70c8ee 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -497,18 +497,14 @@ impl ExtendedPrivKey { hmac_engine.input(seed); let hmac_result: Hmac = Hmac::from_engine(hmac_engine); + let sk = secp256k1::SecretKey::from_slice(&hmac_result[..32])?; + Ok(ExtendedPrivKey { network: network, depth: 0, parent_fingerprint: Default::default(), child_number: ChildNumber::from_normal_idx(0)?, - private_key: PrivateKey { - compressed: true, - network: network, - key: secp256k1::SecretKey::from_slice( - &hmac_result[..32] - ).map_err(Error::Ecdsa)?, - }, + private_key: PrivateKey::new(sk, network), chain_code: ChainCode::from(&hmac_result[32..]), }) } @@ -545,11 +541,10 @@ impl ExtendedPrivKey { hmac_engine.input(&endian::u32_to_array_be(u32::from(i))); let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - let mut sk = PrivateKey { - compressed: true, - network: self.network, - key: secp256k1::SecretKey::from_slice(&hmac_result[..32]).map_err(Error::Ecdsa)?, - }; + let mut sk = PrivateKey::new( + secp256k1::SecretKey::from_slice(&hmac_result[..32])?, + self.network + ); sk.key.add_assign(&self.private_key[..]).map_err(Error::Ecdsa)?; Ok(ExtendedPrivKey { @@ -578,19 +573,18 @@ impl ExtendedPrivKey { return Err(Error::UnknownVersion(ver)); }; + let sk = PrivateKey::new( + secp256k1::SecretKey::from_slice(&data[46..78])?, + network + ); + Ok(ExtendedPrivKey { network: network, depth: data[4], parent_fingerprint: Fingerprint::from(&data[5..9]), child_number: endian::slice_to_u32_be(&data[9..13]).into(), chain_code: ChainCode::from(&data[13..45]), - private_key: PrivateKey { - compressed: true, - network: network, - key: secp256k1::SecretKey::from_slice( - &data[46..78] - ).map_err(Error::Ecdsa)?, - }, + private_key: sk, }) } @@ -662,11 +656,10 @@ impl ExtendedPubKey { let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - let private_key = PrivateKey { - compressed: true, - network: self.network, - key: secp256k1::SecretKey::from_slice(&hmac_result[..32])?, - }; + let private_key = PrivateKey::new( + secp256k1::SecretKey::from_slice(&hmac_result[..32])?, + self.network, + ); let chain_code = ChainCode::from(&hmac_result[32..]); Ok((private_key, chain_code)) } diff --git a/src/util/contracthash.rs b/src/util/contracthash.rs index 271f8a63..91f11b47 100644 --- a/src/util/contracthash.rs +++ b/src/util/contracthash.rs @@ -329,25 +329,13 @@ mod tests { let (sk2, pk2) = secp.generate_keypair(&mut thread_rng()); let (sk3, pk3) = secp.generate_keypair(&mut thread_rng()); - let sk1 = PrivateKey { - key: sk1, - compressed: true, - network: Network::Bitcoin, - }; - let sk2 = PrivateKey { - key: sk2, - compressed: false, - network: Network::Bitcoin, - }; - let sk3 = PrivateKey { - key: sk3, - compressed: true, - network: Network::Bitcoin, - }; + let sk1 = PrivateKey::new(sk1, Network::Bitcoin); + let sk2 = PrivateKey::new_uncompressed(sk2, Network::Bitcoin); + let sk3 = PrivateKey::new(sk3, Network::Bitcoin); let pks = [ - PublicKey { key: pk1, compressed: true }, - PublicKey { key: pk2, compressed: false }, - PublicKey { key: pk3, compressed: true }, + PublicKey::new(pk1), + PublicKey::new_uncompressed(pk2), + PublicKey::new(pk3), ]; let contract = b"if bottle mt dont remembr drink wont pay"; From 187eae8a13d958e21a879bf4ad95c95416b43c0a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 1 May 2021 13:40:21 +0200 Subject: [PATCH 3/3] Streamlining private key construction API in BIP32 --- src/util/bip32.rs | 25 ++++++------------------- src/util/ecdsa.rs | 8 ++++++++ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/util/bip32.rs b/src/util/bip32.rs index 0e70c8ee..efc40a4f 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -497,14 +497,12 @@ impl ExtendedPrivKey { hmac_engine.input(seed); let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - let sk = secp256k1::SecretKey::from_slice(&hmac_result[..32])?; - Ok(ExtendedPrivKey { network: network, depth: 0, parent_fingerprint: Default::default(), child_number: ChildNumber::from_normal_idx(0)?, - private_key: PrivateKey::new(sk, network), + private_key: PrivateKey::from_slice(&hmac_result[..32], network)?, chain_code: ChainCode::from(&hmac_result[32..]), }) } @@ -541,11 +539,8 @@ impl ExtendedPrivKey { hmac_engine.input(&endian::u32_to_array_be(u32::from(i))); let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - let mut sk = PrivateKey::new( - secp256k1::SecretKey::from_slice(&hmac_result[..32])?, - self.network - ); - sk.key.add_assign(&self.private_key[..]).map_err(Error::Ecdsa)?; + let mut sk = PrivateKey::from_slice(&hmac_result[..32], self.network)?; + sk.key.add_assign(&self.private_key[..])?; Ok(ExtendedPrivKey { network: self.network, @@ -573,18 +568,13 @@ impl ExtendedPrivKey { return Err(Error::UnknownVersion(ver)); }; - let sk = PrivateKey::new( - secp256k1::SecretKey::from_slice(&data[46..78])?, - network - ); - Ok(ExtendedPrivKey { network: network, depth: data[4], parent_fingerprint: Fingerprint::from(&data[5..9]), child_number: endian::slice_to_u32_be(&data[9..13]).into(), chain_code: ChainCode::from(&data[13..45]), - private_key: sk, + private_key: PrivateKey::from_slice(&data[46..78], network)?, }) } @@ -656,10 +646,7 @@ impl ExtendedPubKey { let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - let private_key = PrivateKey::new( - secp256k1::SecretKey::from_slice(&hmac_result[..32])?, - self.network, - ); + let private_key = PrivateKey::from_slice(&hmac_result[..32], self.network)?; let chain_code = ChainCode::from(&hmac_result[32..]); Ok((private_key, chain_code)) } @@ -674,7 +661,7 @@ impl ExtendedPubKey { ) -> Result { let (sk, chain_code) = self.ckd_pub_tweak(i)?; let mut pk = self.public_key; - pk.key.add_exp_assign(secp, &sk[..]).map_err(Error::Ecdsa)?; + pk.key.add_exp_assign(secp, &sk[..])?; Ok(ExtendedPubKey { network: self.network, diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index c62ac585..99d7af67 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -201,6 +201,14 @@ impl PrivateKey { self.key[..].to_vec() } + /// Deserialize a private key from a slice + pub fn from_slice(data: &[u8], network: Network) -> Result { + Ok(PrivateKey::new( + secp256k1::SecretKey::from_slice(data)?, + network, + )) + } + /// Format the private key to WIF format. pub fn fmt_wif(&self, fmt: &mut dyn fmt::Write) -> fmt::Result { let mut ret = [0; 34];