Accept flexible input types for Taproot-related functions

Refactor Taproot functions to accept any type implementing `Into<XOnlyPublicKey>`,
instead of requiring `XOnlyPublicKey` directly. This improves ergonomics when working
with compatible types, avoiding unnecessary `.into()` conversions at call sites.
This commit is contained in:
Erick Cestari 2025-04-28 14:28:11 -03:00
parent 2a518d62e6
commit c11772a768
No known key found for this signature in database
GPG Key ID: D7D17E26F2FC3F3C
14 changed files with 65 additions and 46 deletions

View File

@ -26,7 +26,7 @@ fn main() {
// Get an unspent output that is locked to the key above that we control. // Get an unspent output that is locked to the key above that we control.
// In a real application these would come from the chain. // In a real application these would come from the chain.
let (dummy_out_point, dummy_utxo) = dummy_unspent_transaction_output(&secp, internal_key.into()); let (dummy_out_point, dummy_utxo) = dummy_unspent_transaction_output(&secp, internal_key);
// Get an address to send to. // Get an address to send to.
let address = receivers_address(); let address = receivers_address();
@ -45,7 +45,7 @@ fn main() {
// The change output is locked to a key controlled by us. // The change output is locked to a key controlled by us.
let change = TxOut { let change = TxOut {
value: CHANGE_AMOUNT, value: CHANGE_AMOUNT,
script_pubkey: ScriptBuf::new_p2tr(&secp, internal_key.into(), None), // Change comes back to us. script_pubkey: ScriptBuf::new_p2tr(&secp, internal_key, None), // Change comes back to us.
}; };
// The transaction we want to sign and broadcast. // The transaction we want to sign and broadcast.
@ -113,10 +113,11 @@ fn receivers_address() -> Address {
/// ///
/// This output is locked to keys that we control, in a real application this would be a valid /// This output is locked to keys that we control, in a real application this would be a valid
/// output taken from a transaction that appears in the chain. /// output taken from a transaction that appears in the chain.
fn dummy_unspent_transaction_output<C: Verification>( fn dummy_unspent_transaction_output<C: Verification, K: Into<UntweakedPublicKey>>(
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
) -> (OutPoint, TxOut) { ) -> (OutPoint, TxOut) {
let internal_key = internal_key.into();
let script_pubkey = ScriptBuf::new_p2tr(secp, internal_key, None); let script_pubkey = ScriptBuf::new_p2tr(secp, internal_key, None);
let out_point = OutPoint { let out_point = OutPoint {

View File

@ -83,11 +83,12 @@ fn get_internal_address_xpriv<C: Signing>(
} }
// Get the Taproot Key Origin. // Get the Taproot Key Origin.
fn get_tap_key_origin( fn get_tap_key_origin<K: Into<UntweakedPublicKey> + std::cmp::Ord>(
x_only_key: UntweakedPublicKey, x_only_key: K,
master_fingerprint: Fingerprint, master_fingerprint: Fingerprint,
path: DerivationPath, path: DerivationPath,
) -> BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, (Fingerprint, DerivationPath))> { ) -> BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, (Fingerprint, DerivationPath))> {
let x_only_key = x_only_key.into();
let mut map = BTreeMap::new(); let mut map = BTreeMap::new();
map.insert(x_only_key, (vec![], (master_fingerprint, path))); map.insert(x_only_key, (vec![], (master_fingerprint, path)));
map map
@ -151,12 +152,12 @@ fn main() {
// Get the Tap Key Origins // Get the Tap Key Origins
// Map of tap root X-only keys to origin info and leaf hashes contained in it. // Map of tap root X-only keys to origin info and leaf hashes contained in it.
let origin_input_1 = get_tap_key_origin( let origin_input_1 = get_tap_key_origin(
pk_input_1.into(), pk_input_1,
MASTER_FINGERPRINT.parse::<Fingerprint>().unwrap(), MASTER_FINGERPRINT.parse::<Fingerprint>().unwrap(),
"m/86'/0'/0'/0/0".parse::<DerivationPath>().unwrap(), "m/86'/0'/0'/0/0".parse::<DerivationPath>().unwrap(),
); );
let origin_input_2 = get_tap_key_origin( let origin_input_2 = get_tap_key_origin(
pk_input_2.into(), pk_input_2,
MASTER_FINGERPRINT.parse::<Fingerprint>().unwrap(), MASTER_FINGERPRINT.parse::<Fingerprint>().unwrap(),
"m/86'/0'/0'/1/0".parse::<DerivationPath>().unwrap(), "m/86'/0'/0'/1/0".parse::<DerivationPath>().unwrap(),
); );
@ -187,7 +188,7 @@ fn main() {
// The change output is locked to a key controlled by us. // The change output is locked to a key controlled by us.
let change = TxOut { let change = TxOut {
value: CHANGE_AMOUNT, value: CHANGE_AMOUNT,
script_pubkey: ScriptBuf::new_p2tr(&secp, pk_change.into(), None), // Change comes back to us. script_pubkey: ScriptBuf::new_p2tr(&secp, pk_change, None), // Change comes back to us.
}; };
// The transaction we want to sign and broadcast. // The transaction we want to sign and broadcast.

View File

@ -404,7 +404,7 @@ impl BenefactorWallet {
let taproot_spend_info = TaprootBuilder::new() let taproot_spend_info = TaprootBuilder::new()
.add_leaf(0, script.clone())? .add_leaf(0, script.clone())?
.finalize(&self.secp, internal_keypair.x_only_public_key().0.into()) .finalize(&self.secp, internal_keypair.x_only_public_key().0)
.expect("should be finalizable"); .expect("should be finalizable");
self.current_spend_info = Some(taproot_spend_info.clone()); self.current_spend_info = Some(taproot_spend_info.clone());
let script_pubkey = ScriptBuf::new_p2tr( let script_pubkey = ScriptBuf::new_p2tr(
@ -502,7 +502,7 @@ impl BenefactorWallet {
let taproot_spend_info = TaprootBuilder::new() let taproot_spend_info = TaprootBuilder::new()
.add_leaf(0, script.clone())? .add_leaf(0, script.clone())?
.finalize(&self.secp, new_internal_keypair.x_only_public_key().0.into()) .finalize(&self.secp, new_internal_keypair.x_only_public_key().0)
.expect("should be finalizable"); .expect("should be finalizable");
self.current_spend_info = Some(taproot_spend_info.clone()); self.current_spend_info = Some(taproot_spend_info.clone());
let prevout_script_pubkey = input.witness_utxo.as_ref().unwrap().script_pubkey.clone(); let prevout_script_pubkey = input.witness_utxo.as_ref().unwrap().script_pubkey.clone();

View File

@ -59,6 +59,7 @@ use crate::constants::{
}; };
use crate::crypto::key::{ use crate::crypto::key::{
CompressedPublicKey, PubkeyHash, PublicKey, TweakedPublicKey, UntweakedPublicKey, CompressedPublicKey, PubkeyHash, PublicKey, TweakedPublicKey, UntweakedPublicKey,
XOnlyPublicKey,
}; };
use crate::network::{Network, NetworkKind, Params}; use crate::network::{Network, NetworkKind, Params};
use crate::prelude::{String, ToOwned}; use crate::prelude::{String, ToOwned};
@ -69,7 +70,6 @@ use crate::script::{
WitnessScriptSizeError, WitnessScriptSizeError,
}; };
use crate::taproot::TapNodeHash; use crate::taproot::TapNodeHash;
use crate::XOnlyPublicKey;
#[rustfmt::skip] // Keep public re-exports separate. #[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)] #[doc(inline)]
@ -573,12 +573,13 @@ impl Address {
} }
/// Constructs a new pay-to-Taproot (P2TR) [`Address`] from an untweaked key. /// Constructs a new pay-to-Taproot (P2TR) [`Address`] from an untweaked key.
pub fn p2tr<C: Verification>( pub fn p2tr<C: Verification, K: Into<UntweakedPublicKey>>(
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
merkle_root: Option<TapNodeHash>, merkle_root: Option<TapNodeHash>,
hrp: impl Into<KnownHrp>, hrp: impl Into<KnownHrp>,
) -> Address { ) -> Address {
let internal_key = internal_key.into();
let program = WitnessProgram::p2tr(secp, internal_key, merkle_root); let program = WitnessProgram::p2tr(secp, internal_key, merkle_root);
Address::from_witness_program(program, hrp) Address::from_witness_program(program, hrp)
} }

View File

@ -49,11 +49,12 @@ define_extension_trait! {
/// Computes P2TR output with a given internal key and a single script spending path equal to /// Computes P2TR output with a given internal key and a single script spending path equal to
/// the current script, assuming that the script is a Tapscript. /// the current script, assuming that the script is a Tapscript.
fn to_p2tr<C: Verification>( fn to_p2tr<C: Verification, K: Into<UntweakedPublicKey>>(
&self, &self,
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
) -> ScriptBuf { ) -> ScriptBuf {
let internal_key = internal_key.into();
let leaf_hash = self.tapscript_leaf_hash(); let leaf_hash = self.tapscript_leaf_hash();
let merkle_root = TapNodeHash::from(leaf_hash); let merkle_root = TapNodeHash::from(leaf_hash);
ScriptBuf::new_p2tr(secp, internal_key, Some(merkle_root)) ScriptBuf::new_p2tr(secp, internal_key, Some(merkle_root))
@ -157,11 +158,12 @@ define_extension_trait! {
/// Generates P2TR for script spending path using an internal public key and some optional /// Generates P2TR for script spending path using an internal public key and some optional
/// script tree Merkle root. /// script tree Merkle root.
fn new_p2tr<C: Verification>( fn new_p2tr<C: Verification, K: Into<UntweakedPublicKey>>(
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
merkle_root: Option<TapNodeHash>, merkle_root: Option<TapNodeHash>,
) -> Self { ) -> Self {
let internal_key = internal_key.into();
let (output_key, _) = internal_key.tap_tweak(secp, merkle_root); let (output_key, _) = internal_key.tap_tweak(secp, merkle_root);
// output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1) // output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1)
new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize()) new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize())

View File

@ -15,11 +15,10 @@ use internals::array::ArrayExt;
use internals::write_err; use internals::write_err;
use secp256k1::Secp256k1; use secp256k1::Secp256k1;
use crate::crypto::key::{CompressedPublicKey, Keypair, PrivateKey}; use crate::crypto::key::{CompressedPublicKey, Keypair, PrivateKey, XOnlyPublicKey};
use crate::internal_macros::{impl_array_newtype, impl_array_newtype_stringify}; use crate::internal_macros::{impl_array_newtype, impl_array_newtype_stringify};
use crate::network::NetworkKind; use crate::network::NetworkKind;
use crate::prelude::{String, Vec}; use crate::prelude::{String, Vec};
use crate::XOnlyPublicKey;
/// Version bytes for extended public keys on the Bitcoin network. /// Version bytes for extended public keys on the Bitcoin network.
const VERSION_BYTES_MAINNET_PUBLIC: [u8; 4] = [0x04, 0x88, 0xB2, 0x1E]; const VERSION_BYTES_MAINNET_PUBLIC: [u8; 4] = [0x04, 0x88, 0xB2, 0x1E];

View File

@ -95,11 +95,12 @@ impl WitnessProgram {
/// ///
/// This function applies BIP341 key-tweaking to the untweaked /// This function applies BIP341 key-tweaking to the untweaked
/// key using the merkle root, if it's present. /// key using the merkle root, if it's present.
pub fn p2tr<C: Verification>( pub fn p2tr<C: Verification, K: Into<UntweakedPublicKey>>(
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
merkle_root: Option<TapNodeHash>, merkle_root: Option<TapNodeHash>,
) -> Self { ) -> Self {
let internal_key = internal_key.into();
let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root); let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
let pubkey = output_key.to_inner().serialize(); let pubkey = output_key.to_inner().serialize();
WitnessProgram::new_p2tr(pubkey) WitnessProgram::new_p2tr(pubkey)

View File

@ -129,6 +129,16 @@ impl From<secp256k1::PublicKey> for XOnlyPublicKey {
fn from(pk: secp256k1::PublicKey) -> XOnlyPublicKey { XOnlyPublicKey::new(pk) } fn from(pk: secp256k1::PublicKey) -> XOnlyPublicKey { XOnlyPublicKey::new(pk) }
} }
impl fmt::LowerHex for XOnlyPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
}
// Allocate for serialized size
impl_to_hex_from_lower_hex!(XOnlyPublicKey, |_| constants::SCHNORR_PUBLIC_KEY_SIZE * 2);
impl fmt::Display for XOnlyPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}
/// A Bitcoin ECDSA public key. /// A Bitcoin ECDSA public key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PublicKey { pub struct PublicKey {
@ -842,13 +852,13 @@ pub type UntweakedPublicKey = XOnlyPublicKey;
pub struct TweakedPublicKey(XOnlyPublicKey); pub struct TweakedPublicKey(XOnlyPublicKey);
impl fmt::LowerHex for TweakedPublicKey { impl fmt::LowerHex for TweakedPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0 .0, f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
} }
// Allocate for serialized size // Allocate for serialized size
impl_to_hex_from_lower_hex!(TweakedPublicKey, |_| constants::SCHNORR_PUBLIC_KEY_SIZE * 2); impl_to_hex_from_lower_hex!(TweakedPublicKey, |_| constants::SCHNORR_PUBLIC_KEY_SIZE * 2);
impl fmt::Display for TweakedPublicKey { impl fmt::Display for TweakedPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0 .0, f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
} }
/// Untweaked BIP-340 key pair. /// Untweaked BIP-340 key pair.

View File

@ -1881,8 +1881,8 @@ mod tests {
use secp256k1::SecretKey; use secp256k1::SecretKey;
use crate::consensus::serde as con_serde; use crate::consensus::serde as con_serde;
use crate::crypto::key::XOnlyPublicKey;
use crate::taproot::{TapNodeHash, TapTweakHash}; use crate::taproot::{TapNodeHash, TapTweakHash};
use crate::XOnlyPublicKey;
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
struct UtxoSpent { struct UtxoSpent {

View File

@ -6,7 +6,7 @@ use core::str::FromStr;
use hashes::{hash160, ripemd160, sha256, sha256d}; use hashes::{hash160, ripemd160, sha256, sha256d};
use crate::bip32::KeySource; use crate::bip32::KeySource;
use crate::crypto::key::PublicKey; use crate::crypto::key::{PublicKey, XOnlyPublicKey};
use crate::crypto::{ecdsa, taproot}; use crate::crypto::{ecdsa, taproot};
use crate::prelude::{btree_map, BTreeMap, Borrow, Box, ToOwned, Vec}; use crate::prelude::{btree_map, BTreeMap, Borrow, Box, ToOwned, Vec};
use crate::psbt::map::Map; use crate::psbt::map::Map;
@ -20,7 +20,6 @@ use crate::sighash::{
use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash};
use crate::transaction::{Transaction, TxOut}; use crate::transaction::{Transaction, TxOut};
use crate::witness::Witness; use crate::witness::Witness;
use crate::XOnlyPublicKey;
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
const PSBT_IN_NON_WITNESS_UTXO: u64 = 0x00; const PSBT_IN_NON_WITNESS_UTXO: u64 = 0x00;

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
use crate::bip32::KeySource; use crate::bip32::KeySource;
use crate::crypto::key::XOnlyPublicKey;
use crate::prelude::{btree_map, BTreeMap, Vec}; use crate::prelude::{btree_map, BTreeMap, Vec};
use crate::psbt::map::Map; use crate::psbt::map::Map;
use crate::psbt::{raw, Error}; use crate::psbt::{raw, Error};
use crate::script::ScriptBuf; use crate::script::ScriptBuf;
use crate::taproot::{TapLeafHash, TapTree}; use crate::taproot::{TapLeafHash, TapTree};
use crate::XOnlyPublicKey;
/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00 /// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
const PSBT_OUT_REDEEM_SCRIPT: u64 = 0x00; const PSBT_OUT_REDEEM_SCRIPT: u64 = 0x00;

View File

@ -13,7 +13,7 @@ use internals::slice::SliceExt;
use super::map::{Input, Map, Output, PsbtSighashType}; use super::map::{Input, Map, Output, PsbtSighashType};
use crate::bip32::{ChildNumber, Fingerprint, KeySource}; use crate::bip32::{ChildNumber, Fingerprint, KeySource};
use crate::consensus::encode::{self, deserialize_partial, serialize, Decodable, Encodable}; use crate::consensus::encode::{self, deserialize_partial, serialize, Decodable, Encodable};
use crate::crypto::key::PublicKey; use crate::crypto::key::{PublicKey, XOnlyPublicKey};
use crate::crypto::{ecdsa, taproot}; use crate::crypto::{ecdsa, taproot};
use crate::io::Write; use crate::io::Write;
use crate::prelude::{DisplayHex, String, Vec}; use crate::prelude::{DisplayHex, String, Vec};
@ -24,7 +24,6 @@ use crate::taproot::{
}; };
use crate::transaction::{Transaction, TxOut}; use crate::transaction::{Transaction, TxOut};
use crate::witness::Witness; use crate::witness::Witness;
use crate::XOnlyPublicKey;
/// A trait for serializing a value as raw data for insertion into PSBT /// A trait for serializing a value as raw data for insertion into PSBT
/// key-value maps. /// key-value maps.

View File

@ -97,10 +97,11 @@ impl From<TapLeafHash> for TapNodeHash {
impl TapTweakHash { impl TapTweakHash {
/// Constructs a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where /// Constructs a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where
/// `P` is the internal key and `R` is the Merkle root. /// `P` is the internal key and `R` is the Merkle root.
pub fn from_key_and_tweak( pub fn from_key_and_tweak<K: Into<UntweakedPublicKey>>(
internal_key: UntweakedPublicKey, internal_key: K,
merkle_root: Option<TapNodeHash>, merkle_root: Option<TapNodeHash>,
) -> TapTweakHash { ) -> TapTweakHash {
let internal_key = internal_key.into();
let mut eng = sha256t::Hash::<TapTweakTag>::engine(); let mut eng = sha256t::Hash::<TapTweakTag>::engine();
// always hash the key // always hash the key
eng.input(&internal_key.serialize()); eng.input(&internal_key.serialize());
@ -248,14 +249,15 @@ impl TaprootSpendInfo {
/// weights of satisfaction for that script. /// weights of satisfaction for that script.
/// ///
/// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation. /// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation.
pub fn with_huffman_tree<C, I>( pub fn with_huffman_tree<C, I, K>(
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
script_weights: I, script_weights: I,
) -> Result<Self, TaprootBuilderError> ) -> Result<Self, TaprootBuilderError>
where where
I: IntoIterator<Item = (u32, ScriptBuf)>, I: IntoIterator<Item = (u32, ScriptBuf)>,
C: secp256k1::Verification, C: secp256k1::Verification,
K: Into<UntweakedPublicKey>,
{ {
let builder = TaprootBuilder::with_huffman_tree(script_weights)?; let builder = TaprootBuilder::with_huffman_tree(script_weights)?;
Ok(builder.finalize(secp, internal_key).expect("Huffman tree is always complete")) Ok(builder.finalize(secp, internal_key).expect("Huffman tree is always complete"))
@ -272,11 +274,12 @@ impl TaprootSpendInfo {
/// ///
/// Refer to BIP 341 footnote ('Why should the output key always have a Taproot commitment, even /// Refer to BIP 341 footnote ('Why should the output key always have a Taproot commitment, even
/// if there is no script path?') for more details. /// if there is no script path?') for more details.
pub fn new_key_spend<C: secp256k1::Verification>( pub fn new_key_spend<C: secp256k1::Verification, K: Into<UntweakedPublicKey>>(
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
merkle_root: Option<TapNodeHash>, merkle_root: Option<TapNodeHash>,
) -> Self { ) -> Self {
let internal_key = internal_key.into();
let (output_key, parity) = internal_key.tap_tweak(secp, merkle_root); let (output_key, parity) = internal_key.tap_tweak(secp, merkle_root);
Self { Self {
internal_key, internal_key,
@ -312,9 +315,9 @@ impl TaprootSpendInfo {
/// ///
/// This is useful when you want to manually build a Taproot tree without using /// This is useful when you want to manually build a Taproot tree without using
/// [`TaprootBuilder`]. /// [`TaprootBuilder`].
pub fn from_node_info<C: secp256k1::Verification>( pub fn from_node_info<C: secp256k1::Verification, K: Into<UntweakedPublicKey>>(
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
node: NodeInfo, node: NodeInfo,
) -> TaprootSpendInfo { ) -> TaprootSpendInfo {
// Create as if it is a key spend path with the given Merkle root // Create as if it is a key spend path with the given Merkle root
@ -583,11 +586,12 @@ impl TaprootBuilder {
/// ///
/// Returns the unmodified builder as Err if the builder is not finalizable. /// Returns the unmodified builder as Err if the builder is not finalizable.
/// See also [`TaprootBuilder::is_finalizable`] /// See also [`TaprootBuilder::is_finalizable`]
pub fn finalize<C: secp256k1::Verification>( pub fn finalize<C: secp256k1::Verification, K: Into<XOnlyPublicKey>>(
mut self, mut self,
secp: &Secp256k1<C>, secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey, internal_key: K,
) -> Result<TaprootSpendInfo, TaprootBuilder> { ) -> Result<TaprootSpendInfo, TaprootBuilder> {
let internal_key = internal_key.into();
match self.branch.len() { match self.branch.len() {
0 => Ok(TaprootSpendInfo::new_key_spend(secp, internal_key, None)), 0 => Ok(TaprootSpendInfo::new_key_spend(secp, internal_key, None)),
1 => 1 =>

View File

@ -66,7 +66,7 @@ fn psbt_sign_taproot() {
let internal_key = kp.x_only_public_key().0; // Ignore the parity. let internal_key = kp.x_only_public_key().0; // Ignore the parity.
let tree = let tree =
create_taproot_tree(secp, script1.clone(), script2.clone(), script3.clone(), internal_key.into()); create_taproot_tree(secp, script1.clone(), script2.clone(), script3.clone(), internal_key);
let address = create_p2tr_address(tree.clone()); let address = create_p2tr_address(tree.clone());
assert_eq!( assert_eq!(
@ -131,7 +131,7 @@ fn psbt_sign_taproot() {
address, address,
to_address, to_address,
tree.clone(), tree.clone(),
x_only_pubkey.into(), x_only_pubkey,
signing_key_path, signing_key_path,
script2.clone(), script2.clone(),
); );
@ -176,13 +176,14 @@ fn create_basic_single_sig_script(secp: &Secp256k1<secp256k1::All>, sk: &str) ->
.into_script() .into_script()
} }
fn create_taproot_tree( fn create_taproot_tree<K: Into<XOnlyPublicKey>>(
secp: &Secp256k1<secp256k1::All>, secp: &Secp256k1<secp256k1::All>,
script1: ScriptBuf, script1: ScriptBuf,
script2: ScriptBuf, script2: ScriptBuf,
script3: ScriptBuf, script3: ScriptBuf,
internal_key: XOnlyPublicKey, internal_key: K,
) -> TaprootSpendInfo { ) -> TaprootSpendInfo {
let internal_key = internal_key.into();
let builder = TaprootBuilder::new(); let builder = TaprootBuilder::new();
let builder = builder.add_leaf(2, script1).unwrap(); let builder = builder.add_leaf(2, script1).unwrap();
let builder = builder.add_leaf(2, script2).unwrap(); let builder = builder.add_leaf(2, script2).unwrap();
@ -267,14 +268,15 @@ fn finalize_psbt_for_key_path_spend(mut psbt: Psbt) -> Psbt {
psbt psbt
} }
fn create_psbt_for_taproot_script_path_spend( fn create_psbt_for_taproot_script_path_spend<K: Into<XOnlyPublicKey>>(
from_address: Address, from_address: Address,
to_address: Address, to_address: Address,
tree: TaprootSpendInfo, tree: TaprootSpendInfo,
x_only_pubkey_of_signing_key: XOnlyPublicKey, x_only_pubkey_of_signing_key: K,
signing_key_path: &str, signing_key_path: &str,
use_script: ScriptBuf, use_script: ScriptBuf,
) -> Psbt { ) -> Psbt {
let x_only_pubkey_of_signing_key = x_only_pubkey_of_signing_key.into();
let utxo_value = 6280; let utxo_value = 6280;
let send_value = 6000; let send_value = 6000;
let mfp = "73c5da0a"; let mfp = "73c5da0a";