Introduce wrapper type for secp256k1::Keypair
What changed, and why it matters
This commit is a routine code-quality refactor in the rust-bitcoin library. It wraps the underlying secp256k1 keypair type in a library-specific type so that parsing errors can be more precise and the public API is cleaner. There is no direct security vulnerability being fixed here; it is an interface improvement that may indirectly reduce misuse.
No immediate security action required. Treat as a normal API refactor. Downstream users should update imports from secp256k1::Keypair to bitcoin::key::Keypair when upgrading, and note the new from_str error type.
Security signals we found
API refactor replacing direct re-export of cryptographic keypair type with a wrapper
Introduction of a dedicated ParseKeypairError for tighter error typing
No direct cryptographic bug, memory-safety issue, or authorization bypass evident in diff
Potential indirect hardening: wrapper reduces chance of downstream code mixing raw secp256k1 and bitcoin key types
Evidence from the diff
The change introduces a new bitcoin::key::Keypair wrapper around secp256k1::Keypair, replacing direct re-exports and usages. It adds a narrow ParseKeypairError, helper methods (to_inner, to_secret_key, to_public_key, to_x_only_public_key, from_secret_key, generate), and updates call sites in BIP32, sighash tests, PSBT signing, and examples to use the wrapper. The previous public re-export of secp256k1::Keypair is removed in favor of the new wrapper. The commit message frames this as solving an imprecise error type for from_str in XOnlyPublicKey and providing a cleaner interface.
Changed components
bitcoin/src/crypto/key.rsbitcoin/src/bip32.rsbitcoin/src/crypto/sighash.rsbitcoin/src/psbt/mod.rsbitcoin/src/lib.rsbitcoin/examples/sign-tx-taproot.rsbitcoin/examples/taproot-psbt.rsbitcoin/tests/psbt-sign-taproot.rsInspect captured patch +159 / −47
diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs
index a1554966..a88cba5f 100644
--- a/bitcoin/examples/sign-tx-taproot.rs
+++ b/bitcoin/examples/sign-tx-taproot.rs
@@ -19,7 +19,7 @@ const CHANGE_AMOUNT: Amount = Amount::from_sat_u32(14_999_000); // 1000 sat fee.
fn main() {
// Get a keypair we control. In a real application these would come from a stored secret.
let keypair = senders_keys();
- let (internal_key, _parity) = keypair.x_only_public_key();
+ let (internal_key, _parity) = keypair.to_x_only_public_key();
// Get an unspent output that is locked to the key above that we control.
// In a real application these would come from the chain.
@@ -67,7 +67,7 @@ fn main() {
// Sign the sighash using the secp256k1 library (exported by rust-bitcoin).
let tweaked: TweakedKeypair = keypair.tap_tweak(None);
- let signature = secp256k1::schnorr::sign(&sighash.to_byte_array(), tweaked.as_keypair());
+ let signature = secp256k1::schnorr::sign(&sighash.to_byte_array(), &tweaked.as_keypair().to_inner());
// Update the witness stack.
let signature = bitcoin::taproot::Signature { signature, sighash_type };
diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs
index 2b5ef494..40bf7f7a 100644
--- a/bitcoin/examples/taproot-psbt.rs
+++ b/bitcoin/examples/taproot-psbt.rs
@@ -80,7 +80,7 @@ use std::collections::BTreeMap;
use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv, Xpub};
use bitcoin::consensus::encode;
use bitcoin::ext::*;
-use bitcoin::key::{TapTweak, XOnlyPublicKey};
+use bitcoin::key::{Keypair, TapTweak, XOnlyPublicKey};
use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP};
use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType};
use bitcoin::sighash::{self, SighashCache, TapSighash, TapSighashType};
@@ -399,7 +399,7 @@ impl BenefactorWallet {
let taproot_spend_info = TaprootBuilder::new()
.add_leaf(0, script.clone())?
- .finalize(internal_keypair.x_only_public_key().0)
+ .finalize(internal_keypair.to_x_only_public_key().0)
.expect("should be finalizable");
self.current_spend_info = Some(taproot_spend_info.clone());
let script_pubkey = ScriptPubKeyBuf::new_p2tr(
@@ -435,7 +435,7 @@ impl BenefactorWallet {
(vec![leaf_hash], (self.beneficiary_xpub.fingerprint(), derivation_path.clone())),
);
origins.insert(
- internal_keypair.x_only_public_key().0.into(),
+ internal_keypair.to_x_only_public_key().0,
(vec![], (self.master_xpriv.fingerprint(), derivation_path)),
);
let ty = "SIGHASH_ALL".parse::<PsbtSighashType>()?;
@@ -450,7 +450,7 @@ impl BenefactorWallet {
tap_key_origins: origins,
tap_merkle_root: taproot_spend_info.merkle_root(),
sighash_type: Some(ty),
- tap_internal_key: Some(internal_keypair.x_only_public_key().0.into()),
+ tap_internal_key: Some(internal_keypair.to_x_only_public_key().0),
tap_scripts,
..Default::default()
};
@@ -494,7 +494,7 @@ impl BenefactorWallet {
let taproot_spend_info = TaprootBuilder::new()
.add_leaf(0, script.clone())?
- .finalize(new_internal_keypair.x_only_public_key().0)
+ .finalize(new_internal_keypair.to_x_only_public_key().0)
.expect("should be finalizable");
self.current_spend_info = Some(taproot_spend_info.clone());
let prevout_script_pubkey = input.witness_utxo.as_ref().unwrap().script_pubkey.clone();
@@ -599,7 +599,7 @@ impl BenefactorWallet {
tap_key_origins: origins,
tap_merkle_root: taproot_spend_info.merkle_root(),
sighash_type: Some(ty),
- tap_internal_key: Some(new_internal_keypair.x_only_public_key().0.into()),
+ tap_internal_key: Some(new_internal_keypair.to_x_only_public_key().0),
tap_scripts,
..Default::default()
};
@@ -730,13 +730,13 @@ fn sign_psbt_taproot(
hash: TapSighash,
sighash_type: TapSighashType,
) {
- let keypair = secp256k1::Keypair::from_seckey_byte_array(secret_key.to_secret_bytes()).unwrap();
+ let keypair = Keypair::from_secret_key(&secret_key);
let keypair = match leaf_hash {
None => keypair.tap_tweak(psbt_input.tap_merkle_root).to_keypair(),
Some(_) => keypair, // no tweak for script spend
};
- let signature = secp256k1::schnorr::sign(&hash.to_byte_array(), &keypair);
+ let signature = secp256k1::schnorr::sign(&hash.to_byte_array(), &keypair.to_inner());
let final_signature = taproot::Signature { signature, sighash_type };
diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs
index 5d02b1a7..b66d0b14 100644
--- a/bitcoin/src/bip32.rs
+++ b/bitcoin/src/bip32.rs
@@ -743,8 +743,7 @@ impl Xpriv {
/// Constructs a new BIP-0340 keypair for Schnorr signatures and Taproot use matching the internal
/// secret key representation.
pub fn to_keypair(self) -> Keypair {
- Keypair::from_seckey_byte_array(self.private_key.to_secret_bytes())
- .expect("BIP-0032 internal private key representation is broken")
+ Keypair::from_secret_key(&self.private_key)
}
/// Derives an extended private key from a path.
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index 65ac68db..6e428b71 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -25,7 +25,7 @@ use crate::script::{self, WitnessScriptBuf};
use crate::taproot::{TapNodeHash, TapTweakHash};
#[rustfmt::skip] // Keep public re-exports separate.
-pub use secp256k1::{constants, Keypair, Parity, Verification};
+pub use secp256k1::{constants, Parity, Verification};
#[cfg(all(feature = "rand", feature = "std"))]
pub use secp256k1::rand;
pub use serialized_x_only::SerializedXOnlyPublicKey;
@@ -44,7 +44,7 @@ impl XOnlyPublicKey {
/// Returns the x-only public key and the parity of the full public key.
#[inline]
pub fn from_keypair(keypair: &Keypair) -> (Self, Parity) {
- let (xonly, parity) = secp256k1::XOnlyPublicKey::from_keypair(keypair);
+ let (xonly, parity) = secp256k1::XOnlyPublicKey::from_keypair(&keypair.to_inner());
(Self::new(xonly), parity)
}
@@ -139,6 +139,81 @@ impl fmt::Display for XOnlyPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}
+/// A Bitcoin secret and public key pair.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Keypair(secp256k1::Keypair);
+
+impl Keypair {
+ /// Generates a new random key pair.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # #[cfg(all(feature = "rand", feature = "std"))] {
+ /// use bitcoin::{secp256k1::rand, Keypair};
+ ///
+ /// let keypair = Keypair::generate(&mut rand::rng());
+ /// # }
+ /// ```
+ #[inline]
+ #[cfg(feature = "rand")]
+ pub fn generate<R: secp256k1::rand::Rng + ?Sized>(rng: &mut R) -> Self {
+ Self::from(secp256k1::Keypair::new(rng))
+ }
+
+ /// Creates a [`Keypair`] directly from a secp256k1 secret key.
+ #[inline]
+ pub fn from_secret_key(sk: &secp256k1::SecretKey) -> Self {
+ Self::from(secp256k1::Keypair::from_secret_key(sk))
+ }
+
+ /// Returns the inner [`secp256k1::Keypair`].
+ #[inline]
+ pub fn to_inner(self) -> secp256k1::Keypair { self.0 }
+
+ /// Returns the [`PrivateKey`] for this [`Keypair`].
+ ///
+ /// This is equivalent to using [`secp256k1::SecretKey::from_keypair`] on the inner value.
+ #[inline]
+ pub fn to_secret_key(self) -> secp256k1::SecretKey { secp256k1::SecretKey::from_keypair(&self.to_inner()) }
+
+ /// Returns the secret bytes for this [`Keypair`].
+ #[inline]
+ pub fn to_secret_bytes(self) -> [u8; constants::SECRET_KEY_SIZE] { self.to_inner().to_secret_bytes() }
+
+ /// Returns the [`PublicKey`] for this [`Keypair`].
+ ///
+ /// This is equivalent to using [`PublicKey::from_keypair`].
+ #[inline]
+ pub fn to_public_key(self) -> PublicKey { PublicKey::from_keypair(&self) }
+
+ /// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for this [`Keypair`].
+ ///
+ /// This is equivalent to using [`XOnlyPublicKey::from_keypair`].
+ #[inline]
+ pub fn to_x_only_public_key(self) -> (XOnlyPublicKey, Parity) {
+ XOnlyPublicKey::from_keypair(&self)
+ }
+}
+
+impl FromStr for Keypair {
+ type Err = ParseKeypairError;
+ fn from_str(s: &str) -> Result<Self, ParseKeypairError> {
+ secp256k1::Keypair::from_str(s)
+ .map(Self::from)
+ .map_err(ParseKeypairError)
+ }
+}
+
+impl From<secp256k1::Keypair> for Keypair {
+ fn from(pk: secp256k1::Keypair) -> Self { Self(pk) }
+}
+
+impl From<Keypair> for secp256k1::PublicKey {
+ fn from(kp: Keypair) -> Self { kp.to_public_key().inner }
+}
+
/// A Bitcoin ECDSA public key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PublicKey {
@@ -314,6 +389,11 @@ impl PublicKey {
/// Computes the public key as supposed to be used with this secret.
pub fn from_private_key(sk: PrivateKey) -> Self { sk.public_key() }
+ /// Extracts the public key from a Keypair
+ pub fn from_keypair(pair: &Keypair) -> Self {
+ Self::new(secp256k1::PublicKey::from_keypair(&pair.to_inner()))
+ }
+
/// Checks that `sig` is a valid ECDSA signature for `msg` using this public key.
pub fn verify(
&self,
@@ -861,7 +941,7 @@ pub type UntweakedKeypair = Keypair;
/// # #[cfg(all(feature = "rand", feature = "std"))] {
/// # use bitcoin::key::{Keypair, TweakedKeypair, TweakedPublicKey};
/// # use bitcoin::secp256k1::rand;
-/// # let keypair = TweakedKeypair::dangerous_assume_tweaked(Keypair::new(&mut rand::rng()));
+/// # let keypair = TweakedKeypair::dangerous_assume_tweaked(Keypair::generate(&mut rand::rng()));
/// // There are various conversion methods available to get a tweaked pubkey from a tweaked keypair.
/// let (_pk, _parity) = keypair.public_parts();
/// let _pk = TweakedPublicKey::from_keypair(keypair);
@@ -947,8 +1027,8 @@ impl TapTweak for UntweakedKeypair {
fn tap_tweak(self, merkle_root: Option<TapNodeHash>) -> TweakedKeypair {
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self);
let tweak = TapTweakHash::from_key_and_merkle_root(pubkey, merkle_root).to_scalar();
- let tweaked = self.add_xonly_tweak(&tweak).expect("Tap tweak failed");
- TweakedKeypair(tweaked)
+ let tweaked = self.to_inner().add_xonly_tweak(&tweak).expect("Tap tweak failed");
+ TweakedKeypair(Self::from(tweaked))
}
fn dangerous_assume_tweaked(self) -> TweakedKeypair { TweakedKeypair(self) }
@@ -958,8 +1038,8 @@ impl TweakedPublicKey {
/// Returns the [`TweakedPublicKey`] for `keypair`.
#[inline]
pub fn from_keypair(keypair: TweakedKeypair) -> Self {
- let (xonly, _parity) = keypair.0.x_only_public_key();
- Self(xonly.into())
+ let (xonly, _parity) = keypair.to_keypair().to_x_only_public_key();
+ Self(xonly)
}
/// Constructs a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider
@@ -1015,8 +1095,8 @@ impl TweakedKeypair {
/// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeypair`].
#[inline]
pub fn public_parts(&self) -> (TweakedPublicKey, Parity) {
- let (xonly, parity) = self.0.x_only_public_key();
- (TweakedPublicKey(xonly.into()), parity)
+ let (xonly, parity) = self.to_keypair().to_x_only_public_key();
+ (TweakedPublicKey(xonly), parity)
}
}
@@ -1027,7 +1107,7 @@ impl From<TweakedPublicKey> for XOnlyPublicKey {
impl From<TweakedKeypair> for Keypair {
#[inline]
- fn from(pair: TweakedKeypair) -> Self { pair.0 }
+ fn from(pair: TweakedKeypair) -> Self { pair.to_keypair() }
}
impl From<TweakedKeypair> for TweakedPublicKey {
@@ -1144,6 +1224,25 @@ impl From<InvalidWifCompressionFlagError> for FromWifError {
fn from(e: InvalidWifCompressionFlagError) -> Self { Self::InvalidWifCompressionFlag(e) }
}
+/// Error returned while constructing a [`Keypair`] from string.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ParseKeypairError(secp256k1::Error);
+
+impl From<Infallible> for ParseKeypairError {
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for ParseKeypairError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write_err!(f, "parse keypair failed"; self.0)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for ParseKeypairError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
+}
+
/// Error returned while constructing public key from string.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParsePublicKeyError {
@@ -1705,7 +1804,7 @@ mod tests {
fn public_key_constructors() {
use secp256k1::rand;
- let kp = Keypair::new(&mut rand::rng());
+ let kp = Keypair::generate(&mut rand::rng());
let _ = PublicKey::new(kp);
let _ = PublicKey::new_uncompressed(kp);
@@ -1819,4 +1918,21 @@ mod tests {
// Confirm that the into_inner() returns the same data that was initially wrapped
assert_eq!(inner_key, btc_pubkey.into_inner());
}
+
+ #[test]
+ fn keypair_from_str_roundtrip() {
+ #[cfg(all(feature = "rand", feature = "std"))]
+ let keypair = Keypair::generate(&mut rand::rng());
+ #[cfg(not(all(feature = "rand", feature = "std")))]
+ let keypair = {
+ let bytes = <[u8; 32]>::from_hex("1ede31b0e7e47c2afc65ffd158b1b1b9d3b752bba8fd117dc8b9e944a390e8d9").unwrap();
+ let sk = PrivateKey::from_byte_array(bytes, NetworkKind::Test).unwrap();
+ Keypair::from_secret_key(&sk.inner)
+ };
+
+ // Use secp256k1::DisplaySecret, since no key type implements Display
+ let encoded = format!("{}", keypair.to_inner().display_secret());
+ let decoded = encoded.parse::<Keypair>().unwrap();
+ assert_eq!(decoded, keypair);
+ }
}
diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs
index 5b300515..d396e988 100644
--- a/bitcoin/src/crypto/sighash.rs
+++ b/bitcoin/src/crypto/sighash.rs
@@ -1869,7 +1869,8 @@ mod tests {
use crate::consensus::serde as con_serde;
use crate::crypto::key::XOnlyPublicKey;
- use crate::taproot::{TapNodeHash, TapTweakHash};
+ use crate::key::{Keypair, TapTweak};
+ use crate::taproot::TapNodeHash;
#[derive(serde::Deserialize)]
struct UtxoSpent {
@@ -1912,7 +1913,6 @@ mod tests {
#[serde(rename_all = "camelCase")]
struct KpsInputSpendingIntermediary {
internal_pubkey: XOnlyPublicKey,
- tweak: TapTweakHash,
tweaked_privkey: SecretKey,
sig_msg: String,
//precomputed_used: Vec<String>, // unused
@@ -1993,10 +1993,9 @@ mod tests {
};
// tests
- let keypair = secp256k1::Keypair::from_secret_key(&internal_priv_key);
+ let keypair = Keypair::from_secret_key(&internal_priv_key);
let (internal_key, _parity) = XOnlyPublicKey::from_keypair(&keypair);
- let tweak = TapTweakHash::from_key_and_merkle_root(internal_key, merkle_root);
- let tweaked_keypair = keypair.add_xonly_tweak(&tweak.to_scalar()).unwrap();
+ let tweaked_keypair = keypair.tap_tweak(merkle_root);
let mut sig_msg = Vec::new();
cache
.taproot_encode_signing_data_to(
@@ -2014,18 +2013,17 @@ mod tests {
let key_spend_sig = secp256k1::schnorr::sign_with_aux_rand(
&sighash.to_byte_array(),
- &tweaked_keypair,
+ &tweaked_keypair.to_keypair().to_inner(),
&[0u8; 32],
);
assert_eq!(expected.internal_pubkey, internal_key);
- assert_eq!(expected.tweak, tweak);
assert_eq!(expected.sig_msg, sig_msg.to_lower_hex_string());
assert_eq!(expected.sig_hash, sighash);
assert_eq!(expected_hash_ty, hash_ty);
assert_eq!(expected_key_spend_sig, key_spend_sig);
- let tweaked_priv_key = SecretKey::from_keypair(&tweaked_keypair);
+ let tweaked_priv_key = SecretKey::from_keypair(&tweaked_keypair.to_keypair().to_inner());
assert_eq!(expected.tweaked_privkey, tweaked_priv_key);
}
}
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index 525814a3..20beada7 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -178,7 +178,7 @@ pub use crate::{
address::{Address, AddressType, KnownHrp},
bip32::XKeyIdentifier,
crypto::ecdsa,
- crypto::key::{self, CompressedPublicKey, PrivateKey, PublicKey, XOnlyPublicKey},
+ crypto::key::{self, CompressedPublicKey, Keypair, PrivateKey, PublicKey, XOnlyPublicKey},
crypto::sighash::{self, LegacySighash, SegwitV0Sighash, TapSighash, TapSighashTag},
merkle_tree::MerkleBlock,
network::params::{self, Params},
diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs
index 1da03944..0fa077f3 100644
--- a/bitcoin/src/psbt/mod.rs
+++ b/bitcoin/src/psbt/mod.rs
@@ -19,12 +19,12 @@ use core::{cmp, fmt};
use std::collections::{HashMap, HashSet};
use internals::write_err;
-use secp256k1::{Keypair, Message};
+use secp256k1::Message;
use crate::bip32::{self, KeySource, Xpriv, Xpub};
use crate::crypto::key::{PrivateKey, PublicKey};
use crate::crypto::{ecdsa, taproot};
-use crate::key::{TapTweak, XOnlyPublicKey};
+use crate::key::{TapTweak, XOnlyPublicKey, Keypair};
use crate::prelude::{btree_map, BTreeMap, BTreeSet, Borrow, Box, Vec};
use crate::script::{ScriptExt as _, ScriptPubKeyExt as _};
use crate::sighash::{self, EcdsaSighashType, Prevouts, SighashCache};
@@ -432,10 +432,10 @@ impl Psbt {
.to_keypair();
#[cfg(all(feature = "rand", feature = "std"))]
- let signature = secp256k1::schnorr::sign(&sighash.to_byte_array(), &key_pair);
+ let signature = secp256k1::schnorr::sign(&sighash.to_byte_array(), &key_pair.to_inner());
#[cfg(not(all(feature = "rand", feature = "std")))]
let signature =
- secp256k1::schnorr::sign_no_aux_rand(&sighash.to_byte_array(), &key_pair);
+ secp256k1::schnorr::sign_no_aux_rand(&sighash.to_byte_array(), &key_pair.to_inner());
let signature = taproot::Signature { signature, sighash_type };
input.tap_key_sig = Some(signature);
@@ -461,11 +461,11 @@ impl Psbt {
#[cfg(all(feature = "rand", feature = "std"))]
let signature =
- secp256k1::schnorr::sign(&sighash.to_byte_array(), &key_pair);
+ secp256k1::schnorr::sign(&sighash.to_byte_array(), &key_pair.to_inner());
#[cfg(not(all(feature = "rand", feature = "std")))]
let signature = secp256k1::schnorr::sign_no_aux_rand(
&sighash.to_byte_array(),
- &key_pair,
+ &key_pair.to_inner(),
);
let signature = taproot::Signature { signature, sighash_type };
diff --git a/bitcoin/tests/psbt-sign-taproot.rs b/bitcoin/tests/psbt-sign-taproot.rs
index 294d9276..a9bcb67c 100644
--- a/bitcoin/tests/psbt-sign-taproot.rs
+++ b/bitcoin/tests/psbt-sign-taproot.rs
@@ -12,10 +12,9 @@ use bitcoin::script::TapScriptExt as _;
use bitcoin::taproot::{LeafVersion, TaprootBuilder, TaprootSpendInfo};
use bitcoin::transaction::Version;
use bitcoin::{
- absolute, script, Address, Amount, Network, OutPoint, PrivateKey, Psbt, ScriptSigBuf, Sequence,
- TapScriptBuf, Transaction, TxIn, TxOut, Witness, XOnlyPublicKey,
+ absolute, script, Address, Amount, Keypair, Network, OutPoint, PrivateKey, Psbt,
+ ScriptSigBuf, Sequence, TapScriptBuf, Transaction, TxIn, TxOut, Witness, XOnlyPublicKey,
};
-use secp256k1::Keypair;
#[test]
fn psbt_sign_taproot() {
@@ -58,7 +57,7 @@ fn psbt_sign_taproot() {
// Just use one of the secret keys for the key path spend.
let kp = sk_path[2].0.parse::<Keypair>().expect("failed to create keypair");
- let internal_key = kp.x_only_public_key().0; // Ignore the parity.
+ let internal_key = kp.to_x_only_public_key().0; // Ignore the parity.
let tree = create_taproot_tree(script1, script2.clone(), script3, internal_key);
@@ -85,7 +84,7 @@ fn psbt_sign_taproot() {
//
let keystore = Keystore {
mfp: mfp.parse::<Fingerprint>().unwrap(),
- sk: PrivateKey::new(kp.secret_key(), Network::Testnet(bitcoin::TestnetVersion::V3)),
+ sk: PrivateKey::new(kp.to_secret_key(), Network::Testnet(bitcoin::TestnetVersion::V3)),
};
let _ = psbt_key_path_spend.sign(&keystore);
@@ -110,12 +109,12 @@ fn psbt_sign_taproot() {
{
// use private key of path "m/86'/1'/0'/0/1" as signing key
let kp = sk_path[1].0.parse::<Keypair>().expect("failed to create keypair");
- let x_only_pubkey = kp.x_only_public_key().0;
+ let x_only_pubkey = kp.to_x_only_public_key().0;
let signing_key_path = sk_path[1].1;
let keystore = Keystore {
mfp: mfp.parse::<Fingerprint>().unwrap(),
- sk: PrivateKey::new(kp.secret_key(), Network::Testnet(bitcoin::TestnetVersion::V3)),
+ sk: PrivateKey::new(kp.to_secret_key(), Network::Testnet(bitcoin::TestnetVersion::V3)),
};
//
@@ -140,7 +139,7 @@ fn psbt_sign_taproot() {
sig,
psbt_script_path_spend.inputs[0]
.tap_script_sigs
- .get(&(x_only_pubkey.into(), script2.tapscript_leaf_hash()))
+ .get(&(x_only_pubkey, script2.tapscript_leaf_hash()))
.unwrap()
.signature
.to_string()
@@ -163,7 +162,7 @@ fn psbt_sign_taproot() {
fn create_basic_single_sig_script(sk: &str) -> TapScriptBuf {
let kp = sk.parse::<Keypair>().expect("failed to create keypair");
- let x_only_pubkey = kp.x_only_public_key().0;
+ let x_only_pubkey = kp.to_x_only_public_key().0;
script::Builder::new()
.push_slice(x_only_pubkey.serialize())
.push_opcode(OP_CHECKSIG)
Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.