Introduce signing functions on sighash types
What changed, and why it matters
This commit adds convenience helper methods that let developers sign Bitcoin transaction hash values more directly. It does not change any security-critical behavior; the same cryptographic signing operations were already available through other functions. The change is purely an API usability improvement.
No security action required; review as a normal API refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces sign() on LegacySighash and SegwitV0Sighash, plus sign_key_spend() and sign_script_spend() on TapSighash. These helpers internally call the existing PrivateKey::raw_ecdsa_sign and Keypair::raw_bip340_sign routines and wrap the result with the appropriate sighash type. The examples are updated to use the new helpers. No cryptographic logic, validation, or consensus code is modified.
Changed components
bitcoin/src/crypto/sighash.rsbitcoin/examples/sign-tx-segwit-v0.rsbitcoin/examples/sign-tx-taproot.rsInspect captured patch +53 / −8
diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs
index 6163d9f2..4a420a27 100644
--- a/bitcoin/examples/sign-tx-segwit-v0.rs
+++ b/bitcoin/examples/sign-tx-segwit-v0.rs
@@ -7,8 +7,8 @@ use bitcoin::key::WPubkeyHash;
use bitcoin::locktime::absolute;
use bitcoin::sighash::{EcdsaSighashType, SighashCache};
use bitcoin::{
- ecdsa, transaction, Address, Amount, Network, OutPoint, PrivateKey, ScriptPubKeyBuf,
- ScriptSigBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness,
+ transaction, Address, Amount, Network, OutPoint, PrivateKey, ScriptPubKeyBuf, ScriptSigBuf,
+ Sequence, Transaction, TxIn, TxOut, Txid, Witness,
};
const DUMMY_UTXO_AMOUNT: Amount = Amount::from_sat_u32(20_000_000);
@@ -66,7 +66,7 @@ fn main() {
.expect("failed to create sighash");
// Sign the sighash using the private key.
- let signature = ecdsa::Signature { signature: sk.raw_ecdsa_sign(sighash), sighash_type };
+ let signature = sighash.sign(&sk, sighash_type);
// Update the witness stack.
let pk = sk.to_public_key();
diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs
index cc7961d3..e5157a58 100644
--- a/bitcoin/examples/sign-tx-taproot.rs
+++ b/bitcoin/examples/sign-tx-taproot.rs
@@ -64,12 +64,9 @@ fn main() {
.taproot_key_spend_signature_hash(input_index, &prevouts, sighash_type)
.expect("failed to construct sighash");
- // Sign the sighash using the secp256k1 library (exported by rust-bitcoin).
+ // Sign the sighash and update the witness stack.
let tweaked: TweakedKeypair = keypair.tap_tweak(None);
- let signature = tweaked.as_keypair().raw_bip340_sign(&sighash.to_byte_array());
-
- // Update the witness stack.
- let signature = bitcoin::taproot::Signature { signature, sighash_type };
+ let signature = sighash.sign_key_spend(&tweaked, sighash_type);
*sighasher.witness_mut(input_index).unwrap() = Witness::p2tr_key_spend(&signature);
// Get the signed transaction.
diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs
index f13d1e8c..5caf9493 100644
--- a/bitcoin/src/crypto/sighash.rs
+++ b/bitcoin/src/crypto/sighash.rs
@@ -16,6 +16,8 @@ use core::str;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
+use crypto::key::{TweakedKeypair, UntweakedKeypair};
+use crypto::{ecdsa, taproot, PrivateKey};
use hashes::{hash_newtype, sha256, sha256d, sha256t, sha256t_tag};
use io::Write;
@@ -81,10 +83,24 @@ impl_message_from_hash!(SegwitV0Sighash);
impl LegacySighash {
fn engine() -> sha256d::HashEngine { sha256d::Hash::engine() }
fn from_engine(e: sha256d::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) }
+
+ /// Signs this sighash using `pk`.
+ ///
+ /// `sighash_type` must be the same as that used to create the sighash.
+ pub fn sign(&self, pk: &PrivateKey, sighash_type: EcdsaSighashType) -> ecdsa::Signature {
+ ecdsa::Signature { signature: pk.raw_ecdsa_sign(*self), sighash_type }
+ }
}
impl SegwitV0Sighash {
fn engine() -> sha256d::HashEngine { sha256d::Hash::engine() }
fn from_engine(e: sha256d::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) }
+
+ /// Signs this sighash using `pk`.
+ ///
+ /// `sighash_type` must be the same as that used to create the sighash.
+ pub fn sign(&self, pk: &PrivateKey, sighash_type: EcdsaSighashType) -> ecdsa::Signature {
+ ecdsa::Signature { signature: pk.raw_ecdsa_sign(*self), sighash_type }
+ }
}
sha256t_tag! {
@@ -102,6 +118,38 @@ hashes::impl_hex_for_newtype!(TapSighash);
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapSighash);
+impl TapSighash {
+ /// Signs the sighash for a P2TR key-path spending transaction with the
+ /// [`TweakedKeypair`] and creates a Taproot signature as defined in [BIP-340].
+ ///
+ /// For P2TR script-path spend use [`TapSighash::sign_script_spend`].
+ ///
+ /// [BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
+ pub fn sign_key_spend(
+ &self,
+ keypair: &TweakedKeypair,
+ sighash_type: TapSighashType,
+ ) -> taproot::Signature {
+ let signature = keypair.as_keypair().raw_bip340_sign(self.as_ref());
+ taproot::Signature { signature, sighash_type }
+ }
+
+ /// Signs the sighash with an [`UntweakedKeypair`] without applying a tweak and creates a
+ /// taproot signature as defined in [BIP-340].
+ ///
+ /// For P2TR key spend use [`TapSighash::sign_key_spend`].
+ ///
+ /// [BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
+ pub fn sign_script_spend(
+ &self,
+ keypair: &UntweakedKeypair,
+ sighash_type: TapSighashType,
+ ) -> taproot::Signature {
+ let signature = keypair.raw_bip340_sign(self.as_ref());
+ taproot::Signature { signature, sighash_type }
+ }
+}
+
/// Efficiently calculates signature hash message for legacy, SegWit and Taproot inputs.
#[derive(Debug, Clone)]
pub struct SighashCache<T: Borrow<Transaction>> {
Why this scored 15/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.