Skip to content

Commit

Permalink
Merge pull request #592 from LNP-BP/feat/ecdsa-key-creation
Browse files Browse the repository at this point in the history
Constructors for compressed and uncompressed ECDSA keys
  • Loading branch information
apoelstra committed May 6, 2021
2 parents 3fd88d3 + 187eae8 commit d0fb626
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 48 deletions.
5 changes: 1 addition & 4 deletions src/util/address.rs
Expand Up @@ -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);
Expand Down
32 changes: 6 additions & 26 deletions src/util/bip32.rs
Expand Up @@ -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..]),
})
}
Expand Down Expand Up @@ -545,12 +539,8 @@ impl ExtendedPrivKey {

hmac_engine.input(&endian::u32_to_array_be(u32::from(i)));
let hmac_result: Hmac<sha512::Hash> = 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,
Expand Down Expand Up @@ -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)?,
})
}

Expand Down Expand Up @@ -662,11 +646,7 @@ impl ExtendedPubKey {

let hmac_result: Hmac<sha512::Hash> = 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))
}
Expand All @@ -681,7 +661,7 @@ impl ExtendedPubKey {
) -> Result<ExtendedPubKey, Error> {
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,
Expand Down
24 changes: 6 additions & 18 deletions src/util/contracthash.rs
Expand Up @@ -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";

Expand Down
45 changes: 45 additions & 0 deletions src/util/ecdsa.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> PublicKey {
PublicKey {
Expand All @@ -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<PrivateKey, Error> {
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];
Expand Down

0 comments on commit d0fb626

Please sign in to comment.