Skip to content

Commit b72f56c

Browse files
committed
BIP32 extended keys are using Scep256k1 keys instead of bitcoin ECDSA
According to #588, BIP32 does not support uncompressed keys and using type with compression flag is a mistake
1 parent 7010672 commit b72f56c

File tree

3 files changed

+55
-31
lines changed

3 files changed

+55
-31
lines changed

examples/bip32.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{env, process};
44
use std::str::FromStr;
55

66
use bitcoin::secp256k1::Secp256k1;
7-
use bitcoin::util::ecdsa::PrivateKey;
7+
use bitcoin::{PrivateKey, PublicKey};
88
use bitcoin::util::bip32::ExtendedPrivKey;
99
use bitcoin::util::bip32::ExtendedPubKey;
1010
use bitcoin::util::bip32::DerivationPath;
@@ -58,7 +58,7 @@ fn main() {
5858
let public_key = xpub.derive_pub(&secp, &vec![zero, zero])
5959
.unwrap()
6060
.public_key;
61-
let address = Address::p2wpkh(&public_key, network).unwrap();
61+
let address = Address::p2wpkh(&PublicKey::new(public_key), network).unwrap();
6262
println!("First receiving address: {}", address);
6363

6464
}

src/util/bip32.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ use hashes::{sha512, Hash, HashEngine, Hmac, HmacEngine};
2828
use secp256k1::{self, Secp256k1};
2929

3030
use network::constants::Network;
31-
use util::{base58, endian, key};
32-
use util::ecdsa::{PublicKey, PrivateKey};
31+
use util::{base58, endian};
32+
use util::key;
33+
use io::Write;
3334

3435
/// A chain code
3536
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -44,7 +45,8 @@ impl_array_newtype!(Fingerprint, u8, 4);
4445
impl_bytes_newtype!(Fingerprint, 4);
4546

