Skip to content

Commit e6a3d60

Browse files
committed
BIP32 extended key to_ecdsa() and to_schnorr() methods
1 parent b72f56c commit e6a3d60

File tree

3 files changed

+43
-8
lines changed

3 files changed

+43
-8
lines changed

examples/bip32.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn main() {
4949
let path = DerivationPath::from_str("m/84h/0h/0h").unwrap();
5050
let child = root.derive_priv(&secp, &path).unwrap();
5151
println!("Child at {}: {}", path, child);
52-
let xpub = ExtendedPubKey::from_private(&secp, &child);
52+
let xpub = ExtendedPubKey::from_priv(&secp, &child);
5353
println!("Public key at {}: {}", path, xpub);
5454

5555
// generate first receiving address at m/0/0

src/util/bip32.rs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ use core::{fmt, str::FromStr, default::Default};
2525

2626
use hash_types::XpubIdentifier;
2727
use hashes::{sha512, Hash, HashEngine, Hmac, HmacEngine};
28-
use secp256k1::{self, Secp256k1};
28+
use secp256k1::{self, Secp256k1, XOnlyPublicKey};
2929

3030
use network::constants::Network;
3131
use util::{base58, endian};
32-
use util::key;
32+
use util::{key, ecdsa, schnorr};
3333
use io::Write;
3434

3535
/// A chain code
@@ -527,6 +527,21 @@ impl ExtendedPrivKey {
527527
})
528528
}
529529

530+
/// Constructs ECDSA compressed private key matching internal secret key representation.
531+
pub fn to_priv(&self) -> ecdsa::PrivateKey {
532+
ecdsa::PrivateKey {
533+
compressed: true,
534+
network: self.network,
535+
key: self.private_key
536+
}
537+
}
538+
539+
/// Constructs BIP340 keypair for Schnorr signatures and Taproot use matching the internal
540+
/// secret key representation.
541+
pub fn to_keypair<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> schnorr::KeyPair {
542+
schnorr::KeyPair::from_seckey_slice(secp, &self.private_key[..]).expect("BIP32 internal private key representation is broken")
543+
}
544+
530545
/// Attempts to derive an extended private key from a path.
531546
///
532547
/// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
@@ -616,7 +631,7 @@ impl ExtendedPrivKey {
616631

617632
/// Returns the HASH160 of the public key belonging to the xpriv
618633
pub fn identifier<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> XpubIdentifier {
619-
ExtendedPubKey::from_private(secp, self).identifier()
634+
ExtendedPubKey::from_priv(secp, self).identifier()
620635
}
621636

622637
/// Returns the first four bytes of the identifier
@@ -627,7 +642,13 @@ impl ExtendedPrivKey {
627642

628643
impl ExtendedPubKey {
629644
/// Derives a public key from a private key
645+
#[deprecated(since = "0.28.0", note = "use ExtendedPubKey::from_priv")]
630646
pub fn from_private<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &ExtendedPrivKey) -> ExtendedPubKey {
647+
ExtendedPubKey::from_priv(secp, sk)
648+
}
649+
650+
/// Derives a public key from a private key
651+
pub fn from_priv<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &ExtendedPrivKey) -> ExtendedPubKey {
631652
ExtendedPubKey {
632653
network: sk.network,
633654
depth: sk.depth,
@@ -638,6 +659,20 @@ impl ExtendedPubKey {
638659
}
639660
}
640661

662+
/// Constructs ECDSA compressed public key matching internal public key representation.
663+
pub fn to_pub(&self) -> ecdsa::PublicKey {
664+
ecdsa::PublicKey {
665+
compressed: true,
666+
key: self.public_key
667+
}
668+
}
669+
670+
/// Constructs BIP340 x-only public key for BIP-340 signatures and Taproot use matching
671+
/// the internal public key representation.
672+
pub fn to_x_only_pub(&self) -> XOnlyPublicKey {
673+
XOnlyPublicKey::from(self.public_key)
674+
}
675+
641676
/// Attempts to derive an extended public key from a path.
642677
///
643678
/// The `path` argument can be both of type `DerivationPath` or `Vec<ChildNumber>`.
@@ -869,7 +904,7 @@ mod tests {
869904
expected_pk: &str) {
870905

871906
let mut sk = ExtendedPrivKey::new_master(network, seed).unwrap();
872-
let mut pk = ExtendedPubKey::from_private(secp, &sk);
907+
let mut pk = ExtendedPubKey::from_priv(secp, &sk);
873908

874909
// Check derivation convenience method for ExtendedPrivKey
875910
assert_eq!(
@@ -897,15 +932,15 @@ mod tests {
897932
match num {
898933
Normal {..} => {
899934
let pk2 = pk.ckd_pub(secp, num).unwrap();
900-
pk = ExtendedPubKey::from_private(secp, &sk);
935+
pk = ExtendedPubKey::from_priv(secp, &sk);
901936
assert_eq!(pk, pk2);
902937
}
903938
Hardened {..} => {
904939
assert_eq!(
905940
pk.ckd_pub(secp, num),
906941
Err(Error::CannotDeriveFromHardenedKey)
907942
);
908-
pk = ExtendedPubKey::from_private(secp, &sk);
943+
pk = ExtendedPubKey::from_priv(secp, &sk);
909944
}
910945
}
911946
}

src/util/psbt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ mod tests {
310310

311311
sk = sk.derive_priv(secp, &dpath).unwrap();
312312

313-
let pk: ExtendedPubKey = ExtendedPubKey::from_private(&secp, &sk);
313+
let pk: ExtendedPubKey = ExtendedPubKey::from_priv(&secp, &sk);
314314

315315
hd_keypaths.insert(pk.public_key, (fprint, dpath.into()));
316316

0 commit comments

Comments
 (0)