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 0934af0f..1d595cba 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -502,13 +502,7 @@ impl ExtendedPrivKey { 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::from_slice(&hmac_result[..32], network)?, chain_code: ChainCode::from(&hmac_result[32..]), }) } @@ -545,12 +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 { - compressed: true, - network: self.network, - key: secp256k1::SecretKey::from_slice(&hmac_result[..32]).map_err(Error::Ecdsa)?, - }; - 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, @@ -584,13 +574,7 @@ impl ExtendedPrivKey { 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: PrivateKey::from_slice(&data[46..78], network)?, }) } @@ -662,11 +646,7 @@ 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::from_slice(&hmac_result[..32], self.network)?; let chain_code = ChainCode::from(&hmac_result[32..]); Ok((private_key, chain_code)) } @@ -681,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/contracthash.rs b/src/util/contracthash.rs index 3e8a4809..4781690b 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"; diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index e8b2d78e..99d7af67 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 { @@ -164,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];