4647
/// Extended private key
47-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
48+
#[derive(Copy, Clone, PartialEq, Eq)]
49+
#[cfg_attr(feature = "std", derive(Debug))]
4850
pub struct ExtendedPrivKey {
4951
/// The network this key is to be used on
5052
pub network: Network,
@@ -55,12 +57,26 @@ pub struct ExtendedPrivKey {
5557
/// Child number of the key used to derive from parent (0 for master)
5658
pub child_number: ChildNumber,
5759
/// Private key
58-
pub private_key: PrivateKey,
60+
pub private_key: secp256k1::SecretKey,
5961
/// Chain code
6062
pub chain_code: ChainCode
6163
}
6264
serde_string_impl!(ExtendedPrivKey, "a BIP-32 extended private key");
6365

66+
#[cfg(not(feature = "std"))]
67+
#[cfg_attr(docsrs, doc(cfg(not(feature = "std"))))]
68+
impl fmt::Debug for ExtendedPrivKey {
69+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70+
f.debug_struct("ExtendedPrivKey")
71+
.field("network", &self.network)
72+
.field("depth", &self.depth)
73+
.field("parent_fingerprint", &self.parent_fingerprint)
74+
.field("child_number", &self.child_number)
75+
.field("chain_code", &self.chain_code)
76+
.finish_non_exhaustive()
77+
}
78+
}
79+
6480
/// Extended public key
6581
#[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)]
6682
pub struct ExtendedPubKey {
@@ -73,7 +89,7 @@ pub struct ExtendedPubKey {
7389
/// Child number of the key used to derive from parent (0 for master)
7490
pub child_number: ChildNumber,
7591
/// Public key
76-
pub public_key: PublicKey,
92+
pub public_key: secp256k1::PublicKey,
7793
/// Chain code
7894
pub chain_code: ChainCode
7995
}
@@ -506,7 +522,7 @@ impl ExtendedPrivKey {
506522
depth: 0,
507523
parent_fingerprint: Default::default(),
508524
child_number: ChildNumber::from_normal_idx(0)?,
509-
private_key: PrivateKey::from_slice(&hmac_result[..32], network)?,
525+
private_key: secp256k1::SecretKey::from_slice(&hmac_result[..32])?,
510526
chain_code: ChainCode::from(&hmac_result[32..]),
511527
})
512528
}
@@ -532,7 +548,7 @@ impl ExtendedPrivKey {
532548
match i {
533549
ChildNumber::Normal { .. } => {
534550
// Non-hardened key: compute public data and use that
535-
hmac_engine.input(&PublicKey::from_private_key(secp, &self.private_key).key.serialize()[..]);
551+
hmac_engine.input(&secp256k1::PublicKey::from_secret_key(secp, &self.private_key).serialize()[..]);
536552
}
537553
ChildNumber::Hardened { .. } => {
538554
// Hardened key: use only secret data to prevent public derivation
@@ -543,8 +559,8 @@ impl ExtendedPrivKey {
543559

544560
hmac_engine.input(&endian::u32_to_array_be(u32::from(i)));
545561
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
546-
let mut sk = PrivateKey::from_slice(&hmac_result[..32], self.network)?;
547-
sk.key.add_assign(&self.private_key[..])?;
562+
let mut sk = secp256k1::SecretKey::from_slice(&hmac_result[..32])?;
563+
sk.add_assign(&self.private_key[..])?;
548564

549565
Ok(ExtendedPrivKey {
550566
network: self.network,
@@ -578,7 +594,7 @@ impl ExtendedPrivKey {
578594
parent_fingerprint: Fingerprint::from(&data[5..9]),
579595
child_number: endian::slice_to_u32_be(&data[9..13]).into(),
580596
chain_code: ChainCode::from(&data[13..45]),
581-
private_key: PrivateKey::from_slice(&data[46..78], network)?,
597+
private_key: secp256k1::SecretKey::from_slice(&data[46..78])?,
582598
})
583599
}
584600

@@ -617,7 +633,7 @@ impl ExtendedPubKey {
617633
depth: sk.depth,
618634
parent_fingerprint: sk.parent_fingerprint,
619635
child_number: sk.child_number,
620-
public_key: PublicKey::from_private_key(secp, &sk.private_key),
636+
public_key: secp256k1::PublicKey::from_secret_key(secp, &sk.private_key),
621637
chain_code: sk.chain_code
622638
}
623639
}
@@ -638,19 +654,19 @@ impl ExtendedPubKey {
638654
}
639655

640656
/// Compute the scalar tweak added to this key to get a child key
641-
pub fn ckd_pub_tweak(&self, i: ChildNumber) -> Result<(PrivateKey, ChainCode), Error> {
657+
pub fn ckd_pub_tweak(&self, i: ChildNumber) -> Result<(secp256k1::SecretKey, ChainCode), Error> {
642658
match i {
643659
ChildNumber::Hardened { .. } => {
644660
Err(Error::CannotDeriveFromHardenedKey)
645661
}
646662
ChildNumber::Normal { index: n } => {
647663
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(&self.chain_code[..]);
648-
hmac_engine.input(&self.public_key.key.serialize()[..]);
664+
hmac_engine.input(&self.public_key.serialize()[..]);
649665
hmac_engine.input(&endian::u32_to_array_be(n));
650666

651667
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
652668

653-
let private_key = PrivateKey::from_slice(&hmac_result[..32], self.network)?;
669+
let private_key = secp256k1::SecretKey::from_slice(&hmac_result[..32])?;
654670
let chain_code = ChainCode::from(&hmac_result[32..]);
655671
Ok((private_key, chain_code))
656672
}
@@ -665,7 +681,7 @@ impl ExtendedPubKey {
665681
) -> Result<ExtendedPubKey, Error> {
666682
let (sk, chain_code) = self.ckd_pub_tweak(i)?;
667683
let mut pk = self.public_key;
668-
pk.key.add_exp_assign(secp, &sk[..])?;
684+
pk.add_exp_assign(secp, &sk[..])?;
669685

670686
Ok(ExtendedPubKey {
671687
network: self.network,
@@ -697,7 +713,7 @@ impl ExtendedPubKey {
697713
parent_fingerprint: Fingerprint::from(&data[5..9]),
698714
child_number: endian::slice_to_u32_be(&data[9..13]).into(),
699715
chain_code: ChainCode::from(&data[13..45]),
700-
public_key: PublicKey::from_slice(&data[45..78])?,
716+
public_key: secp256k1::PublicKey::from_slice(&data[45..78])?,
701717
})
702718
}
703719

@@ -712,14 +728,14 @@ impl ExtendedPubKey {
712728
ret[5..9].copy_from_slice(&self.parent_fingerprint[..]);
713729
ret[9..13].copy_from_slice(&endian::u32_to_array_be(u32::from(self.child_number)));
714730
ret[13..45].copy_from_slice(&self.chain_code[..]);
715-
ret[45..78].copy_from_slice(&self.public_key.key.serialize()[..]);
731+
ret[45..78].copy_from_slice(&self.public_key.serialize()[..]);
716732
ret
717733
}
718734

719735
/// Returns the HASH160 of the chaincode
720736
pub fn identifier(&self) -> XpubIdentifier {
721737
let mut engine = XpubIdentifier::engine();
722-
self.public_key.write_into(&mut engine).expect("engines don't error");
738+
engine.write(&self.public_key.serialize()).expect("engines don't error");
723739
XpubIdentifier::from_engine(engine)
724740
}
725741

src/util/psbt/mod.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -243,24 +243,23 @@ impl Decodable for PartiallySignedTransaction {
243243

244244
#[cfg(test)]
245245
mod tests {
246+
use super::PartiallySignedTransaction;
247+
246248
use hashes::hex::FromHex;
247249
use hashes::{sha256, hash160, Hash, ripemd160};
248250
use hash_types::Txid;
249251

250-
251-
use secp256k1::Secp256k1;
252+
use secp256k1::{Secp256k1, self};
252253

253254
use blockdata::script::Script;
254255
use blockdata::transaction::{Transaction, TxIn, TxOut, OutPoint};
255256
use network::constants::Network::Bitcoin;
256257
use consensus::encode::{deserialize, serialize, serialize_hex};
257258
use util::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, Fingerprint, KeySource};
258-
use util::ecdsa::PublicKey;
259+
use util::ecdsa;
259260
use util::psbt::map::{Output, Input};
260261
use util::psbt::raw;
261262

262-
use super::PartiallySignedTransaction;
263-
use util::psbt::raw::ProprietaryKey;
264263
use std::collections::BTreeMap;
265264
use blockdata::witness::Witness;
266265

@@ -292,7 +291,7 @@ mod tests {
292291
let secp = &Secp256k1::new();
293292
let seed = Vec::from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
294293

295-
let mut hd_keypaths: BTreeMap<PublicKey, KeySource> = Default::default();
294+
let mut hd_keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = Default::default();
296295

297296
let mut sk: ExtendedPrivKey = ExtendedPrivKey::new_master(Bitcoin, &seed).unwrap();
298297

@@ -322,7 +321,10 @@ mod tests {
322321
witness_script: Some(hex_script!(
323322
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787"
324323
)),
325-
bip32_derivation: hd_keypaths,
324+
bip32_derivation: hd_keypaths.into_iter().map(|(key, src)| (ecdsa::PublicKey {
325+
compressed: true,
326+
key,
327+
}, src)).collect(),
326328
..Default::default()
327329
};
328330

@@ -435,7 +437,7 @@ mod tests {
435437
vec![3, 4 ,5],
436438
)].into_iter().collect();
437439
let key_source = ("deadbeef".parse().unwrap(), "m/0'/1".parse().unwrap());
438-
let keypaths: BTreeMap<PublicKey, KeySource> = vec![(
440+
let keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = vec![(
439441
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
440442
key_source.clone(),
441443
)].into_iter().collect();
@@ -479,7 +481,10 @@ mod tests {
479481
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
480482
vec![8, 5, 4],
481483
)].into_iter().collect(),
482-
bip32_derivation: keypaths.clone(),
484+
bip32_derivation: keypaths.clone().into_iter().map(|(key, src)| (ecdsa::PublicKey {
485+
compressed: true,
486+
key,
487+
}, src)).collect(),
483488
final_script_witness: Some(vec![vec![1, 3], vec![5]]),
484489
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
485490
sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
@@ -490,7 +495,10 @@ mod tests {
490495
..Default::default()
491496
}],
492497
outputs: vec![Output {
493-
bip32_derivation: keypaths.clone(),
498+
bip32_derivation: keypaths.into_iter().map(|(key, src)| (ecdsa::PublicKey {
499+
compressed: true,
500+
key,
501+
}, src)).collect(),
494502
proprietary: proprietary.clone(),
495503
unknown: unknown.clone(),
496504
..Default::default()
@@ -1012,7 +1020,7 @@ mod tests {
10121020
#[test]
10131021
fn serialize_and_deserialize_proprietary() {
10141022
let mut psbt: PartiallySignedTransaction = hex_psbt!("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
1015-
psbt.proprietary.insert(ProprietaryKey {
1023+
psbt.proprietary.insert(raw::ProprietaryKey {
10161024
prefix: b"test".to_vec(),
10171025
subtype: 0u8,
10181026
key: b"test".to_vec(),

0 commit comments

Comments
 (0)