Wrap secp256k1::XOnlyPublicKey to improve error handling
This commit creates a wrapper type for XOnlyPublicKey instead of directly re-exporting it from the secp256k1 library.
This commit is contained in:
parent
f9bc0f517d
commit
2a518d62e6
|
@ -26,7 +26,7 @@ fn main() {
|
|||
|
||||
// Get an unspent output that is locked to the key above that we control.
|
||||
// In a real application these would come from the chain.
|
||||
let (dummy_out_point, dummy_utxo) = dummy_unspent_transaction_output(&secp, internal_key);
|
||||
let (dummy_out_point, dummy_utxo) = dummy_unspent_transaction_output(&secp, internal_key.into());
|
||||
|
||||
// Get an address to send to.
|
||||
let address = receivers_address();
|
||||
|
@ -45,7 +45,7 @@ fn main() {
|
|||
// The change output is locked to a key controlled by us.
|
||||
let change = TxOut {
|
||||
value: CHANGE_AMOUNT,
|
||||
script_pubkey: ScriptBuf::new_p2tr(&secp, internal_key, None), // Change comes back to us.
|
||||
script_pubkey: ScriptBuf::new_p2tr(&secp, internal_key.into(), None), // Change comes back to us.
|
||||
};
|
||||
|
||||
// The transaction we want to sign and broadcast.
|
||||
|
|
|
@ -151,12 +151,12 @@ fn main() {
|
|||
// Get the Tap Key Origins
|
||||
// Map of tap root X-only keys to origin info and leaf hashes contained in it.
|
||||
let origin_input_1 = get_tap_key_origin(
|
||||
pk_input_1,
|
||||
pk_input_1.into(),
|
||||
MASTER_FINGERPRINT.parse::<Fingerprint>().unwrap(),
|
||||
"m/86'/0'/0'/0/0".parse::<DerivationPath>().unwrap(),
|
||||
);
|
||||
let origin_input_2 = get_tap_key_origin(
|
||||
pk_input_2,
|
||||
pk_input_2.into(),
|
||||
MASTER_FINGERPRINT.parse::<Fingerprint>().unwrap(),
|
||||
"m/86'/0'/0'/1/0".parse::<DerivationPath>().unwrap(),
|
||||
);
|
||||
|
@ -187,7 +187,7 @@ fn main() {
|
|||
// The change output is locked to a key controlled by us.
|
||||
let change = TxOut {
|
||||
value: CHANGE_AMOUNT,
|
||||
script_pubkey: ScriptBuf::new_p2tr(&secp, pk_change, None), // Change comes back to us.
|
||||
script_pubkey: ScriptBuf::new_p2tr(&secp, pk_change.into(), None), // Change comes back to us.
|
||||
};
|
||||
|
||||
// The transaction we want to sign and broadcast.
|
||||
|
@ -210,14 +210,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()
|
||||
},
|
||||
|
|
|
@ -404,7 +404,7 @@ impl BenefactorWallet {
|
|||
|
||||
let taproot_spend_info = TaprootBuilder::new()
|
||||
.add_leaf(0, script.clone())?
|
||||
.finalize(&self.secp, internal_keypair.x_only_public_key().0)
|
||||
.finalize(&self.secp, internal_keypair.x_only_public_key().0.into())
|
||||
.expect("should be finalizable");
|
||||
self.current_spend_info = Some(taproot_spend_info.clone());
|
||||
let script_pubkey = ScriptBuf::new_p2tr(
|
||||
|
@ -442,7 +442,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::<PsbtSighashType>()?;
|
||||
|
@ -457,7 +457,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()
|
||||
};
|
||||
|
@ -502,7 +502,7 @@ impl BenefactorWallet {
|
|||
|
||||
let taproot_spend_info = TaprootBuilder::new()
|
||||
.add_leaf(0, script.clone())?
|
||||
.finalize(&self.secp, new_internal_keypair.x_only_public_key().0)
|
||||
.finalize(&self.secp, new_internal_keypair.x_only_public_key().0.into())
|
||||
.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();
|
||||
|
@ -608,7 +608,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()
|
||||
};
|
||||
|
|
|
@ -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::{
|
||||
|
@ -69,6 +69,7 @@ use crate::script::{
|
|||
WitnessScriptSizeError,
|
||||
};
|
||||
use crate::taproot::TapNodeHash;
|
||||
use crate::XOnlyPublicKey;
|
||||
|
||||
#[rustfmt::skip] // Keep public re-exports separate.
|
||||
#[doc(inline)]
|
||||
|
|
|
@ -13,12 +13,13 @@ 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::internal_macros::{impl_array_newtype, impl_array_newtype_stringify};
|
||||
use crate::network::NetworkKind;
|
||||
use crate::prelude::{String, Vec};
|
||||
use crate::XOnlyPublicKey;
|
||||
|
||||
/// Version bytes for extended public keys on the Bitcoin network.
|
||||
const VERSION_BYTES_MAINNET_PUBLIC: [u8; 4] = [0x04, 0x88, 0xB2, 0x1E];
|
||||
|
|
|
@ -25,11 +25,110 @@ 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<secp256k1::XOnlyPublicKey>) -> 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<XOnlyPublicKey, ParseXOnlyPublicKeyError> {
|
||||
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<V: Verification>(
|
||||
&self,
|
||||
secp: &Secp256k1<V>,
|
||||
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<V: Verification>(
|
||||
&self,
|
||||
secp: &Secp256k1<V>,
|
||||
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<XOnlyPublicKey, ParseXOnlyPublicKeyError> {
|
||||
secp256k1::XOnlyPublicKey::from_str(s)
|
||||
.map(XOnlyPublicKey::from)
|
||||
.map_err(|_| ParseXOnlyPublicKeyError::InvalidXCoordinate)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<secp256k1::XOnlyPublicKey> for XOnlyPublicKey {
|
||||
fn from(pk: secp256k1::XOnlyPublicKey) -> XOnlyPublicKey { XOnlyPublicKey::new(pk) }
|
||||
}
|
||||
|
||||
impl From<secp256k1::PublicKey> for XOnlyPublicKey {
|
||||
fn from(pk: secp256k1::PublicKey) -> XOnlyPublicKey { XOnlyPublicKey::new(pk) }
|
||||
}
|
||||
|
||||
/// A Bitcoin ECDSA public key.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct PublicKey {
|
||||
|
@ -222,7 +321,7 @@ impl From<secp256k1::PublicKey> for PublicKey {
|
|||
}
|
||||
|
||||
impl From<PublicKey> 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.
|
||||
|
@ -743,13 +842,13 @@ pub type UntweakedPublicKey = XOnlyPublicKey;
|
|||
pub struct TweakedPublicKey(XOnlyPublicKey);
|
||||
|
||||
impl fmt::LowerHex for TweakedPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0 .0, f) }
|
||||
}
|
||||
// Allocate for serialized size
|
||||
impl_to_hex_from_lower_hex!(TweakedPublicKey, |_| constants::SCHNORR_PUBLIC_KEY_SIZE * 2);
|
||||
|
||||
impl fmt::Display for TweakedPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0 .0, f) }
|
||||
}
|
||||
|
||||
/// Untweaked BIP-340 key pair.
|
||||
|
@ -874,7 +973,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
|
||||
|
@ -914,7 +1013,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1246,7 +1345,7 @@ mod serialized_x_only {
|
|||
|
||||
impl SerializedXOnlyPublicKey {
|
||||
/// Returns `XOnlyPublicKey` if the bytes are valid.
|
||||
pub fn to_validated(self) -> Result<XOnlyPublicKey, secp256k1::Error> {
|
||||
pub fn to_validated(self) -> Result<XOnlyPublicKey, ParseXOnlyPublicKeyError> {
|
||||
XOnlyPublicKey::from_byte_array(self.as_byte_array())
|
||||
}
|
||||
}
|
||||
|
@ -1265,6 +1364,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::*;
|
||||
|
|
|
@ -1878,10 +1878,11 @@ mod tests {
|
|||
})
|
||||
}
|
||||
|
||||
use secp256k1::{SecretKey, XOnlyPublicKey};
|
||||
use secp256k1::SecretKey;
|
||||
|
||||
use crate::consensus::serde as con_serde;
|
||||
use crate::taproot::{TapNodeHash, TapTweakHash};
|
||||
use crate::XOnlyPublicKey;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct UtxoSpent {
|
||||
|
|
|
@ -4,7 +4,6 @@ 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;
|
||||
|
@ -21,6 +20,7 @@ use crate::sighash::{
|
|||
use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash};
|
||||
use crate::transaction::{Transaction, TxOut};
|
||||
use crate::witness::Witness;
|
||||
use crate::XOnlyPublicKey;
|
||||
|
||||
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
|
||||
const PSBT_IN_NON_WITNESS_UTXO: u64 = 0x00;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
use secp256k1::XOnlyPublicKey;
|
||||
|
||||
use crate::bip32::KeySource;
|
||||
use crate::prelude::{btree_map, BTreeMap, Vec};
|
||||
use crate::psbt::map::Map;
|
||||
use crate::psbt::{raw, Error};
|
||||
use crate::script::ScriptBuf;
|
||||
use crate::taproot::{TapLeafHash, TapTree};
|
||||
use crate::XOnlyPublicKey;
|
||||
|
||||
/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
|
||||
const PSBT_OUT_REDEEM_SCRIPT: u64 = 0x00;
|
||||
|
|
|
@ -850,14 +850,14 @@ impl GetKey for $map<PublicKey, PrivateKey> {
|
|||
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));
|
||||
|
@ -2257,7 +2257,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();
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ 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};
|
||||
|
@ -25,6 +24,7 @@ use crate::taproot::{
|
|||
};
|
||||
use crate::transaction::{Transaction, TxOut};
|
||||
use crate::witness::Witness;
|
||||
use crate::XOnlyPublicKey;
|
||||
|
||||
/// A trait for serializing a value as raw data for insertion into PSBT
|
||||
/// key-value maps.
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
@ -1523,7 +1524,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),
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
@ -66,7 +66,7 @@ fn psbt_sign_taproot() {
|
|||
let internal_key = kp.x_only_public_key().0; // Ignore the parity.
|
||||
|
||||
let tree =
|
||||
create_taproot_tree(secp, script1.clone(), script2.clone(), script3.clone(), internal_key);
|
||||
create_taproot_tree(secp, script1.clone(), script2.clone(), script3.clone(), internal_key.into());
|
||||
|
||||
let address = create_p2tr_address(tree.clone());
|
||||
assert_eq!(
|
||||
|
@ -131,7 +131,7 @@ fn psbt_sign_taproot() {
|
|||
address,
|
||||
to_address,
|
||||
tree.clone(),
|
||||
x_only_pubkey,
|
||||
x_only_pubkey.into(),
|
||||
signing_key_path,
|
||||
script2.clone(),
|
||||
);
|
||||
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue