diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs index 00cedd4f1..a68c968b4 100644 --- a/bitcoin/examples/sign-tx-taproot.rs +++ b/bitcoin/examples/sign-tx-taproot.rs @@ -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 /// output taken from a transaction that appears in the chain. -fn dummy_unspent_transaction_output( +fn dummy_unspent_transaction_output>( secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, ) -> (OutPoint, TxOut) { + let internal_key = internal_key.into(); let script_pubkey = ScriptBuf::new_p2tr(secp, internal_key, None); let out_point = OutPoint { diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs index 0105dc59f..c35dbe463 100644 --- a/bitcoin/examples/taproot-psbt-simple.rs +++ b/bitcoin/examples/taproot-psbt-simple.rs @@ -85,11 +85,12 @@ fn get_internal_address_xpriv( } // Get the Taproot Key Origin. -fn get_tap_key_origin( - x_only_key: UntweakedPublicKey, +fn get_tap_key_origin + std::cmp::Ord>( + x_only_key: K, master_fingerprint: Fingerprint, path: DerivationPath, ) -> BTreeMap, (Fingerprint, DerivationPath))> { + let x_only_key = x_only_key.into(); let mut map = BTreeMap::new(); map.insert(x_only_key, (vec![], (master_fingerprint, path))); map @@ -212,14 +213,14 @@ fn main() { Input { witness_utxo: Some(utxos[0].clone()), tap_key_origins: origins[0].clone(), - tap_internal_key: Some(pk_input_1), + tap_internal_key: Some(pk_input_1.into()), sighash_type: Some(ty), ..Default::default() }, Input { witness_utxo: Some(utxos[1].clone()), tap_key_origins: origins[1].clone(), - tap_internal_key: Some(pk_input_2), + tap_internal_key: Some(pk_input_2.into()), sighash_type: Some(ty), ..Default::default() }, diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index 040b0857e..39b70f9f4 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -444,7 +444,7 @@ impl BenefactorWallet { (vec![leaf_hash], (self.beneficiary_xpub.fingerprint(), derivation_path.clone())), ); origins.insert( - internal_keypair.x_only_public_key().0, + internal_keypair.x_only_public_key().0.into(), (vec![], (self.master_xpriv.fingerprint(&self.secp), derivation_path)), ); let ty = "SIGHASH_ALL".parse::()?; @@ -459,7 +459,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), + tap_internal_key: Some(internal_keypair.x_only_public_key().0.into()), tap_scripts, ..Default::default() }; @@ -612,7 +612,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), + tap_internal_key: Some(new_internal_keypair.x_only_public_key().0.into()), tap_scripts, ..Default::default() }; diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index b178612d2..c2a0b1a75 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -50,7 +50,7 @@ use bech32::primitives::gf32::Fe32; use bech32::primitives::hrp::Hrp; use hashes::{hash160, HashEngine}; use internals::array::ArrayExt; -use secp256k1::{Secp256k1, Verification, XOnlyPublicKey}; +use secp256k1::{Secp256k1, Verification}; use crate::address::script_pubkey::ScriptBufExt as _; use crate::constants::{ @@ -59,6 +59,7 @@ use crate::constants::{ }; use crate::crypto::key::{ CompressedPublicKey, PubkeyHash, PublicKey, TweakedPublicKey, UntweakedPublicKey, + XOnlyPublicKey, }; use crate::network::{Network, NetworkKind, Params}; use crate::prelude::{String, ToOwned}; @@ -572,12 +573,13 @@ impl Address { } /// Constructs a new pay-to-Taproot (P2TR) [`Address`] from an untweaked key. - pub fn p2tr( + pub fn p2tr>( secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, merkle_root: Option, hrp: impl Into, ) -> Address { + let internal_key = internal_key.into(); let program = WitnessProgram::p2tr(secp, internal_key, merkle_root); Address::from_witness_program(program, hrp) } diff --git a/bitcoin/src/address/script_pubkey.rs b/bitcoin/src/address/script_pubkey.rs index a8f902667..bc3637de3 100644 --- a/bitcoin/src/address/script_pubkey.rs +++ b/bitcoin/src/address/script_pubkey.rs @@ -49,11 +49,12 @@ define_extension_trait! { /// 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. - fn to_p2tr( + fn to_p2tr>( &self, secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, ) -> ScriptBuf { + let internal_key = internal_key.into(); let leaf_hash = self.tapscript_leaf_hash(); let merkle_root = TapNodeHash::from(leaf_hash); 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 /// script tree Merkle root. - fn new_p2tr( + fn new_p2tr>( secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, merkle_root: Option, ) -> Self { + let internal_key = internal_key.into(); 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) new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize()) diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 12be7a31c..22ed79d7a 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -13,9 +13,9 @@ use core::{fmt, slice}; use hashes::{hash160, hash_newtype, sha512, Hash, HashEngine, Hmac, HmacEngine}; use internals::array::ArrayExt; use internals::write_err; -use secp256k1::{Secp256k1, XOnlyPublicKey}; +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::network::NetworkKind; use crate::prelude::{String, Vec}; diff --git a/bitcoin/src/blockdata/script/witness_program.rs b/bitcoin/src/blockdata/script/witness_program.rs index 79a22dc8a..7ef28b846 100644 --- a/bitcoin/src/blockdata/script/witness_program.rs +++ b/bitcoin/src/blockdata/script/witness_program.rs @@ -95,11 +95,12 @@ impl WitnessProgram { /// /// This function applies BIP341 key-tweaking to the untweaked /// key using the merkle root, if it's present. - pub fn p2tr( + pub fn p2tr>( secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, merkle_root: Option, ) -> Self { + let internal_key = internal_key.into(); let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root); let pubkey = output_key.as_x_only_public_key().serialize(); WitnessProgram::new_p2tr(pubkey) diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index 70699ab74..2b5bf86b2 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -25,11 +25,120 @@ use crate::script::{self, ScriptBuf}; use crate::taproot::{TapNodeHash, TapTweakHash}; #[rustfmt::skip] // Keep public re-exports separate. -pub use secp256k1::{constants, Keypair, Parity, Secp256k1, Verification, XOnlyPublicKey}; +pub use secp256k1::{constants, Keypair, Parity, Secp256k1, Verification}; #[cfg(feature = "rand-std")] pub use secp256k1::rand; pub use serialized_x_only::SerializedXOnlyPublicKey; +/// A Bitcoin Schnorr X-only public key used for BIP340 signatures. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct XOnlyPublicKey(secp256k1::XOnlyPublicKey); + +impl XOnlyPublicKey { + /// Constructs a new x-only public key from the provided generic Secp256k1 x-only public key. + pub fn new(key: impl Into) -> XOnlyPublicKey { + XOnlyPublicKey(key.into()) + } + + /// Creates an x-only public key from a keypair. + /// + /// Returns the x-only public key and the parity of the full public key. + #[inline] + pub fn from_keypair(keypair: &Keypair) -> (XOnlyPublicKey, Parity) { + let (xonly, parity) = secp256k1::XOnlyPublicKey::from_keypair(keypair); + (XOnlyPublicKey::new(xonly), parity) + } + + /// Creates an x-only public key from a 32-byte x-coordinate. + /// + /// Returns an error if the provided bytes don't represent a valid secp256k1 point x-coordinate. + #[inline] + pub fn from_byte_array( + data: &[u8; constants::SCHNORR_PUBLIC_KEY_SIZE], + ) -> Result { + secp256k1::XOnlyPublicKey::from_byte_array(data) + .map(XOnlyPublicKey::new) + .map_err(|_| ParseXOnlyPublicKeyError::InvalidXCoordinate) + } + + /// Serializes the x-only public key as a byte-encoded x coordinate value (32 bytes). + #[inline] + pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] { self.0.serialize() } + + /// Converts this x-only public key to a full public key given the parity. + #[inline] + pub fn public_key(&self, parity: Parity) -> PublicKey { self.0.public_key(parity).into() } + + /// Verifies that a tweak produced by [`XOnlyPublicKey::add_tweak`] was computed correctly. + /// + /// Should be called on the original untweaked key. Takes the tweaked key and output parity from + /// [`XOnlyPublicKey::add_tweak`] as input. + #[inline] + pub fn tweak_add_check( + &self, + secp: &Secp256k1, + tweaked_key: &Self, + tweaked_parity: Parity, + tweak: secp256k1::Scalar, + ) -> bool { + self.0.tweak_add_check(secp, &tweaked_key.0, tweaked_parity, tweak) + } + + /// Tweaks an [`XOnlyPublicKey`] by adding the generator multiplied with the given tweak to it. + /// + /// # Returns + /// + /// The newly tweaked key plus an opaque type representing the parity of the tweaked key, this + /// should be provided to `tweak_add_check` which can be used to verify a tweak more efficiently + /// than regenerating it and checking equality. + /// + /// # Errors + /// + /// If the resulting key would be invalid. + #[inline] + pub fn add_tweak( + &self, + secp: &Secp256k1, + tweak: &secp256k1::Scalar, + ) -> Result<(XOnlyPublicKey, Parity), TweakXOnlyPublicKeyError> { + match self.0.add_tweak(secp, tweak) { + Ok((xonly, parity)) => Ok((XOnlyPublicKey(xonly), parity)), + Err(secp256k1::Error::InvalidTweak) => Err(TweakXOnlyPublicKeyError::BadTweak), + Err(secp256k1::Error::InvalidParityValue(_)) => + Err(TweakXOnlyPublicKeyError::ParityError), + Err(_) => Err(TweakXOnlyPublicKeyError::ResultKeyInvalid), + } + } +} + +impl FromStr for XOnlyPublicKey { + type Err = ParseXOnlyPublicKeyError; + fn from_str(s: &str) -> Result { + secp256k1::XOnlyPublicKey::from_str(s) + .map(XOnlyPublicKey::from) + .map_err(|_| ParseXOnlyPublicKeyError::InvalidXCoordinate) + } +} + +impl From for XOnlyPublicKey { + fn from(pk: secp256k1::XOnlyPublicKey) -> XOnlyPublicKey { XOnlyPublicKey::new(pk) } +} + +impl From for XOnlyPublicKey { + 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. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PublicKey { @@ -222,7 +331,7 @@ impl From for PublicKey { } impl From for XOnlyPublicKey { - fn from(pk: PublicKey) -> XOnlyPublicKey { pk.inner.into() } + fn from(pk: PublicKey) -> XOnlyPublicKey { XOnlyPublicKey::new(pk.inner) } } /// An opaque return type for PublicKey::to_sort_key. @@ -874,7 +983,7 @@ impl TweakedPublicKey { #[inline] pub fn from_keypair(keypair: TweakedKeypair) -> Self { let (xonly, _parity) = keypair.0.x_only_public_key(); - TweakedPublicKey(xonly) + TweakedPublicKey(xonly.into()) } /// Constructs a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider @@ -933,7 +1042,7 @@ impl TweakedKeypair { #[inline] pub fn public_parts(&self) -> (TweakedPublicKey, Parity) { let (xonly, parity) = self.0.x_only_public_key(); - (TweakedPublicKey(xonly), parity) + (TweakedPublicKey(xonly.into()), parity) } } @@ -1265,7 +1374,7 @@ mod serialized_x_only { impl SerializedXOnlyPublicKey { /// Returns `XOnlyPublicKey` if the bytes are valid. - pub fn to_validated(self) -> Result { + pub fn to_validated(self) -> Result { XOnlyPublicKey::from_byte_array(self.as_byte_array()) } } @@ -1284,6 +1393,48 @@ impl fmt::Debug for SerializedXOnlyPublicKey { } } +/// Error that can occur when parsing an [`XOnlyPublicKey`] from bytes. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ParseXOnlyPublicKeyError { + /// The provided bytes do not represent a valid secp256k1 point x-coordinate. + InvalidXCoordinate, +} + +impl fmt::Display for ParseXOnlyPublicKeyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::InvalidXCoordinate => write!(f, "Invalid X coordinate for secp256k1 point"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseXOnlyPublicKeyError {} + +/// Error that can occur when tweaking an [`XOnlyPublicKey`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TweakXOnlyPublicKeyError { + /// The tweak value was invalid. + BadTweak, + /// The resulting public key would be invalid. + ResultKeyInvalid, + /// Invalid parity value encountered during the operation. + ParityError, +} + +impl fmt::Display for TweakXOnlyPublicKeyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::BadTweak => write!(f, "Invalid tweak value"), + Self::ResultKeyInvalid => write!(f, "Resulting public key would be invalid"), + Self::ParityError => write!(f, "Invalid parity value encountered"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for TweakXOnlyPublicKeyError {} + #[cfg(test)] mod tests { use super::*; diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index e2ea1a0cd..a8709ac2b 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -1878,9 +1878,10 @@ mod tests { }) } - use secp256k1::{SecretKey, XOnlyPublicKey}; + use secp256k1::SecretKey; use crate::consensus::serde as con_serde; + use crate::crypto::key::XOnlyPublicKey; use crate::taproot::{TapNodeHash, TapTweakHash}; #[derive(serde::Deserialize)] diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs index 8f1f27537..d33be651b 100644 --- a/bitcoin/src/psbt/map/input.rs +++ b/bitcoin/src/psbt/map/input.rs @@ -4,10 +4,9 @@ use core::fmt; use core::str::FromStr; use hashes::{hash160, ripemd160, sha256, sha256d}; -use secp256k1::XOnlyPublicKey; use crate::bip32::KeySource; -use crate::crypto::key::PublicKey; +use crate::crypto::key::{PublicKey, XOnlyPublicKey}; use crate::crypto::{ecdsa, taproot}; use crate::prelude::{btree_map, BTreeMap, Borrow, Box, ToOwned, Vec}; use crate::psbt::map::Map; diff --git a/bitcoin/src/psbt/map/output.rs b/bitcoin/src/psbt/map/output.rs index 4829e39f5..22e28abc6 100644 --- a/bitcoin/src/psbt/map/output.rs +++ b/bitcoin/src/psbt/map/output.rs @@ -1,8 +1,7 @@ // SPDX-License-Identifier: CC0-1.0 -use secp256k1::XOnlyPublicKey; - use crate::bip32::KeySource; +use crate::crypto::key::XOnlyPublicKey; use crate::prelude::{btree_map, BTreeMap, Vec}; use crate::psbt::map::Map; use crate::psbt::{raw, Error}; diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index b9d6a9369..1766574dd 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -850,14 +850,14 @@ impl GetKey for $map { match key_request { KeyRequest::Pubkey(pk) => Ok(self.get(&pk).cloned()), KeyRequest::XOnlyPubkey(xonly) => { - let pubkey_even = PublicKey::new(xonly.public_key(secp256k1::Parity::Even)); + let pubkey_even = xonly.public_key(secp256k1::Parity::Even); let key = self.get(&pubkey_even).cloned(); if key.is_some() { return Ok(key); } - let pubkey_odd = PublicKey::new(xonly.public_key(secp256k1::Parity::Odd)); + let pubkey_odd = xonly.public_key(secp256k1::Parity::Odd); if let Some(priv_key) = self.get(&pubkey_odd).copied() { let negated_priv_key = priv_key.negate(); return Ok(Some(negated_priv_key)); @@ -2267,7 +2267,7 @@ mod tests { pubkey_map.insert(pk, priv_key); - let req_result = pubkey_map.get_key(&KeyRequest::XOnlyPubkey(xonly), &secp).unwrap(); + let req_result = pubkey_map.get_key(&KeyRequest::XOnlyPubkey(xonly.into()), &secp).unwrap(); let retrieved_key = req_result.unwrap(); diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index bc582a147..8f6193fd2 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -9,12 +9,11 @@ use hashes::{hash160, ripemd160, sha256, sha256d}; use internals::compact_size; #[allow(unused)] // MSRV polyfill use internals::slice::SliceExt; -use secp256k1::XOnlyPublicKey; use super::map::{Input, Map, Output, PsbtSighashType}; use crate::bip32::{ChildNumber, Fingerprint, KeySource}; 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::io::Write; use crate::prelude::{DisplayHex, String, Vec}; diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs index 2a8c59c22..0e9764f6b 100644 --- a/bitcoin/src/taproot/mod.rs +++ b/bitcoin/src/taproot/mod.rs @@ -25,6 +25,7 @@ use crate::consensus::Encodable; use crate::crypto::key::{ SerializedXOnlyPublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey, }; +use crate::key::ParseXOnlyPublicKeyError; use crate::prelude::{BTreeMap, BTreeSet, BinaryHeap, Vec}; use crate::{Script, ScriptBuf}; @@ -96,10 +97,11 @@ impl From for TapNodeHash { impl TapTweakHash { /// 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. - pub fn from_key_and_tweak( - internal_key: UntweakedPublicKey, + pub fn from_key_and_tweak>( + internal_key: K, merkle_root: Option, ) -> TapTweakHash { + let internal_key = internal_key.into(); let mut eng = sha256t::Hash::::engine(); // always hash the key eng.input(&internal_key.serialize()); @@ -247,14 +249,15 @@ impl TaprootSpendInfo { /// weights of satisfaction for that script. /// /// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation. - pub fn with_huffman_tree( + pub fn with_huffman_tree( secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, script_weights: I, ) -> Result where I: IntoIterator, C: secp256k1::Verification, + K: Into, { let builder = TaprootBuilder::with_huffman_tree(script_weights)?; Ok(builder.finalize(secp, internal_key).expect("Huffman tree is always complete")) @@ -271,11 +274,12 @@ impl TaprootSpendInfo { /// /// 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. - pub fn new_key_spend( + pub fn new_key_spend>( secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, merkle_root: Option, ) -> Self { + let internal_key = internal_key.into(); let (output_key, parity) = internal_key.tap_tweak(secp, merkle_root); Self { internal_key, @@ -311,9 +315,9 @@ impl TaprootSpendInfo { /// /// This is useful when you want to manually build a Taproot tree without using /// [`TaprootBuilder`]. - pub fn from_node_info( + pub fn from_node_info>( secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, node: NodeInfo, ) -> TaprootSpendInfo { // Create as if it is a key spend path with the given Merkle root @@ -582,11 +586,12 @@ impl TaprootBuilder { /// /// Returns the unmodified builder as Err if the builder is not finalizable. /// See also [`TaprootBuilder::is_finalizable`] - pub fn finalize( + pub fn finalize>( mut self, secp: &Secp256k1, - internal_key: UntweakedPublicKey, + internal_key: K, ) -> Result { + let internal_key = internal_key.into(); match self.branch.len() { 0 => Ok(TaprootSpendInfo::new_key_spend(secp, internal_key, None)), 1 => @@ -1523,7 +1528,7 @@ pub enum TaprootError { /// Invalid control block size. InvalidControlBlockSize(InvalidControlBlockSizeError), /// Invalid Taproot internal key. - InvalidInternalKey(secp256k1::Error), + InvalidInternalKey(ParseXOnlyPublicKeyError), /// Invalid control block hex InvalidControlBlockHex(HexToBytesError), } diff --git a/bitcoin/tests/psbt-sign-taproot.rs b/bitcoin/tests/psbt-sign-taproot.rs index 78f3a77b1..e692cb1b5 100644 --- a/bitcoin/tests/psbt-sign-taproot.rs +++ b/bitcoin/tests/psbt-sign-taproot.rs @@ -11,9 +11,9 @@ use bitcoin::taproot::{LeafVersion, TaprootBuilder, TaprootSpendInfo}; use bitcoin::transaction::Version; use bitcoin::{ absolute, script, Address, Network, OutPoint, PrivateKey, Psbt, ScriptBuf, Sequence, - Transaction, TxIn, TxOut, Witness, + Transaction, TxIn, TxOut, Witness, XOnlyPublicKey, }; -use secp256k1::{Keypair, Secp256k1, Signing, XOnlyPublicKey}; +use secp256k1::{Keypair, Secp256k1, Signing}; use units::Amount; #[test] @@ -146,7 +146,7 @@ fn psbt_sign_taproot() { sig, psbt_script_path_spend.inputs[0] .tap_script_sigs - .get(&(x_only_pubkey, script2.clone().tapscript_leaf_hash())) + .get(&(x_only_pubkey.into(), script2.clone().tapscript_leaf_hash())) .unwrap() .signature .to_string() @@ -176,13 +176,14 @@ fn create_basic_single_sig_script(secp: &Secp256k1, sk: &str) -> .into_script() } -fn create_taproot_tree( +fn create_taproot_tree>( secp: &Secp256k1, script1: ScriptBuf, script2: ScriptBuf, script3: ScriptBuf, - internal_key: XOnlyPublicKey, + internal_key: K, ) -> TaprootSpendInfo { + let internal_key = internal_key.into(); let builder = TaprootBuilder::new(); let builder = builder.add_leaf(2, script1).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 } -fn create_psbt_for_taproot_script_path_spend( +fn create_psbt_for_taproot_script_path_spend>( from_address: Address, to_address: Address, tree: TaprootSpendInfo, - x_only_pubkey_of_signing_key: XOnlyPublicKey, + x_only_pubkey_of_signing_key: K, signing_key_path: &str, use_script: ScriptBuf, ) -> Psbt { + let x_only_pubkey_of_signing_key = x_only_pubkey_of_signing_key.into(); let utxo_value = 6280; let send_value = 6000; let mfp = "73c5da0a";