From c5fe315a93eac8194b5eddce81beccfe4e313973 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 1 Feb 2023 08:49:17 +1100 Subject: [PATCH 1/8] Move sighash to crypto module There is never any use for the `sighash` module unless one is signing, which requires the `crypto` module. The `sighash` module should therefore live in the `crypto` module. This is not an API breaking change because we reexport it at the crate root. --- bitcoin/src/crypto/mod.rs | 1 + bitcoin/src/{ => crypto}/sighash.rs | 4 ++-- bitcoin/src/lib.rs | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) rename bitcoin/src/{ => crypto}/sighash.rs (99%) diff --git a/bitcoin/src/crypto/mod.rs b/bitcoin/src/crypto/mod.rs index b36b0134..c04531bf 100644 --- a/bitcoin/src/crypto/mod.rs +++ b/bitcoin/src/crypto/mod.rs @@ -9,3 +9,4 @@ pub mod ecdsa; pub mod key; pub mod schnorr; +pub mod sighash; diff --git a/bitcoin/src/sighash.rs b/bitcoin/src/crypto/sighash.rs similarity index 99% rename from bitcoin/src/sighash.rs rename to bitcoin/src/crypto/sighash.rs index bc9dae04..6a2b1664 100644 --- a/bitcoin/src/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -1126,7 +1126,7 @@ mod tests { // These test vectors were stolen from libbtc, which is Copyright 2014 Jonas Schnelli MIT // They were transformed by replacing {...} with run_test_sighash(...), then the ones containing // OP_CODESEPARATOR in their pubkeys were removed - let data = include_str!("../tests/data/legacy_sighash.json"); + let data = include_str!("../../tests/data/legacy_sighash.json"); let testdata = serde_json::from_str::(data).unwrap().as_array().unwrap().clone(); for t in testdata.iter().skip(1) { @@ -1494,7 +1494,7 @@ mod tests { //script_pubkey: Vec, // unused } - let json_str = include_str!("../tests/data/bip341_tests.json"); + let json_str = include_str!("../../tests/data/bip341_tests.json"); let mut data = serde_json::from_str::(json_str).expect("JSON was not well-formatted"); diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index f94c0f15..dc74ca52 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -99,7 +99,6 @@ pub mod merkle_tree; pub mod policy; pub mod pow; pub mod psbt; -pub mod sighash; pub mod sign_message; pub mod string; pub mod taproot; @@ -128,7 +127,7 @@ pub use crate::blockdata::witness::{self, Witness}; pub use crate::blockdata::{constants, opcodes}; pub use crate::consensus::encode::VarInt; pub use crate::crypto::key::{self, PrivateKey, PublicKey}; -pub use crate::crypto::{ecdsa, schnorr}; +pub use crate::crypto::{ecdsa, schnorr, sighash}; pub use crate::error::Error; pub use crate::hash_types::{Txid, Wtxid, BlockHash, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; pub use crate::merkle_tree::MerkleBlock; From 7e4da3c0ab2d872b2a5057609f3bab8e527e8bab Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 1 Feb 2023 09:32:04 +1100 Subject: [PATCH 2/8] Move taproot keys to the keys module We have a keys module, taproot keys should live in there. --- bitcoin/examples/taproot-psbt.rs | 5 +- bitcoin/src/address.rs | 3 +- bitcoin/src/blockdata/script/borrowed.rs | 3 +- bitcoin/src/blockdata/script/owned.rs | 3 +- bitcoin/src/crypto/key.rs | 213 ++++++++++++++++++++++- bitcoin/src/crypto/schnorr.rs | 210 ---------------------- bitcoin/src/taproot.rs | 3 +- bitcoin/tests/serde.rs | 4 +- 8 files changed, 220 insertions(+), 224 deletions(-) diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index d68bd90d..9e943255 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -82,17 +82,16 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKe use bitcoin::consensus::encode; use bitcoin::constants::COIN_VALUE; use bitcoin::hashes::Hash; -use bitcoin::key::XOnlyPublicKey; +use bitcoin::key::{TapTweak, XOnlyPublicKey}; use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP}; use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType}; -use bitcoin::schnorr::{self, TapTweak}; use bitcoin::secp256k1::{Message, Secp256k1}; use bitcoin::sighash::{self, SchnorrSighashType, SighashCache}; use bitcoin::taproot::{ LeafVersion, TapLeafHash, TapSighashHash, TaprootBuilder, TaprootSpendInfo, }; use bitcoin::{ - absolute, script, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness, + absolute, script, schnorr, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness, }; fn main() -> Result<(), Box> { diff --git a/bitcoin/src/address.rs b/bitcoin/src/address.rs index e1cdc0ea..e83eb8bd 100644 --- a/bitcoin/src/address.rs +++ b/bitcoin/src/address.rs @@ -44,8 +44,7 @@ use crate::blockdata::constants::{ use crate::blockdata::opcodes; use crate::blockdata::opcodes::all::*; use crate::blockdata::script::{self, Instruction, Script, ScriptBuf, PushBytes, PushBytesBuf, PushBytesErrorReport}; -use crate::crypto::key::PublicKey; -use crate::crypto::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey}; +use crate::crypto::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey}; use crate::error::ParseIntError; use crate::hash_types::{PubkeyHash, ScriptHash}; use crate::hashes::{sha256, Hash, HashEngine}; diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index 94e0d1e2..676e4eb2 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -17,10 +17,9 @@ use crate::blockdata::script::Error; use crate::consensus::Encodable; use crate::hash_types::{ScriptHash, WScriptHash}; use crate::hashes::Hash; -use crate::key::PublicKey; +use crate::key::{PublicKey, UntweakedPublicKey}; use crate::policy::DUST_RELAY_TX_FEE; use crate::prelude::*; -use crate::schnorr::UntweakedPublicKey; use crate::taproot::{LeafVersion, TapNodeHash, TapLeafHash}; /// Bitcoin script slice. diff --git a/bitcoin/src/blockdata/script/owned.rs b/bitcoin/src/blockdata/script/owned.rs index 89157634..d545a827 100644 --- a/bitcoin/src/blockdata/script/owned.rs +++ b/bitcoin/src/blockdata/script/owned.rs @@ -11,9 +11,8 @@ use crate::blockdata::opcodes::{self, all::*}; use crate::blockdata::script::{opcode_to_verify, Builder, Instruction, Script, PushBytes}; use crate::hashes::hex; use crate::hash_types::{PubkeyHash, WPubkeyHash, ScriptHash, WScriptHash}; -use crate::key::PublicKey; +use crate::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey}; use crate::prelude::*; -use crate::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey}; use crate::taproot::TapNodeHash; /// An owned, growable script. diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index acad5fa1..83af9989 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -12,12 +12,14 @@ use core::{ops, str::FromStr}; use core::fmt::{self, Write}; use bitcoin_internals::write_err; -pub use secp256k1::{self, Secp256k1, XOnlyPublicKey, KeyPair}; + +pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verification, Parity}; use crate::{base58, io}; use crate::network::constants::Network; use crate::hashes::{Hash, hash160, hex, hex::FromHex}; use crate::hash_types::{PubkeyHash, WPubkeyHash}; +use crate::taproot::{TapNodeHash, TapTweakHash}; /// A key-related error. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -546,6 +548,215 @@ impl<'de> serde::Deserialize<'de> for PublicKey { } } +/// Untweaked BIP-340 X-coord-only public key +pub type UntweakedPublicKey = XOnlyPublicKey; + +/// Tweaked BIP-340 X-coord-only public key +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] +#[cfg_attr(feature = "serde", serde(transparent))] +pub struct TweakedPublicKey(XOnlyPublicKey); + +impl fmt::LowerHex for TweakedPublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} + +impl fmt::Display for TweakedPublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// Untweaked BIP-340 key pair +pub type UntweakedKeyPair = KeyPair; + +/// Tweaked BIP-340 key pair +/// +/// # Examples +/// ``` +/// # #[cfg(feature = "rand-std")] { +/// # use bitcoin::crypto::key::{KeyPair, TweakedKeyPair, TweakedPublicKey}; +/// # use bitcoin::secp256k1::{rand, Secp256k1}; +/// # let secp = Secp256k1::new(); +/// # let keypair = TweakedKeyPair::dangerous_assume_tweaked(KeyPair::new(&secp, &mut rand::thread_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); +/// let _pk = TweakedPublicKey::from(keypair); +/// # } +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] +#[cfg_attr(feature = "serde", serde(transparent))] +pub struct TweakedKeyPair(KeyPair); + +/// A trait for tweaking BIP340 key types (x-only public keys and key pairs). +pub trait TapTweak { + /// Tweaked key type with optional auxiliary information + type TweakedAux; + /// Tweaked key type + type TweakedKey; + + /// Tweaks an untweaked key with corresponding public key value and optional script tree merkle + /// root. For the [`KeyPair`] type this also tweaks the private key in the pair. + /// + /// This is done by using the equation Q = P + H(P|c)G, where + /// * Q is the tweaked public key + /// * P is the internal public key + /// * H is the hash function + /// * c is the commitment data + /// * G is the generator point + /// + /// # Returns + /// The tweaked key and its parity. + fn tap_tweak(self, secp: &Secp256k1, merkle_root: Option) -> Self::TweakedAux; + + /// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`] + /// + /// This method is dangerous and can lead to loss of funds if used incorrectly. + /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal. + fn dangerous_assume_tweaked(self) -> Self::TweakedKey; +} + +impl TapTweak for UntweakedPublicKey { + type TweakedAux = (TweakedPublicKey, Parity); + type TweakedKey = TweakedPublicKey; + + /// Tweaks an untweaked public key with corresponding public key value and optional script tree + /// merkle root. + /// + /// This is done by using the equation Q = P + H(P|c)G, where + /// * Q is the tweaked public key + /// * P is the internal public key + /// * H is the hash function + /// * c is the commitment data + /// * G is the generator point + /// + /// # Returns + /// The tweaked key and its parity. + fn tap_tweak(self, secp: &Secp256k1, merkle_root: Option) -> (TweakedPublicKey, Parity) { + let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar(); + let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed"); + + debug_assert!(self.tweak_add_check(secp, &output_key, parity, tweak)); + (TweakedPublicKey(output_key), parity) + } + + fn dangerous_assume_tweaked(self) -> TweakedPublicKey { + TweakedPublicKey(self) + } +} + +impl TapTweak for UntweakedKeyPair { + type TweakedAux = TweakedKeyPair; + type TweakedKey = TweakedKeyPair; + + /// Tweaks private and public keys within an untweaked [`KeyPair`] with corresponding public key + /// value and optional script tree merkle root. + /// + /// This is done by tweaking private key within the pair using the equation q = p + H(P|c), where + /// * q is the tweaked private key + /// * p is the internal private key + /// * H is the hash function + /// * c is the commitment data + /// The public key is generated from a private key by multiplying with generator point, Q = qG. + /// + /// # Returns + /// The tweaked key and its parity. + fn tap_tweak(self, secp: &Secp256k1, merkle_root: Option) -> TweakedKeyPair { + let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self); + let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar(); + let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed"); + TweakedKeyPair(tweaked) + } + + fn dangerous_assume_tweaked(self) -> TweakedKeyPair { + TweakedKeyPair(self) + } +} + +impl TweakedPublicKey { + /// Returns the [`TweakedPublicKey`] for `keypair`. + #[inline] + pub fn from_keypair(keypair: TweakedKeyPair) -> Self { + let (xonly, _parity) = keypair.0.x_only_public_key(); + TweakedPublicKey(xonly) + } + + /// Creates a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider + /// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor. + /// + /// This method is dangerous and can lead to loss of funds if used incorrectly. + /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal. + #[inline] + pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> TweakedPublicKey { + TweakedPublicKey(key) + } + + /// Returns the underlying public key. + pub fn to_inner(self) -> XOnlyPublicKey { + self.0 + } + + /// Serialize the key as a byte-encoded pair of values. In compressed form + /// the y-coordinate is represented by only a single bit, as x determines + /// it up to one bit. + #[inline] + pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] { + self.0.serialize() + } +} + +impl TweakedKeyPair { + /// Creates a new [`TweakedKeyPair`] from a [`KeyPair`]. No tweak is applied, consider + /// calling `tap_tweak` on an [`UntweakedKeyPair`] instead of using this constructor. + /// + /// This method is dangerous and can lead to loss of funds if used incorrectly. + /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal. + #[inline] + pub fn dangerous_assume_tweaked(pair: KeyPair) -> TweakedKeyPair { + TweakedKeyPair(pair) + } + + /// Returns the underlying key pair. + #[inline] + pub fn to_inner(self) -> KeyPair { + self.0 + } + + /// 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), parity) + } +} + +impl From for XOnlyPublicKey { + #[inline] + fn from(pair: TweakedPublicKey) -> Self { + pair.0 + } +} + +impl From for KeyPair { + #[inline] + fn from(pair: TweakedKeyPair) -> Self { + pair.0 + } +} + +impl From for TweakedPublicKey { + #[inline] + fn from(pair: TweakedKeyPair) -> Self { + TweakedPublicKey::from_keypair(pair) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/bitcoin/src/crypto/schnorr.rs b/bitcoin/src/crypto/schnorr.rs index 3f1630c6..40f2a016 100644 --- a/bitcoin/src/crypto/schnorr.rs +++ b/bitcoin/src/crypto/schnorr.rs @@ -15,218 +15,8 @@ pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verific use crate::prelude::*; -use crate::taproot::{TapNodeHash, TapTweakHash}; use crate::sighash::SchnorrSighashType; -/// Untweaked BIP-340 X-coord-only public key -pub type UntweakedPublicKey = XOnlyPublicKey; - -/// Tweaked BIP-340 X-coord-only public key -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] -#[cfg_attr(feature = "serde", serde(transparent))] -pub struct TweakedPublicKey(XOnlyPublicKey); - -impl fmt::LowerHex for TweakedPublicKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(&self.0, f) - } -} - -impl fmt::Display for TweakedPublicKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -/// Untweaked BIP-340 key pair -pub type UntweakedKeyPair = KeyPair; - -/// Tweaked BIP-340 key pair -/// -/// # Examples -/// ``` -/// # #[cfg(feature = "rand-std")] { -/// # use bitcoin::schnorr::{KeyPair, TweakedKeyPair, TweakedPublicKey}; -/// # use bitcoin::secp256k1::{rand, Secp256k1}; -/// # let secp = Secp256k1::new(); -/// # let keypair = TweakedKeyPair::dangerous_assume_tweaked(KeyPair::new(&secp, &mut rand::thread_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); -/// let _pk = TweakedPublicKey::from(keypair); -/// # } -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] -#[cfg_attr(feature = "serde", serde(transparent))] -pub struct TweakedKeyPair(KeyPair); - -/// A trait for tweaking BIP340 key types (x-only public keys and key pairs). -pub trait TapTweak { - /// Tweaked key type with optional auxiliary information - type TweakedAux; - /// Tweaked key type - type TweakedKey; - - /// Tweaks an untweaked key with corresponding public key value and optional script tree merkle - /// root. For the [`KeyPair`] type this also tweaks the private key in the pair. - /// - /// This is done by using the equation Q = P + H(P|c)G, where - /// * Q is the tweaked public key - /// * P is the internal public key - /// * H is the hash function - /// * c is the commitment data - /// * G is the generator point - /// - /// # Returns - /// The tweaked key and its parity. - fn tap_tweak(self, secp: &Secp256k1, merkle_root: Option) -> Self::TweakedAux; - - /// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`] - /// - /// This method is dangerous and can lead to loss of funds if used incorrectly. - /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal. - fn dangerous_assume_tweaked(self) -> Self::TweakedKey; -} - -impl TapTweak for UntweakedPublicKey { - type TweakedAux = (TweakedPublicKey, Parity); - type TweakedKey = TweakedPublicKey; - - /// Tweaks an untweaked public key with corresponding public key value and optional script tree - /// merkle root. - /// - /// This is done by using the equation Q = P + H(P|c)G, where - /// * Q is the tweaked public key - /// * P is the internal public key - /// * H is the hash function - /// * c is the commitment data - /// * G is the generator point - /// - /// # Returns - /// The tweaked key and its parity. - fn tap_tweak(self, secp: &Secp256k1, merkle_root: Option) -> (TweakedPublicKey, Parity) { - let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar(); - let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed"); - - debug_assert!(self.tweak_add_check(secp, &output_key, parity, tweak)); - (TweakedPublicKey(output_key), parity) - } - - fn dangerous_assume_tweaked(self) -> TweakedPublicKey { - TweakedPublicKey(self) - } -} - -impl TapTweak for UntweakedKeyPair { - type TweakedAux = TweakedKeyPair; - type TweakedKey = TweakedKeyPair; - - /// Tweaks private and public keys within an untweaked [`KeyPair`] with corresponding public key - /// value and optional script tree merkle root. - /// - /// This is done by tweaking private key within the pair using the equation q = p + H(P|c), where - /// * q is the tweaked private key - /// * p is the internal private key - /// * H is the hash function - /// * c is the commitment data - /// The public key is generated from a private key by multiplying with generator point, Q = qG. - /// - /// # Returns - /// The tweaked key and its parity. - fn tap_tweak(self, secp: &Secp256k1, merkle_root: Option) -> TweakedKeyPair { - let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self); - let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar(); - let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed"); - TweakedKeyPair(tweaked) - } - - fn dangerous_assume_tweaked(self) -> TweakedKeyPair { - TweakedKeyPair(self) - } -} - -impl TweakedPublicKey { - /// Returns the [`TweakedPublicKey`] for `keypair`. - #[inline] - pub fn from_keypair(keypair: TweakedKeyPair) -> Self { - let (xonly, _parity) = keypair.0.x_only_public_key(); - TweakedPublicKey(xonly) - } - - /// Creates a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider - /// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor. - /// - /// This method is dangerous and can lead to loss of funds if used incorrectly. - /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal. - #[inline] - pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> TweakedPublicKey { - TweakedPublicKey(key) - } - - /// Returns the underlying public key. - pub fn to_inner(self) -> XOnlyPublicKey { - self.0 - } - - /// Serialize the key as a byte-encoded pair of values. In compressed form - /// the y-coordinate is represented by only a single bit, as x determines - /// it up to one bit. - #[inline] - pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] { - self.0.serialize() - } -} - -impl TweakedKeyPair { - /// Creates a new [`TweakedKeyPair`] from a [`KeyPair`]. No tweak is applied, consider - /// calling `tap_tweak` on an [`UntweakedKeyPair`] instead of using this constructor. - /// - /// This method is dangerous and can lead to loss of funds if used incorrectly. - /// Specifically, in multi-party protocols a peer can provide a value that allows them to steal. - #[inline] - pub fn dangerous_assume_tweaked(pair: KeyPair) -> TweakedKeyPair { - TweakedKeyPair(pair) - } - - /// Returns the underlying key pair. - #[inline] - pub fn to_inner(self) -> KeyPair { - self.0 - } - - /// 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), parity) - } -} - -impl From for XOnlyPublicKey { - #[inline] - fn from(pair: TweakedPublicKey) -> Self { - pair.0 - } -} - -impl From for KeyPair { - #[inline] - fn from(pair: TweakedKeyPair) -> Self { - pair.0 - } -} - -impl From for TweakedPublicKey { - #[inline] - fn from(pair: TweakedKeyPair) -> Self { - TweakedPublicKey::from_keypair(pair) - } -} - /// A BIP340-341 serialized schnorr signature with the corresponding hash type. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/bitcoin/src/taproot.rs b/bitcoin/src/taproot.rs index 825b4708..5c71bb83 100644 --- a/bitcoin/src/taproot.rs +++ b/bitcoin/src/taproot.rs @@ -13,7 +13,7 @@ use bitcoin_internals::write_err; use secp256k1::{self, Scalar, Secp256k1}; use crate::consensus::Encodable; -use crate::crypto::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey}; +use crate::crypto::key::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey}; use crate::hashes::{sha256t_hash_newtype, Hash, HashEngine}; use crate::prelude::*; use crate::{io, Script, ScriptBuf}; @@ -1145,7 +1145,6 @@ mod test { use secp256k1::{VerifyOnly, XOnlyPublicKey}; use super::*; - use crate::crypto::schnorr::TapTweak; use crate::hashes::hex::FromHex; use crate::hashes::sha256t::Tag; use crate::hashes::{sha256, Hash, HashEngine}; diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index 79088793..08e47063 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -30,15 +30,15 @@ use bitcoin::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource}; use bitcoin::blockdata::locktime::{absolute, relative}; use bitcoin::blockdata::witness::Witness; use bitcoin::consensus::encode::deserialize; +use bitcoin::crypto::key::UntweakedPublicKey; use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey}; use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; -use bitcoin::schnorr::{self, UntweakedPublicKey}; use bitcoin::sighash::{EcdsaSighashType, SchnorrSighashType}; use bitcoin::taproot::{ControlBlock, LeafVersion, TaprootBuilder, TaprootSpendInfo}; use bitcoin::{ - ecdsa, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target, + ecdsa, schnorr, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target, Transaction, TxIn, TxOut, Txid, Work, }; use secp256k1::Secp256k1; From 98130f49f1a4fab8fdeec10b9f70c82736ca8afe Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 7 Feb 2023 13:14:44 +1100 Subject: [PATCH 3/8] Rename TapSighashHash to TapSighash The TapSighash is the taproot sighash, no need to append `Hash` to the identifier. --- bitcoin/examples/taproot-psbt.rs | 4 ++-- bitcoin/src/crypto/sighash.rs | 28 ++++++++++++++-------------- bitcoin/src/taproot.rs | 12 ++++++------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index 9e943255..bea60d1b 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -88,7 +88,7 @@ use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType}; use bitcoin::secp256k1::{Message, Secp256k1}; use bitcoin::sighash::{self, SchnorrSighashType, SighashCache}; use bitcoin::taproot::{ - LeafVersion, TapLeafHash, TapSighashHash, TaprootBuilder, TaprootSpendInfo, + LeafVersion, TapLeafHash, TapSighash, TaprootBuilder, TaprootSpendInfo, }; use bitcoin::{ absolute, script, schnorr, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness, @@ -734,7 +734,7 @@ fn sign_psbt_schnorr( pubkey: XOnlyPublicKey, leaf_hash: Option, psbt_input: &mut psbt::Input, - hash: TapSighashHash, + hash: TapSighash, hash_ty: SchnorrSighashType, secp: &Secp256k1, ) { diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 6a2b1664..1db59f3b 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -22,7 +22,7 @@ use crate::error::impl_std_error; use crate::hashes::{sha256, sha256d, Hash}; use crate::hash_types::Sighash; use crate::prelude::*; -use crate::taproot::{LeafVersion, TapLeafHash, TapSighashHash, TAPROOT_ANNEX_PREFIX}; +use crate::taproot::{LeafVersion, TapLeafHash, TapSighash, TAPROOT_ANNEX_PREFIX}; /// Used for signature hash for invalid use of SIGHASH_SINGLE. #[rustfmt::skip] @@ -640,8 +640,8 @@ impl> SighashCache { annex: Option, leaf_hash_code_separator: Option<(TapLeafHash, u32)>, sighash_type: SchnorrSighashType, - ) -> Result { - let mut enc = TapSighashHash::engine(); + ) -> Result { + let mut enc = TapSighash::engine(); self.taproot_encode_signing_data_to( &mut enc, input_index, @@ -650,7 +650,7 @@ impl> SighashCache { leaf_hash_code_separator, sighash_type, )?; - Ok(TapSighashHash::from_engine(enc)) + Ok(TapSighash::from_engine(enc)) } /// Computes the BIP341 sighash for a key spend. @@ -659,8 +659,8 @@ impl> SighashCache { input_index: usize, prevouts: &Prevouts, sighash_type: SchnorrSighashType, - ) -> Result { - let mut enc = TapSighashHash::engine(); + ) -> Result { + let mut enc = TapSighash::engine(); self.taproot_encode_signing_data_to( &mut enc, input_index, @@ -669,7 +669,7 @@ impl> SighashCache { None, sighash_type, )?; - Ok(TapSighashHash::from_engine(enc)) + Ok(TapSighash::from_engine(enc)) } /// Computes the BIP341 sighash for a script spend. @@ -682,8 +682,8 @@ impl> SighashCache { prevouts: &Prevouts, leaf_hash: S, sighash_type: SchnorrSighashType, - ) -> Result { - let mut enc = TapSighashHash::engine(); + ) -> Result { + let mut enc = TapSighash::engine(); self.taproot_encode_signing_data_to( &mut enc, input_index, @@ -692,7 +692,7 @@ impl> SighashCache { Some((leaf_hash.into(), 0xFFFFFFFF)), sighash_type, )?; - Ok(TapSighashHash::from_engine(enc)) + Ok(TapSighash::from_engine(enc)) } /// Encodes the BIP143 signing data for any flag type into a given object implementing a @@ -1073,7 +1073,7 @@ mod tests { use crate::hashes::{Hash, HashEngine}; use crate::internal_macros::hex; use crate::network::constants::Network; - use crate::taproot::{TapLeafHash, TapSighashHash}; + use crate::taproot::{TapLeafHash, TapSighash}; extern crate serde_json; @@ -1144,9 +1144,9 @@ mod tests { let bytes = hex!("00011b96877db45ffa23b307e9f0ac87b80ef9a80b4c5f0db3fbe734422453e83cc5576f3d542c5d4898fb2b696c15d43332534a7c1d1255fda38993545882df92c3e353ff6d36fbfadc4d168452afd8467f02fe53d71714fcea5dfe2ea759bd00185c4cb02bc76d42620393ca358a1a713f4997f9fc222911890afb3fe56c6a19b202df7bffdcfad08003821294279043746631b00e2dc5e52a111e213bbfe6ef09a19428d418dab0d50000000000"); let expected = hex!("04e808aad07a40b3767a1442fead79af6ef7e7c9316d82dec409bb31e77699b0"); - let mut enc = TapSighashHash::engine(); + let mut enc = TapSighash::engine(); enc.input(&bytes); - let hash = TapSighashHash::from_engine(enc); + let hash = TapSighash::from_engine(enc); assert_eq!(expected, hash.into_inner()); } @@ -1456,7 +1456,7 @@ mod tests { tweaked_privkey: SecretKey, sig_msg: String, //precomputed_used: Vec, // unused - sig_hash: TapSighashHash, + sig_hash: TapSighash, } #[derive(serde::Deserialize)] diff --git a/bitcoin/src/taproot.rs b/bitcoin/src/taproot.rs index 5c71bb83..34ff3af8 100644 --- a/bitcoin/src/taproot.rs +++ b/bitcoin/src/taproot.rs @@ -39,7 +39,7 @@ const MIDSTATE_TAPTWEAK: [u8; 32] = [ ]; // d129a2f3701c655d6583b6c3b941972795f4e23294fd54f4a2ae8d8547ca590b -/// The SHA-256 midstate value for the [`TapSighashHash`]. +/// The SHA-256 midstate value for the [`TapSighash`]. const MIDSTATE_TAPSIGHASH: [u8; 32] = [ 245, 4, 164, 37, 215, 248, 120, 59, 19, 99, 134, 138, 227, 229, 86, 88, 110, 238, 148, 93, 188, 120, 136, 221, 2, 166, 226, 195, 24, 115, 254, 159, @@ -63,13 +63,13 @@ sha256t_hash_newtype!(TapTweakHash, TapTweakTag, MIDSTATE_TAPTWEAK, 64, This hash type is used while computing the tweaked public key", false ); #[rustfmt::skip] -sha256t_hash_newtype!(TapSighashHash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64, +sha256t_hash_newtype!(TapSighash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64, doc="Taproot-tagged hash with tag \"TapSighash\". This hash type is used for computing taproot signature hash.", false ); -impl secp256k1::ThirtyTwoByteHash for TapSighashHash { +impl secp256k1::ThirtyTwoByteHash for TapSighash { fn into_32(self) -> [u8; 32] { self.into_inner() } } @@ -1185,7 +1185,7 @@ mod test { assert_eq!(empty_hash("TapLeaf"), TapLeafHash::hash(&[]).into_inner()); assert_eq!(empty_hash("TapBranch"), TapNodeHash::hash(&[]).into_inner()); assert_eq!(empty_hash("TapTweak"), TapTweakHash::hash(&[]).into_inner()); - assert_eq!(empty_hash("TapSighash"), TapSighashHash::hash(&[]).into_inner()); + assert_eq!(empty_hash("TapSighash"), TapSighash::hash(&[]).into_inner()); } #[test] @@ -1208,7 +1208,7 @@ mod test { "8aa4229474ab0100b2d6f0687f031d1fc9d8eef92a042ad97d279bff456b15e4" ); assert_eq!( - TapSighashHash::from_engine(TapSighashTag::engine()).to_string(), + TapSighash::from_engine(TapSighashTag::engine()).to_string(), "dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803" ); @@ -1230,7 +1230,7 @@ mod test { "cd8737b5e6047fc3f16f03e8b9959e3440e1bdf6dd02f7bb899c352ad490ea1e" ); assert_eq!( - TapSighashHash::hash(&[0]).to_string(), + TapSighash::hash(&[0]).to_string(), "c2fd0de003889a09c4afcf676656a0d8a1fb706313ff7d509afb00c323c010cd" ); } From e38d843536e7beea7ae22109c4d9b75867f4b6ec Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 7 Feb 2023 14:17:03 +1100 Subject: [PATCH 4/8] Do not use deprecated function in rustdoc example Currently we are use the deprecated signing method on `Transaction`, we should use the new method on the sighash cache. --- bitcoin/src/blockdata/transaction.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 10bb53ef..3d8308d9 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -589,8 +589,9 @@ impl EncodeSigningDataResult { /// ```rust /// # use bitcoin::consensus::deserialize; /// # use bitcoin::Transaction; - /// # use bitcoin::hash_types::Sighash; + /// # use bitcoin::crypto::sighash::SighashCache; /// # use bitcoin_hashes::{Hash, hex::FromHex}; + /// # use bitcoin::hash_types::Sighash; /// # let mut writer = Sighash::engine(); /// # let input_index = 0; /// # let script_pubkey = bitcoin::ScriptBuf::new(); @@ -598,7 +599,8 @@ impl EncodeSigningDataResult { /// # const SOME_TX: &'static str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; /// # let raw_tx = Vec::from_hex(SOME_TX).unwrap(); /// # let tx: Transaction = deserialize(&raw_tx).unwrap(); - /// if tx.encode_signing_data_to(&mut writer, input_index, &script_pubkey, sighash_u32) + /// # let cache = SighashCache::new(&tx); + /// if cache.legacy_encode_signing_data_to(&mut writer, input_index, &script_pubkey, sighash_u32) /// .is_sighash_single_bug() /// .expect("writer can't fail") { /// // use a hash value of "1", instead of computing the actual hash due to SIGHASH_SINGLE bug From 40c246743bab8a91be903ea6d48aa309953c21e8 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 7 Feb 2023 13:47:08 +1100 Subject: [PATCH 5/8] Split Sighash into LegacySighash and SegwitV0Sighash Currently we have `TapSighash` that is used for taproot sighashes but for non-taproot sighashes we use `hash_types::Sighash`. We can improve the API by creating a `LegacySighash`, and `SegwitV0Sighash`. Copy the original `Sighash` macro calls to create the two new types in the `sighash` module. While we are at it, put the `TapSighash` and `TapSighashTag` into the `sighash` module also. --- bitcoin/src/blockdata/transaction.rs | 10 ++-- bitcoin/src/crypto/sighash.rs | 72 ++++++++++++++++++++-------- bitcoin/src/hash_types.rs | 7 --- bitcoin/src/psbt/mod.rs | 25 +++++----- bitcoin/src/taproot.rs | 21 ++------ 5 files changed, 75 insertions(+), 60 deletions(-) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 3d8308d9..104ef4c7 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -30,7 +30,8 @@ use crate::blockdata::witness::Witness; use crate::blockdata::locktime::absolute::{self, Height, Time}; use crate::blockdata::locktime::relative; use crate::consensus::{encode, Decodable, Encodable}; -use crate::hash_types::{Sighash, Txid, Wtxid}; +use crate::crypto::sighash::LegacySighash; +use crate::hash_types::{Txid, Wtxid}; use crate::VarInt; use crate::internal_macros::impl_consensus_encoding; use crate::parse::impl_parse_str_through_int; @@ -589,10 +590,9 @@ impl EncodeSigningDataResult { /// ```rust /// # use bitcoin::consensus::deserialize; /// # use bitcoin::Transaction; - /// # use bitcoin::crypto::sighash::SighashCache; + /// # use bitcoin::crypto::sighash::{LegacySighash, SighashCache}; /// # use bitcoin_hashes::{Hash, hex::FromHex}; - /// # use bitcoin::hash_types::Sighash; - /// # let mut writer = Sighash::engine(); + /// # let mut writer = LegacySighash::engine(); /// # let input_index = 0; /// # let script_pubkey = bitcoin::ScriptBuf::new(); /// # let sighash_u32 = 0u32; @@ -837,7 +837,7 @@ impl Transaction { input_index: usize, script_pubkey: &Script, sighash_u32: u32 - ) -> Sighash { + ) -> LegacySighash { assert!(input_index < self.input.len()); // Panic on OOB, enables expect below. let cache = crate::sighash::SighashCache::new(self); diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 1db59f3b..11c70b23 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -19,10 +19,9 @@ use crate::blockdata::transaction::EncodeSigningDataResult; use crate::blockdata::witness::Witness; use crate::consensus::{encode, Encodable}; use crate::error::impl_std_error; -use crate::hashes::{sha256, sha256d, Hash}; -use crate::hash_types::Sighash; +use crate::hashes::{hash_newtype, sha256, sha256t_hash_newtype, sha256d, Hash}; use crate::prelude::*; -use crate::taproot::{LeafVersion, TapLeafHash, TapSighash, TAPROOT_ANNEX_PREFIX}; +use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX}; /// Used for signature hash for invalid use of SIGHASH_SINGLE. #[rustfmt::skip] @@ -33,6 +32,39 @@ pub(crate) const UINT256_ONE: [u8; 32] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]; +/// The SHA-256 midstate value for the [`TapSighash`]. +pub(crate) const MIDSTATE_TAPSIGHASH: [u8; 32] = [ + 245, 4, 164, 37, 215, 248, 120, 59, 19, 99, 134, 138, 227, 229, 86, 88, 110, 238, 148, 93, 188, + 120, 136, 221, 2, 166, 226, 195, 24, 115, 254, 159, +]; +// f504a425d7f8783b1363868ae3e556586eee945dbc7888dd02a6e2c31873fe9f + +macro_rules! impl_thirty_two_byte_hash { + ($ty:ident) => { + impl secp256k1::ThirtyTwoByteHash for $ty { + fn into_32(self) -> [u8; 32] { self.into_inner() } + } + } +} + +#[rustfmt::skip] +hash_newtype!(LegacySighash, sha256d::Hash, 32, + doc="Hash of a transaction according to the legacy signature algorithm", false); +impl_thirty_two_byte_hash!(LegacySighash); + +#[rustfmt::skip] +hash_newtype!(SegwitV0Sighash, sha256d::Hash, 32, + doc="Hash of a transaction according to the segwit version 0 signature algorithm", false); +impl_thirty_two_byte_hash!(SegwitV0Sighash); + +#[rustfmt::skip] +sha256t_hash_newtype!(TapSighash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64, + doc="Taproot-tagged hash with tag \"TapSighash\". + +This hash type is used for computing taproot signature hash.", false +); +impl_thirty_two_byte_hash!(TapSighash); + /// Efficiently calculates signature hash message for legacy, segwit and taproot inputs. #[derive(Debug)] pub struct SighashCache> { @@ -741,9 +773,9 @@ impl> SighashCache { if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None { self.segwit_cache().outputs.consensus_encode(&mut writer)?; } else if sighash == EcdsaSighashType::Single && input_index < self.tx.borrow().output.len() { - let mut single_enc = Sighash::engine(); + let mut single_enc = LegacySighash::engine(); self.tx.borrow().output[input_index].consensus_encode(&mut single_enc)?; - let hash = Sighash::from_engine(single_enc); + let hash = LegacySighash::from_engine(single_enc); writer.write_all(&hash[..])?; } else { writer.write_all(&zero_hash[..])?; @@ -761,8 +793,8 @@ impl> SighashCache { script_code: &Script, value: u64, sighash_type: EcdsaSighashType, - ) -> Result { - let mut enc = Sighash::engine(); + ) -> Result { + let mut enc = SegwitV0Sighash::engine(); self.segwit_encode_signing_data_to( &mut enc, input_index, @@ -770,7 +802,7 @@ impl> SighashCache { value, sighash_type, )?; - Ok(Sighash::from_engine(enc)) + Ok(SegwitV0Sighash::from_engine(enc)) } /// Encodes the legacy signing data from which a signature hash for a given input index with a @@ -930,15 +962,15 @@ impl> SighashCache { input_index: usize, script_pubkey: &Script, sighash_type: u32, - ) -> Result { - let mut enc = Sighash::engine(); + ) -> Result { + let mut enc = LegacySighash::engine(); if self .legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type) .is_sighash_single_bug()? { - Ok(Sighash::from_inner(UINT256_ONE)) + Ok(LegacySighash::from_inner(UINT256_ONE)) } else { - Ok(Sighash::from_engine(enc)) + Ok(LegacySighash::from_engine(enc)) } } @@ -1068,12 +1100,12 @@ mod tests { use crate::blockdata::locktime::absolute; use crate::consensus::deserialize; use crate::crypto::key::PublicKey; - use crate::hash_types::Sighash; + use crate::crypto::sighash::{LegacySighash, TapSighash}; use crate::hashes::hex::FromHex; - use crate::hashes::{Hash, HashEngine}; + use crate::hashes::HashEngine; use crate::internal_macros::hex; use crate::network::constants::Network; - use crate::taproot::{TapLeafHash, TapSighash}; + use crate::taproot::TapLeafHash; extern crate serde_json; @@ -1092,7 +1124,7 @@ mod tests { let cache = SighashCache::new(&tx); let got = cache.legacy_signature_hash(1, &script, SIGHASH_SINGLE).expect("sighash"); - let want = Sighash::from_slice(&UINT256_ONE).unwrap(); + let want = LegacySighash::from_slice(&UINT256_ONE).unwrap(); assert_eq!(got, want) } @@ -1115,7 +1147,7 @@ mod tests { let script = ScriptBuf::from(Vec::from_hex(script).unwrap()); let mut raw_expected = Vec::from_hex(expected_result).unwrap(); raw_expected.reverse(); - let want = Sighash::from_slice(&raw_expected[..]).unwrap(); + let want = LegacySighash::from_slice(&raw_expected[..]).unwrap(); let cache = SighashCache::new(&tx); let got = cache.legacy_signature_hash(input_index, &script, hash_type as u32).unwrap(); @@ -1635,7 +1667,7 @@ mod tests { let mut cache = SighashCache::new(&tx); assert_eq!( cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(), - "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670".parse::().unwrap(), + "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670".parse::().unwrap(), ); let cache = cache.segwit_cache(); @@ -1671,7 +1703,7 @@ mod tests { let mut cache = SighashCache::new(&tx); assert_eq!( cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(), - "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6".parse::().unwrap(), + "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6".parse::().unwrap(), ); let cache = cache.segwit_cache(); @@ -1712,7 +1744,7 @@ mod tests { let mut cache = SighashCache::new(&tx); assert_eq!( cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(), - "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c".parse::().unwrap(), + "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c".parse::().unwrap(), ); let cache = cache.segwit_cache(); diff --git a/bitcoin/src/hash_types.rs b/bitcoin/src/hash_types.rs index 78c0342d..31b7cb84 100644 --- a/bitcoin/src/hash_types.rs +++ b/bitcoin/src/hash_types.rs @@ -66,13 +66,6 @@ See [`hashes::Hash::DISPLAY_BACKWARD`] for more details. "); hash_newtype!(Wtxid, sha256d::Hash, 32, doc="A bitcoin witness transaction ID."); hash_newtype!(BlockHash, sha256d::Hash, 32, doc="A bitcoin block hash."); - hash_newtype!(Sighash, sha256d::Hash, 32, doc="Hash of the transaction according to the signature algorithm", false); - impl secp256k1::ThirtyTwoByteHash for Sighash { - fn into_32(self) -> [u8; 32] { - use hashes::Hash; - *self.as_inner() - } - } hash_newtype!(PubkeyHash, hash160::Hash, 20, doc="A hash of a public key."); hash_newtype!(ScriptHash, hash160::Hash, 20, doc="A hash of Bitcoin Script bytecode."); diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 73b6c541..62d756e9 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -326,34 +326,37 @@ impl PartiallySignedTransaction { let hash_ty = input.ecdsa_hash_ty() .map_err(|_| SignError::InvalidSighashType)?; // Only support standard sighash types. - let sighash = match self.output_type(input_index)? { + match self.output_type(input_index)? { Bare => { - cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())? + let sighash = cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())?; + Ok((Message::from(sighash), hash_ty)) }, Sh => { let script_code = input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?; - cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())? + let sighash = cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?; + Ok((Message::from(sighash), hash_ty)) }, Wpkh => { let script_code = ScriptBuf::p2wpkh_script_code(spk).ok_or(SignError::NotWpkh)?; - cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)? - } + let sighash = cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?; + Ok((Message::from(sighash), hash_ty)) + }, ShWpkh => { let script_code = ScriptBuf::p2wpkh_script_code(input.redeem_script.as_ref().expect("checked above")) .ok_or(SignError::NotWpkh)?; - cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)? + let sighash = cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?; + Ok((Message::from(sighash), hash_ty)) }, Wsh | ShWsh => { let script_code = input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?; - cache.segwit_signature_hash(input_index, script_code, utxo.value, hash_ty)? + let sighash = cache.segwit_signature_hash(input_index, script_code, utxo.value, hash_ty)?; + Ok((Message::from(sighash), hash_ty)) }, Tr => { // This PSBT signing API is WIP, taproot to come shortly. - return Err(SignError::Unsupported); + Err(SignError::Unsupported) } - }; - - Ok((Message::from(sighash), hash_ty)) + } } /// Returns the spending utxo for this PSBT's input at `input_index`. diff --git a/bitcoin/src/taproot.rs b/bitcoin/src/taproot.rs index 34ff3af8..06bfe9e0 100644 --- a/bitcoin/src/taproot.rs +++ b/bitcoin/src/taproot.rs @@ -18,6 +18,8 @@ use crate::hashes::{sha256t_hash_newtype, Hash, HashEngine}; use crate::prelude::*; use crate::{io, Script, ScriptBuf}; +pub use crate::crypto::sighash::{TapSighash, TapSighashTag}; + /// The SHA-256 midstate value for the TapLeaf hash. const MIDSTATE_TAPLEAF: [u8; 32] = [ 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, 108, @@ -39,13 +41,6 @@ const MIDSTATE_TAPTWEAK: [u8; 32] = [ ]; // d129a2f3701c655d6583b6c3b941972795f4e23294fd54f4a2ae8d8547ca590b -/// The SHA-256 midstate value for the [`TapSighash`]. -const MIDSTATE_TAPSIGHASH: [u8; 32] = [ - 245, 4, 164, 37, 215, 248, 120, 59, 19, 99, 134, 138, 227, 229, 86, 88, 110, 238, 148, 93, 188, - 120, 136, 221, 2, 166, 226, 195, 24, 115, 254, 159, -]; -// f504a425d7f8783b1363868ae3e556586eee945dbc7888dd02a6e2c31873fe9f - // Taproot test vectors from BIP-341 state the hashes without any reversing #[rustfmt::skip] sha256t_hash_newtype!(TapLeafHash, TapLeafTag, MIDSTATE_TAPLEAF, 64, @@ -62,16 +57,6 @@ sha256t_hash_newtype!(TapTweakHash, TapTweakTag, MIDSTATE_TAPTWEAK, 64, doc="Taproot-tagged hash with tag \"TapTweak\". This hash type is used while computing the tweaked public key", false ); -#[rustfmt::skip] -sha256t_hash_newtype!(TapSighash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64, - doc="Taproot-tagged hash with tag \"TapSighash\". - -This hash type is used for computing taproot signature hash.", false -); - -impl secp256k1::ThirtyTwoByteHash for TapSighash { - fn into_32(self) -> [u8; 32] { self.into_inner() } -} impl TapTweakHash { /// Creates a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where @@ -1164,6 +1149,8 @@ mod test { #[test] fn test_midstates() { + use crate::crypto::sighash::MIDSTATE_TAPSIGHASH; + // check midstate against hard-coded values assert_eq!(MIDSTATE_TAPLEAF, tag_engine("TapLeaf").midstate().into_inner()); assert_eq!(MIDSTATE_TAPBRANCH, tag_engine("TapBranch").midstate().into_inner()); From f5c26693c5ef44631d1f318ed4c31459eb400fab Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 7 Feb 2023 13:58:56 +1100 Subject: [PATCH 6/8] Make match arms more terse Add function local import statements so we can make the match arms more terse. Refactor only, no logic changes. --- bitcoin/src/crypto/sighash.rs | 156 +++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 68 deletions(-) diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 11c70b23..d7e3b811 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -163,14 +163,16 @@ crate::serde_utils::serde_string_impl!(SchnorrSighashType, "a SchnorrSighashType impl fmt::Display for SchnorrSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use SchnorrSighashType::*; + let s = match self { - SchnorrSighashType::Default => "SIGHASH_DEFAULT", - SchnorrSighashType::All => "SIGHASH_ALL", - SchnorrSighashType::None => "SIGHASH_NONE", - SchnorrSighashType::Single => "SIGHASH_SINGLE", - SchnorrSighashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", - SchnorrSighashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", - SchnorrSighashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", + Default => "SIGHASH_DEFAULT", + All => "SIGHASH_ALL", + None => "SIGHASH_NONE", + Single => "SIGHASH_SINGLE", + AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", + NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", + SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", }; f.write_str(s) } @@ -180,14 +182,16 @@ impl str::FromStr for SchnorrSighashType { type Err = SighashTypeParseError; fn from_str(s: &str) -> Result { + use SchnorrSighashType::*; + match s { - "SIGHASH_DEFAULT" => Ok(SchnorrSighashType::Default), - "SIGHASH_ALL" => Ok(SchnorrSighashType::All), - "SIGHASH_NONE" => Ok(SchnorrSighashType::None), - "SIGHASH_SINGLE" => Ok(SchnorrSighashType::Single), - "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::AllPlusAnyoneCanPay), - "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::NonePlusAnyoneCanPay), - "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::SinglePlusAnyoneCanPay), + "SIGHASH_DEFAULT" => Ok(Default), + "SIGHASH_ALL" => Ok(All), + "SIGHASH_NONE" => Ok(None), + "SIGHASH_SINGLE" => Ok(Single), + "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(AllPlusAnyoneCanPay), + "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(NonePlusAnyoneCanPay), + "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SinglePlusAnyoneCanPay), _ => Err(SighashTypeParseError { unrecognized: s.to_owned() }), } } @@ -239,15 +243,17 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use Error::*; + match self { - Error::Io(error_kind) => write!(f, "writer errored: {:?}", error_kind), - Error::IndexOutOfInputsBounds { index, inputs_size } => write!(f, "Requested index ({}) is greater or equal than the number of transaction inputs ({})", index, inputs_size), - Error::SingleWithoutCorrespondingOutput { index, outputs_size } => write!(f, "SIGHASH_SINGLE for input ({}) haven't a corresponding output (#outputs:{})", index, outputs_size), - Error::PrevoutsSize => write!(f, "Number of supplied prevouts differs from the number of inputs in transaction"), - Error::PrevoutIndex => write!(f, "The index requested is greater than available prevouts or different from the provided [Provided::Anyone] index"), - Error::PrevoutKind => write!(f, "A single prevout has been provided but all prevouts are needed without `ANYONECANPAY`"), - Error::WrongAnnex => write!(f, "Annex must be at least one byte long and the first bytes must be `0x50`"), - Error::InvalidSighashType(hash_ty) => write!(f, "Invalid schnorr Signature hash type : {} ", hash_ty), + Io(error_kind) => write!(f, "writer errored: {:?}", error_kind), + IndexOutOfInputsBounds { index, inputs_size } => write!(f, "Requested index ({}) is greater or equal than the number of transaction inputs ({})", index, inputs_size), + SingleWithoutCorrespondingOutput { index, outputs_size } => write!(f, "SIGHASH_SINGLE for input ({}) haven't a corresponding output (#outputs:{})", index, outputs_size), + PrevoutsSize => write!(f, "Number of supplied prevouts differs from the number of inputs in transaction"), + PrevoutIndex => write!(f, "The index requested is greater than available prevouts or different from the provided [Provided::Anyone] index"), + PrevoutKind => write!(f, "A single prevout has been provided but all prevouts are needed without `ANYONECANPAY`"), + WrongAnnex => write!(f, "Annex must be at least one byte long and the first bytes must be `0x50`"), + InvalidSighashType(hash_ty) => write!(f, "Invalid schnorr Signature hash type : {} ", hash_ty), } } } @@ -256,7 +262,7 @@ impl fmt::Display for Error { #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - use self::Error::*; + use Error::*; match self { Io(_) @@ -357,13 +363,15 @@ crate::serde_utils::serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType dat impl fmt::Display for EcdsaSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use EcdsaSighashType::*; + let s = match self { - EcdsaSighashType::All => "SIGHASH_ALL", - EcdsaSighashType::None => "SIGHASH_NONE", - EcdsaSighashType::Single => "SIGHASH_SINGLE", - EcdsaSighashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", - EcdsaSighashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", - EcdsaSighashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", + All => "SIGHASH_ALL", + None => "SIGHASH_NONE", + Single => "SIGHASH_SINGLE", + AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", + NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", + SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", }; f.write_str(s) } @@ -373,13 +381,15 @@ impl str::FromStr for EcdsaSighashType { type Err = SighashTypeParseError; fn from_str(s: &str) -> Result { + use EcdsaSighashType::*; + match s { - "SIGHASH_ALL" => Ok(EcdsaSighashType::All), - "SIGHASH_NONE" => Ok(EcdsaSighashType::None), - "SIGHASH_SINGLE" => Ok(EcdsaSighashType::Single), - "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), - "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), - "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), + "SIGHASH_ALL" => Ok(All), + "SIGHASH_NONE" => Ok(None), + "SIGHASH_SINGLE" => Ok(Single), + "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(AllPlusAnyoneCanPay), + "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(NonePlusAnyoneCanPay), + "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SinglePlusAnyoneCanPay), _ => Err(SighashTypeParseError { unrecognized: s.to_owned() }), } } @@ -388,13 +398,15 @@ impl str::FromStr for EcdsaSighashType { impl EcdsaSighashType { /// Splits the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean. pub(crate) fn split_anyonecanpay_flag(self) -> (EcdsaSighashType, bool) { + use EcdsaSighashType::*; + match self { - EcdsaSighashType::All => (EcdsaSighashType::All, false), - EcdsaSighashType::None => (EcdsaSighashType::None, false), - EcdsaSighashType::Single => (EcdsaSighashType::Single, false), - EcdsaSighashType::AllPlusAnyoneCanPay => (EcdsaSighashType::All, true), - EcdsaSighashType::NonePlusAnyoneCanPay => (EcdsaSighashType::None, true), - EcdsaSighashType::SinglePlusAnyoneCanPay => (EcdsaSighashType::Single, true), + All => (All, false), + None => (None, false), + Single => (Single, false), + AllPlusAnyoneCanPay => (All, true), + NonePlusAnyoneCanPay => (None, true), + SinglePlusAnyoneCanPay => (Single, true), } } @@ -408,6 +420,8 @@ impl EcdsaSighashType { /// verifying signatures, the user should retain the `n` and use it compute the signature hash /// message. pub fn from_consensus(n: u32) -> EcdsaSighashType { + use EcdsaSighashType::*; + // In Bitcoin Core, the SignatureHash function will mask the (int32) value with // 0x1f to (apparently) deactivate ACP when checking for SINGLE and NONE bits. // We however want to be matching also against on ACP-masked ALL, SINGLE, and NONE. @@ -415,15 +429,15 @@ impl EcdsaSighashType { let mask = 0x1f | 0x80; match n & mask { // "real" sighashes - 0x01 => EcdsaSighashType::All, - 0x02 => EcdsaSighashType::None, - 0x03 => EcdsaSighashType::Single, - 0x81 => EcdsaSighashType::AllPlusAnyoneCanPay, - 0x82 => EcdsaSighashType::NonePlusAnyoneCanPay, - 0x83 => EcdsaSighashType::SinglePlusAnyoneCanPay, + 0x01 => All, + 0x02 => None, + 0x03 => Single, + 0x81 => AllPlusAnyoneCanPay, + 0x82 => NonePlusAnyoneCanPay, + 0x83 => SinglePlusAnyoneCanPay, // catchalls - x if x & 0x80 == 0x80 => EcdsaSighashType::AllPlusAnyoneCanPay, - _ => EcdsaSighashType::All, + x if x & 0x80 == 0x80 => AllPlusAnyoneCanPay, + _ => All, } } @@ -433,14 +447,16 @@ impl EcdsaSighashType { /// /// If `n` is a non-standard sighash value. pub fn from_standard(n: u32) -> Result { + use EcdsaSighashType::*; + match n { // Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198 - 0x01 => Ok(EcdsaSighashType::All), - 0x02 => Ok(EcdsaSighashType::None), - 0x03 => Ok(EcdsaSighashType::Single), - 0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), - 0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), - 0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), + 0x01 => Ok(All), + 0x02 => Ok(None), + 0x03 => Ok(Single), + 0x81 => Ok(AllPlusAnyoneCanPay), + 0x82 => Ok(NonePlusAnyoneCanPay), + 0x83 => Ok(SinglePlusAnyoneCanPay), non_standard => Err(NonStandardSighashType(non_standard)), } } @@ -453,13 +469,15 @@ impl EcdsaSighashType { impl From for SchnorrSighashType { fn from(s: EcdsaSighashType) -> Self { + use SchnorrSighashType::*; + match s { - EcdsaSighashType::All => SchnorrSighashType::All, - EcdsaSighashType::None => SchnorrSighashType::None, - EcdsaSighashType::Single => SchnorrSighashType::Single, - EcdsaSighashType::AllPlusAnyoneCanPay => SchnorrSighashType::AllPlusAnyoneCanPay, - EcdsaSighashType::NonePlusAnyoneCanPay => SchnorrSighashType::NonePlusAnyoneCanPay, - EcdsaSighashType::SinglePlusAnyoneCanPay => SchnorrSighashType::SinglePlusAnyoneCanPay, + EcdsaSighashType::All => All, + EcdsaSighashType::None => None, + EcdsaSighashType::Single => Single, + EcdsaSighashType::AllPlusAnyoneCanPay => AllPlusAnyoneCanPay, + EcdsaSighashType::NonePlusAnyoneCanPay => NonePlusAnyoneCanPay, + EcdsaSighashType::SinglePlusAnyoneCanPay => SinglePlusAnyoneCanPay, } } } @@ -467,14 +485,16 @@ impl From for SchnorrSighashType { impl SchnorrSighashType { /// Breaks the sighash flag into the "real" sighash flag and the `SIGHASH_ANYONECANPAY` boolean. pub(crate) fn split_anyonecanpay_flag(self) -> (SchnorrSighashType, bool) { + use SchnorrSighashType::*; + match self { - SchnorrSighashType::Default => (SchnorrSighashType::Default, false), - SchnorrSighashType::All => (SchnorrSighashType::All, false), - SchnorrSighashType::None => (SchnorrSighashType::None, false), - SchnorrSighashType::Single => (SchnorrSighashType::Single, false), - SchnorrSighashType::AllPlusAnyoneCanPay => (SchnorrSighashType::All, true), - SchnorrSighashType::NonePlusAnyoneCanPay => (SchnorrSighashType::None, true), - SchnorrSighashType::SinglePlusAnyoneCanPay => (SchnorrSighashType::Single, true), + Default => (Default, false), + All => (All, false), + None => (None, false), + Single => (Single, false), + AllPlusAnyoneCanPay => (All, true), + NonePlusAnyoneCanPay => (None, true), + SinglePlusAnyoneCanPay => (Single, true), } } From 9f39e872bca277ef86e7001fb15956a1e056b71b Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 7 Feb 2023 14:01:51 +1100 Subject: [PATCH 7/8] Rename SchnorrSighashType to TapSighashType As we did for `SchnorrSighash`, rename the `SchnorrSighashType` to `TapSighashType`. --- bitcoin/examples/taproot-psbt.rs | 10 +-- bitcoin/src/blockdata/transaction.rs | 2 +- bitcoin/src/crypto/schnorr.rs | 10 +-- bitcoin/src/crypto/sighash.rs | 108 +++++++++++++-------------- bitcoin/src/psbt/map/input.rs | 40 +++++----- bitcoin/tests/serde.rs | 4 +- 6 files changed, 87 insertions(+), 87 deletions(-) diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index bea60d1b..c668a3b9 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -86,7 +86,7 @@ use bitcoin::key::{TapTweak, XOnlyPublicKey}; use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP}; use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType}; use bitcoin::secp256k1::{Message, Secp256k1}; -use bitcoin::sighash::{self, SchnorrSighashType, SighashCache}; +use bitcoin::sighash::{self, TapSighashType, SighashCache}; use bitcoin::taproot::{ LeafVersion, TapLeafHash, TapSighash, TaprootBuilder, TaprootSpendInfo, }; @@ -283,7 +283,7 @@ fn generate_bip86_key_spend_tx( let hash_ty = input .sighash_type .and_then(|psbt_sighash_type| psbt_sighash_type.schnorr_hash_ty().ok()) - .unwrap_or(SchnorrSighashType::All); + .unwrap_or(TapSighashType::All); let hash = SighashCache::new(&unsigned_tx).taproot_key_spend_signature_hash( vout, &sighash::Prevouts::All(&[TxOut { @@ -518,7 +518,7 @@ impl BenefactorWallet { let hash_ty = input .sighash_type .and_then(|psbt_sighash_type| psbt_sighash_type.schnorr_hash_ty().ok()) - .unwrap_or(SchnorrSighashType::All); + .unwrap_or(TapSighashType::All); let hash = SighashCache::new(&psbt.unsigned_tx).taproot_key_spend_signature_hash( 0, &sighash::Prevouts::All(&[TxOut { @@ -659,7 +659,7 @@ impl BeneficiaryWallet { let secret_key = self.master_xpriv.derive_priv(&self.secp, &derivation_path)?.to_priv().inner; for lh in leaf_hashes { - let hash_ty = SchnorrSighashType::All; + let hash_ty = TapSighashType::All; let hash = SighashCache::new(&unsigned_tx).taproot_script_spend_signature_hash( 0, &sighash::Prevouts::All(&[TxOut { @@ -735,7 +735,7 @@ fn sign_psbt_schnorr( leaf_hash: Option, psbt_input: &mut psbt::Input, hash: TapSighash, - hash_ty: SchnorrSighashType, + hash_ty: TapSighashType, secp: &Secp256k1, ) { let keypair = secp256k1::KeyPair::from_seckey_slice(secp, secret_key.as_ref()).unwrap(); diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 104ef4c7..af8e4d48 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -38,7 +38,7 @@ use crate::parse::impl_parse_str_through_int; use super::Weight; #[cfg(doc)] -use crate::sighash::{EcdsaSighashType, SchnorrSighashType}; +use crate::sighash::{EcdsaSighashType, TapSighashType}; /// A reference to a transaction output. /// diff --git a/bitcoin/src/crypto/schnorr.rs b/bitcoin/src/crypto/schnorr.rs index 40f2a016..13de5c79 100644 --- a/bitcoin/src/crypto/schnorr.rs +++ b/bitcoin/src/crypto/schnorr.rs @@ -15,7 +15,7 @@ pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verific use crate::prelude::*; -use crate::sighash::SchnorrSighashType; +use crate::sighash::TapSighashType; /// A BIP340-341 serialized schnorr signature with the corresponding hash type. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -25,7 +25,7 @@ pub struct Signature { /// The underlying schnorr signature pub sig: secp256k1::schnorr::Signature, /// The corresponding hash type - pub hash_ty: SchnorrSighashType, + pub hash_ty: TapSighashType, } impl Signature { @@ -36,11 +36,11 @@ impl Signature { // default type let sig = secp256k1::schnorr::Signature::from_slice(sl) .map_err(Error::Secp256k1)?; - Ok(Signature { sig, hash_ty: SchnorrSighashType::Default }) + Ok(Signature { sig, hash_ty: TapSighashType::Default }) }, 65 => { let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65"); - let hash_ty = SchnorrSighashType::from_consensus_u8(*hash_ty) + let hash_ty = TapSighashType::from_consensus_u8(*hash_ty) .map_err(|_| Error::InvalidSighashType(*hash_ty))?; let sig = secp256k1::schnorr::Signature::from_slice(sig) .map_err(Error::Secp256k1)?; @@ -56,7 +56,7 @@ impl Signature { pub fn to_vec(self) -> Vec { // TODO: add support to serialize to a writer to SerializedSig let mut ser_sig = self.sig.as_ref().to_vec(); - if self.hash_ty == SchnorrSighashType::Default { + if self.hash_ty == TapSighashType::Default { // default sighash type, don't add extra sighash byte } else { ser_sig.push(self.hash_ty as u8); diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index d7e3b811..08366a53 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -109,7 +109,7 @@ struct TaprootCache { script_pubkeys: sha256::Hash, } -/// Contains outputs of previous transactions. In the case [`SchnorrSighashType`] variant is +/// Contains outputs of previous transactions. In the case [`TapSighashType`] variant is /// `SIGHASH_ANYONECANPAY`, [`Prevouts::One`] may be used. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Prevouts<'u, T> @@ -139,8 +139,8 @@ pub struct ScriptPath<'s> { /// Hashtype of an input's signature, encoded in the last byte of the signature. /// Fixed values so they can be cast as integer types for encoding. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum SchnorrSighashType { - /// 0x0: Used when not explicitly specified, defaults to [`SchnorrSighashType::All`] +pub enum TapSighashType { + /// 0x0: Used when not explicitly specified, defaults to [`TapSighashType::All`] Default = 0x00, /// 0x1: Sign all outputs. All = 0x01, @@ -159,11 +159,11 @@ pub enum SchnorrSighashType { SinglePlusAnyoneCanPay = 0x83, } #[cfg(feature = "serde")] -crate::serde_utils::serde_string_impl!(SchnorrSighashType, "a SchnorrSighashType data"); +crate::serde_utils::serde_string_impl!(TapSighashType, "a TapSighashType data"); -impl fmt::Display for SchnorrSighashType { +impl fmt::Display for TapSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use SchnorrSighashType::*; + use TapSighashType::*; let s = match self { Default => "SIGHASH_DEFAULT", @@ -178,11 +178,11 @@ impl fmt::Display for SchnorrSighashType { } } -impl str::FromStr for SchnorrSighashType { +impl str::FromStr for TapSighashType { type Err = SighashTypeParseError; fn from_str(s: &str) -> Result { - use SchnorrSighashType::*; + use TapSighashType::*; match s { "SIGHASH_DEFAULT" => Ok(Default), @@ -339,7 +339,7 @@ impl<'s> From> for TapLeafHash { /// Hashtype of an input's signature, encoded in the last byte of the signature. /// /// Fixed values so they can be cast as integer types for encoding (see also -/// [`SchnorrSighashType`]). +/// [`TapSighashType`]). #[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)] pub enum EcdsaSighashType { /// 0x1: Sign all outputs. @@ -467,9 +467,9 @@ impl EcdsaSighashType { pub fn to_u32(self) -> u32 { self as u32 } } -impl From for SchnorrSighashType { +impl From for TapSighashType { fn from(s: EcdsaSighashType) -> Self { - use SchnorrSighashType::*; + use TapSighashType::*; match s { EcdsaSighashType::All => All, @@ -482,10 +482,10 @@ impl From for SchnorrSighashType { } } -impl SchnorrSighashType { +impl TapSighashType { /// Breaks the sighash flag into the "real" sighash flag and the `SIGHASH_ANYONECANPAY` boolean. - pub(crate) fn split_anyonecanpay_flag(self) -> (SchnorrSighashType, bool) { - use SchnorrSighashType::*; + pub(crate) fn split_anyonecanpay_flag(self) -> (TapSighashType, bool) { + use TapSighashType::*; match self { Default => (Default, false), @@ -498,9 +498,9 @@ impl SchnorrSighashType { } } - /// Constructs a [`SchnorrSighashType`] from a raw `u8`. + /// Constructs a [`TapSighashType`] from a raw `u8`. pub fn from_consensus_u8(hash_ty: u8) -> Result { - use SchnorrSighashType::*; + use TapSighashType::*; Ok(match hash_ty { 0x00 => Default, @@ -574,7 +574,7 @@ impl> SighashCache { prevouts: &Prevouts, annex: Option, leaf_hash_code_separator: Option<(TapLeafHash, u32)>, - sighash_type: SchnorrSighashType, + sighash_type: TapSighashType, ) -> Result<(), Error> { prevouts.check_all(self.tx.borrow())?; @@ -608,7 +608,7 @@ impl> SighashCache { // If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE: // sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format. - if sighash != SchnorrSighashType::None && sighash != SchnorrSighashType::Single { + if sighash != TapSighashType::None && sighash != TapSighashType::Single { self.common_cache().outputs.consensus_encode(&mut writer)?; } @@ -656,7 +656,7 @@ impl> SighashCache { // * Data about this output: // If hash_type & 3 equals SIGHASH_SINGLE: // sha_single_output (32): the SHA256 of the corresponding output in CTxOut format. - if sighash == SchnorrSighashType::Single { + if sighash == TapSighashType::Single { let mut enc = sha256::Hash::engine(); self.tx .borrow() @@ -691,7 +691,7 @@ impl> SighashCache { prevouts: &Prevouts, annex: Option, leaf_hash_code_separator: Option<(TapLeafHash, u32)>, - sighash_type: SchnorrSighashType, + sighash_type: TapSighashType, ) -> Result { let mut enc = TapSighash::engine(); self.taproot_encode_signing_data_to( @@ -710,7 +710,7 @@ impl> SighashCache { &mut self, input_index: usize, prevouts: &Prevouts, - sighash_type: SchnorrSighashType, + sighash_type: TapSighashType, ) -> Result { let mut enc = TapSighash::engine(); self.taproot_encode_signing_data_to( @@ -733,7 +733,7 @@ impl> SighashCache { input_index: usize, prevouts: &Prevouts, leaf_hash: S, - sighash_type: SchnorrSighashType, + sighash_type: TapSighashType, ) -> Result { let mut enc = TapSighash::engine(); self.taproot_encode_signing_data_to( @@ -1211,7 +1211,7 @@ mod tests { "01365724000000000023542156b39dab4f8f3508e0432cfb41fab110170acaa2d4c42539cb90a4dc7c093bc500", 0, "33ca0ebfb4a945eeee9569fc0f5040221275f88690b7f8592ada88ce3bdf6703", - SchnorrSighashType::Default, None, None, None + TapSighashType::Default, None, None, None ); test_taproot_sighash( @@ -1219,7 +1219,7 @@ mod tests { "02591f220000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece48fb310000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece", 1, "626ab955d58c9a8a600a0c580549d06dc7da4e802eb2a531f62a588e430967a8", - SchnorrSighashType::All, None, None, None + TapSighashType::All, None, None, None ); test_taproot_sighash( @@ -1227,7 +1227,7 @@ mod tests { "01c4811000000000002251201bf9297d0a2968ae6693aadd0fa514717afefd218087a239afb7418e2d22e65c", 0, "dfa9437f9c9a1d1f9af271f79f2f5482f287cdb0d2e03fa92c8a9b216cc6061c", - SchnorrSighashType::AllPlusAnyoneCanPay, None, None, None + TapSighashType::AllPlusAnyoneCanPay, None, None, None ); test_taproot_sighash( @@ -1235,7 +1235,7 @@ mod tests { "0144c84d0000000000225120e3f2107989c88e67296ab2faca930efa2e3a5bd3ff0904835a11c9e807458621", 0, "3129de36a5d05fff97ffca31eb75fcccbbbc27b3147a7a36a9e4b45d8b625067", - SchnorrSighashType::None, None, None, None + TapSighashType::None, None, None, None ); test_taproot_sighash( @@ -1243,7 +1243,7 @@ mod tests { "013fed110000000000225120eb536ae8c33580290630fc495046e998086a64f8f33b93b07967d9029b265c55", 0, "2441e8b0e063a2083ee790f14f2045022f07258ddde5ee01de543c9e789d80ae", - SchnorrSighashType::NonePlusAnyoneCanPay, None, None, None + TapSighashType::NonePlusAnyoneCanPay, None, None, None ); test_taproot_sighash( @@ -1251,7 +1251,7 @@ mod tests { "01efa558000000000022512007071ea3dc7e331b0687d0193d1e6d6ed10e645ef36f10ef8831d5e522ac9e80", 0, "30239345177cadd0e3ea413d49803580abb6cb27971b481b7788a78d35117a88", - SchnorrSighashType::Single, None, None, None + TapSighashType::Single, None, None, None ); test_taproot_sighash( @@ -1259,7 +1259,7 @@ mod tests { "0107af4e00000000002251202c36d243dfc06cb56a248e62df27ecba7417307511a81ae61aa41c597a929c69", 0, "bf9c83f26c6dd16449e4921f813f551c4218e86f2ec906ca8611175b41b566df", - SchnorrSighashType::SinglePlusAnyoneCanPay, None, None, None + TapSighashType::SinglePlusAnyoneCanPay, None, None, None ); } @@ -1270,7 +1270,7 @@ mod tests { "01ea49260000000000225120ab5e9800806bf18cb246edcf5fe63441208fe955a4b5a35bbff65f5db622a010", 0, "3b003000add359a364a156e73e02846782a59d0d95ca8c4638aaad99f2ef915c", - SchnorrSighashType::SinglePlusAnyoneCanPay, + TapSighashType::SinglePlusAnyoneCanPay, Some("507b979802e62d397acb29f56743a791894b99372872fc5af06a4f6e8d242d0615cda53062bb20e6ec79756fe39183f0c128adfe85559a8fa042b042c018aa8010143799e44f0893c40e1e"), None, None, @@ -1284,7 +1284,7 @@ mod tests { "011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182", 0, "d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e", - SchnorrSighashType::All, + TapSighashType::All, None, Some("20cc4e1107aea1d170c5ff5b6817e1303010049724fb3caa7941792ea9d29b3e2bacab"), None, @@ -1298,7 +1298,7 @@ mod tests { "011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182", 0, "d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e", - SchnorrSighashType::All, + TapSighashType::All, None, None, Some("15a2530514e399f8b5cf0b3d3112cf5b289eaa3e308ba2071b58392fdc6da68a"), @@ -1312,7 +1312,7 @@ mod tests { "011458360000000000225120a7baec3fb9f84614e3899fcc010c638f80f13539344120e1f4d8b68a9a011a13", 0, "a0042aa434f9a75904b64043f2a283f8b4c143c7f4f7f49a6cbe5b9f745f4c15", - SchnorrSighashType::All, + TapSighashType::All, Some("50a6272b470e1460e3332ade7bb14b81671c564fb6245761bd5bd531394b28860e0b3808ab229fb51791fb6ae6fa82d915b2efb8f6df83ae1f5ab3db13e30928875e2a22b749d89358de481f19286cd4caa792ce27f9559082d227a731c5486882cc707f83da361c51b7aadd9a0cf68fe7480c410fa137b454482d9a1ebf0f96d760b4d61426fc109c6e8e99a508372c45caa7b000a41f8251305da3f206c1849985ba03f3d9592832b4053afbd23ab25d0465df0bc25a36c223aacf8e04ec736a418c72dc319e4da3e972e349713ca600965e7c665f2090d5a70e241ac164115a1f5639f28b1773327715ca307ace64a2de7f0e3df70a2ffee3857689f909c0dad46d8a20fa373a4cc6eed6d4c9806bf146f0d76baae1"), Some("7520ab9160dd8299dc1367659be3e8f66781fe440d52940c7f8d314a89b9f2698d406ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6eadac"), None, @@ -1334,27 +1334,27 @@ mod tests { let empty_vec = vec![]; let empty_prevouts : Prevouts = Prevouts::All(&empty_vec); assert_eq!( - c.taproot_signature_hash(0, &empty_prevouts, None, None, SchnorrSighashType::All), + c.taproot_signature_hash(0, &empty_prevouts, None, None, TapSighashType::All), Err(Error::PrevoutsSize) ); let two = vec![TxOut::default(), TxOut::default()]; let too_many_prevouts = Prevouts::All(&two); assert_eq!( - c.taproot_signature_hash(0, &too_many_prevouts, None, None, SchnorrSighashType::All), + c.taproot_signature_hash(0, &too_many_prevouts, None, None, TapSighashType::All), Err(Error::PrevoutsSize) ); let tx_out = TxOut::default(); let prevout = Prevouts::One(1, &tx_out); assert_eq!( - c.taproot_signature_hash(0, &prevout, None, None, SchnorrSighashType::All), + c.taproot_signature_hash(0, &prevout, None, None, TapSighashType::All), Err(Error::PrevoutKind) ); assert_eq!( - c.taproot_signature_hash(0, &prevout, None, None, SchnorrSighashType::AllPlusAnyoneCanPay), + c.taproot_signature_hash(0, &prevout, None, None, TapSighashType::AllPlusAnyoneCanPay), Err(Error::PrevoutIndex) ); assert_eq!( - c.taproot_signature_hash(10, &prevout, None, None, SchnorrSighashType::AllPlusAnyoneCanPay), + c.taproot_signature_hash(10, &prevout, None, None, TapSighashType::AllPlusAnyoneCanPay), Err(Error::IndexOutOfInputsBounds { index: 10, inputs_size: 1 @@ -1362,7 +1362,7 @@ mod tests { ); let prevout = Prevouts::One(0, &tx_out); assert_eq!( - c.taproot_signature_hash(0, &prevout, None, None, SchnorrSighashType::SinglePlusAnyoneCanPay), + c.taproot_signature_hash(0, &prevout, None, None, TapSighashType::SinglePlusAnyoneCanPay), Err(Error::SingleWithoutCorrespondingOutput { index: 0, outputs_size: 0 @@ -1390,7 +1390,7 @@ mod tests { prevout_hex: &str, input_index: usize, expected_hash: &str, - sighash_type: SchnorrSighashType, + sighash_type: TapSighashType, annex_hex: Option<&str>, script_hex: Option<&str>, script_leaf_hash: Option<&str>, @@ -1439,14 +1439,14 @@ mod tests { #[cfg(feature = "serde")] #[test] fn bip_341_sighash_tests() { - fn sighash_deser_numeric<'de, D>(deserializer: D) -> Result + fn sighash_deser_numeric<'de, D>(deserializer: D) -> Result where D: actual_serde::Deserializer<'de>, { use actual_serde::de::{Deserialize, Error, Unexpected}; let raw = u8::deserialize(deserializer)?; - SchnorrSighashType::from_consensus_u8(raw).map_err(|_| { + TapSighashType::from_consensus_u8(raw).map_err(|_| { D::Error::invalid_value( Unexpected::Unsigned(raw.into()), &"number in range 0-3 or 0x81-0x83", @@ -1496,7 +1496,7 @@ mod tests { internal_privkey: SecretKey, merkle_root: Option, #[serde(deserialize_with = "sighash_deser_numeric")] - hash_type: SchnorrSighashType, + hash_type: TapSighashType, } #[derive(serde::Deserialize)] @@ -1584,11 +1584,11 @@ mod tests { let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 { ( secp256k1::schnorr::Signature::from_str(&sig_str).unwrap(), - SchnorrSighashType::Default, + TapSighashType::Default, ) } else { let hash_ty = u8::from_str_radix(&sig_str[128..130], 16).unwrap(); - let hash_ty = SchnorrSighashType::from_consensus_u8(hash_ty).unwrap(); + let hash_ty = TapSighashType::from_consensus_u8(hash_ty).unwrap(); (secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty) }; @@ -1630,17 +1630,17 @@ mod tests { #[test] fn sighashtype_fromstr_display() { let sighashtypes = vec![ - ("SIGHASH_DEFAULT", SchnorrSighashType::Default), - ("SIGHASH_ALL", SchnorrSighashType::All), - ("SIGHASH_NONE", SchnorrSighashType::None), - ("SIGHASH_SINGLE", SchnorrSighashType::Single), - ("SIGHASH_ALL|SIGHASH_ANYONECANPAY", SchnorrSighashType::AllPlusAnyoneCanPay), - ("SIGHASH_NONE|SIGHASH_ANYONECANPAY", SchnorrSighashType::NonePlusAnyoneCanPay), - ("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", SchnorrSighashType::SinglePlusAnyoneCanPay), + ("SIGHASH_DEFAULT", TapSighashType::Default), + ("SIGHASH_ALL", TapSighashType::All), + ("SIGHASH_NONE", TapSighashType::None), + ("SIGHASH_SINGLE", TapSighashType::Single), + ("SIGHASH_ALL|SIGHASH_ANYONECANPAY", TapSighashType::AllPlusAnyoneCanPay), + ("SIGHASH_NONE|SIGHASH_ANYONECANPAY", TapSighashType::NonePlusAnyoneCanPay), + ("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", TapSighashType::SinglePlusAnyoneCanPay), ]; for (s, sht) in sighashtypes { assert_eq!(sht.to_string(), s); - assert_eq!(SchnorrSighashType::from_str(s).unwrap(), sht); + assert_eq!(TapSighashType::from_str(s).unwrap(), sht); } let sht_mistakes = vec![ "SIGHASH_ALL | SIGHASH_ANYONECANPAY", @@ -1658,7 +1658,7 @@ mod tests { ]; for s in sht_mistakes { assert_eq!( - SchnorrSighashType::from_str(s).unwrap_err().to_string(), + TapSighashType::from_str(s).unwrap_err().to_string(), format!("Unrecognized SIGHASH string '{}'", s) ); } diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs index 8ae6e987..83753b7b 100644 --- a/bitcoin/src/psbt/map/input.rs +++ b/bitcoin/src/psbt/map/input.rs @@ -18,7 +18,7 @@ use crate::bip32::KeySource; use crate::psbt::map::Map; use crate::psbt::serialize::Deserialize; use crate::psbt::{self, error, raw, Error}; -use crate::sighash::{self, NonStandardSighashType, SighashTypeParseError, EcdsaSighashType, SchnorrSighashType}; +use crate::sighash::{self, NonStandardSighashType, SighashTypeParseError, EcdsaSighashType, TapSighashType}; use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 @@ -134,7 +134,7 @@ pub struct Input { /// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash -/// type can be either [`EcdsaSighashType`] or [`SchnorrSighashType`] but it is not possible to know +/// type can be either [`EcdsaSighashType`] or [`TapSighashType`] but it is not possible to know /// directly which signature hash type the user is dealing with. Therefore, the user is responsible /// for converting to/from [`PsbtSighashType`] from/to the desired signature hash type they need. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -163,7 +163,7 @@ impl FromStr for PsbtSighashType { // NB: some of Schnorr sighash types are non-standard for pre-taproot // inputs. We also do not support SIGHASH_RESERVED in verbatim form // ("0xFF" string should be used instead). - if let Ok(ty) = SchnorrSighashType::from_str(s) { + if let Ok(ty) = TapSighashType::from_str(s) { return Ok(ty.into()); } @@ -181,8 +181,8 @@ impl From for PsbtSighashType { } } -impl From for PsbtSighashType { - fn from(schnorr_hash_ty: SchnorrSighashType) -> Self { +impl From for PsbtSighashType { + fn from(schnorr_hash_ty: TapSighashType) -> Self { PsbtSighashType { inner: schnorr_hash_ty as u32 } } } @@ -194,20 +194,20 @@ impl PsbtSighashType { EcdsaSighashType::from_standard(self.inner) } - /// Returns the [`SchnorrSighashType`] if the [`PsbtSighashType`] can be + /// Returns the [`TapSighashType`] if the [`PsbtSighashType`] can be /// converted to one. - pub fn schnorr_hash_ty(self) -> Result { + pub fn schnorr_hash_ty(self) -> Result { if self.inner > 0xffu32 { Err(sighash::Error::InvalidSighashType(self.inner)) } else { - SchnorrSighashType::from_consensus_u8(self.inner as u8) + TapSighashType::from_consensus_u8(self.inner as u8) } } /// Creates a [`PsbtSighashType`] from a raw `u32`. /// /// Allows construction of a non-standard or non-valid sighash flag - /// ([`EcdsaSighashType`], [`SchnorrSighashType`] respectively). + /// ([`EcdsaSighashType`], [`TapSighashType`] respectively). pub fn from_u32(n: u32) -> PsbtSighashType { PsbtSighashType { inner: n } } @@ -234,16 +234,16 @@ impl Input { .unwrap_or(Ok(EcdsaSighashType::All)) } - /// Obtains the [`SchnorrSighashType`] for this input if one is specified. If no sighash type is - /// specified, returns [`SchnorrSighashType::Default`]. + /// Obtains the [`TapSighashType`] for this input if one is specified. If no sighash type is + /// specified, returns [`TapSighashType::Default`]. /// /// # Errors /// /// If the `sighash_type` field is set to a invalid Schnorr sighash value. - pub fn schnorr_hash_ty(&self) -> Result { + pub fn schnorr_hash_ty(&self) -> Result { self.sighash_type .map(|sighash_type| sighash_type.schnorr_hash_ty()) - .unwrap_or(Ok(SchnorrSighashType::Default)) + .unwrap_or(Ok(TapSighashType::Default)) } pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> { @@ -545,13 +545,13 @@ mod test { #[test] fn psbt_sighash_type_schnorr() { for schnorr in &[ - SchnorrSighashType::Default, - SchnorrSighashType::All, - SchnorrSighashType::None, - SchnorrSighashType::Single, - SchnorrSighashType::AllPlusAnyoneCanPay, - SchnorrSighashType::NonePlusAnyoneCanPay, - SchnorrSighashType::SinglePlusAnyoneCanPay, + TapSighashType::Default, + TapSighashType::All, + TapSighashType::None, + TapSighashType::Single, + TapSighashType::AllPlusAnyoneCanPay, + TapSighashType::NonePlusAnyoneCanPay, + TapSighashType::SinglePlusAnyoneCanPay, ] { let sighash = PsbtSighashType::from(*schnorr); let s = format!("{}", sighash); diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index 08e47063..d06aafc4 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -35,7 +35,7 @@ use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey}; use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; -use bitcoin::sighash::{EcdsaSighashType, SchnorrSighashType}; +use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::taproot::{ControlBlock, LeafVersion, TaprootBuilder, TaprootSpendInfo}; use bitcoin::{ ecdsa, schnorr, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target, @@ -343,7 +343,7 @@ fn serde_regression_schnorr_sig() { let s = include_str!("data/serde/schnorr_sig_hex"); let sig = schnorr::Signature { sig: secp256k1::schnorr::Signature::from_str(s.trim()).unwrap(), - hash_ty: SchnorrSighashType::All, + hash_ty: TapSighashType::All, }; let got = serialize(&sig).unwrap(); From be7b3754a9f62070d55b65183b09c78d145009f0 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 7 Feb 2023 14:35:03 +1100 Subject: [PATCH 8/8] Rename schnorr module to taproot "schnorr" is a dirty word; the current `schnorr` module defines a `Signature` that includes a sighash type, this sighash type is a bitcoin specific construct related to taproot. Therefore the `Signature` is better named `taproot::Signature`. Note also that the usage of `schnorr` in `secp256k1` is probably justified because the `secp256::schnorr::Signature` is just doing the crypto. While we are at it, update docs and error messages to use "taproot" instead of "schnorr". Also change function names and identifiers that use "schnorr". --- bitcoin/examples/taproot-psbt.rs | 17 +++---- bitcoin/src/crypto/mod.rs | 2 +- bitcoin/src/crypto/sighash.rs | 2 +- bitcoin/src/crypto/{schnorr.rs => taproot.rs} | 17 ++++--- bitcoin/src/lib.rs | 2 +- bitcoin/src/psbt/error.rs | 10 ++-- bitcoin/src/psbt/map/input.rs | 44 +++++++++--------- bitcoin/src/psbt/mod.rs | 12 ++--- bitcoin/src/psbt/serialize.rs | 18 +++---- ...chnorr_sig_bincode => taproot_sig_bincode} | Bin .../{schnorr_sig_hex => taproot_sig_hex} | 0 bitcoin/tests/serde.rs | 11 +++-- 12 files changed, 68 insertions(+), 67 deletions(-) rename bitcoin/src/crypto/{schnorr.rs => taproot.rs} (87%) rename bitcoin/tests/data/serde/{schnorr_sig_bincode => taproot_sig_bincode} (100%) rename bitcoin/tests/data/serde/{schnorr_sig_hex => taproot_sig_hex} (100%) diff --git a/bitcoin/examples/taproot-psbt.rs b/bitcoin/examples/taproot-psbt.rs index c668a3b9..55d6dd34 100644 --- a/bitcoin/examples/taproot-psbt.rs +++ b/bitcoin/examples/taproot-psbt.rs @@ -81,6 +81,7 @@ use std::str::FromStr; use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint}; use bitcoin::consensus::encode; use bitcoin::constants::COIN_VALUE; +use bitcoin::crypto::taproot; use bitcoin::hashes::Hash; use bitcoin::key::{TapTweak, XOnlyPublicKey}; use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP}; @@ -91,7 +92,7 @@ use bitcoin::taproot::{ LeafVersion, TapLeafHash, TapSighash, TaprootBuilder, TaprootSpendInfo, }; use bitcoin::{ - absolute, script, schnorr, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness, + absolute, script, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness, }; fn main() -> Result<(), Box> { @@ -282,7 +283,7 @@ fn generate_bip86_key_spend_tx( |(vout, input)| { let hash_ty = input .sighash_type - .and_then(|psbt_sighash_type| psbt_sighash_type.schnorr_hash_ty().ok()) + .and_then(|psbt_sighash_type| psbt_sighash_type.taproot_hash_ty().ok()) .unwrap_or(TapSighashType::All); let hash = SighashCache::new(&unsigned_tx).taproot_key_spend_signature_hash( vout, @@ -299,7 +300,7 @@ fn generate_bip86_key_spend_tx( .ok_or("Missing taproot key origin")?; let secret_key = master_xpriv.derive_priv(secp, &derivation_path)?.to_priv().inner; - sign_psbt_schnorr( + sign_psbt_taproot( &secret_key, input.tap_internal_key.unwrap(), None, @@ -517,7 +518,7 @@ impl BenefactorWallet { let hash_ty = input .sighash_type - .and_then(|psbt_sighash_type| psbt_sighash_type.schnorr_hash_ty().ok()) + .and_then(|psbt_sighash_type| psbt_sighash_type.taproot_hash_ty().ok()) .unwrap_or(TapSighashType::All); let hash = SighashCache::new(&psbt.unsigned_tx).taproot_key_spend_signature_hash( 0, @@ -535,7 +536,7 @@ impl BenefactorWallet { .ok_or("Missing taproot key origin")?; let secret_key = self.master_xpriv.derive_priv(&self.secp, &derivation_path)?.to_priv().inner; - sign_psbt_schnorr( + sign_psbt_taproot( &secret_key, spend_info.internal_key(), None, @@ -669,7 +670,7 @@ impl BeneficiaryWallet { *lh, hash_ty, )?; - sign_psbt_schnorr( + sign_psbt_taproot( &secret_key, *x_only_pubkey, Some(*lh), @@ -729,7 +730,7 @@ impl BeneficiaryWallet { // licenses. // Calling this with `leaf_hash` = `None` will sign for key-spend -fn sign_psbt_schnorr( +fn sign_psbt_taproot( secret_key: &secp256k1::SecretKey, pubkey: XOnlyPublicKey, leaf_hash: Option, @@ -746,7 +747,7 @@ fn sign_psbt_schnorr( let sig = secp.sign_schnorr(&Message::from_slice(&hash.into_inner()[..]).unwrap(), &keypair); - let final_signature = schnorr::Signature { sig, hash_ty }; + let final_signature = taproot::Signature { sig, hash_ty }; if let Some(lh) = leaf_hash { psbt_input.tap_script_sigs.insert((pubkey, lh), final_signature); diff --git a/bitcoin/src/crypto/mod.rs b/bitcoin/src/crypto/mod.rs index c04531bf..4c4d5129 100644 --- a/bitcoin/src/crypto/mod.rs +++ b/bitcoin/src/crypto/mod.rs @@ -8,5 +8,5 @@ pub mod ecdsa; pub mod key; -pub mod schnorr; pub mod sighash; +pub mod taproot; diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 08366a53..4b85e1b1 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -253,7 +253,7 @@ impl fmt::Display for Error { PrevoutIndex => write!(f, "The index requested is greater than available prevouts or different from the provided [Provided::Anyone] index"), PrevoutKind => write!(f, "A single prevout has been provided but all prevouts are needed without `ANYONECANPAY`"), WrongAnnex => write!(f, "Annex must be at least one byte long and the first bytes must be `0x50`"), - InvalidSighashType(hash_ty) => write!(f, "Invalid schnorr Signature hash type : {} ", hash_ty), + InvalidSighashType(hash_ty) => write!(f, "Invalid taproot signature hash type : {} ", hash_ty), } } } diff --git a/bitcoin/src/crypto/schnorr.rs b/bitcoin/src/crypto/taproot.rs similarity index 87% rename from bitcoin/src/crypto/schnorr.rs rename to bitcoin/src/crypto/taproot.rs index 13de5c79..93f62ef5 100644 --- a/bitcoin/src/crypto/schnorr.rs +++ b/bitcoin/src/crypto/taproot.rs @@ -1,10 +1,9 @@ // Written in 2014 by Andrew Poelstra // SPDX-License-Identifier: CC0-1.0 -//! Schnorr Bitcoin keys. +//! Bitcoin taproot keys. //! -//! This module provides Schnorr keys used in Bitcoin, reexporting Secp256k1 -//! Schnorr key types. +//! This module provides taproot keys used in Bitcoin (including reexporting secp256k1 keys). //! use core::fmt; @@ -17,7 +16,7 @@ use crate::prelude::*; use crate::sighash::TapSighashType; -/// A BIP340-341 serialized schnorr signature with the corresponding hash type. +/// A BIP340-341 serialized taproot signature with the corresponding hash type. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] @@ -66,7 +65,7 @@ impl Signature { } -/// A schnorr sig related error. +/// A taproot sig related error. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[non_exhaustive] pub enum Error { @@ -74,7 +73,7 @@ pub enum Error { InvalidSighashType(u8), /// Signature has valid size but does not parse correctly Secp256k1(secp256k1::Error), - /// Invalid schnorr signature size + /// Invalid taproot signature size InvalidSignatureSize(usize), } @@ -83,11 +82,11 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::InvalidSighashType(hash_ty) => - write!(f, "Invalid signature hash type {}", hash_ty), + write!(f, "invalid signature hash type {}", hash_ty), Error::Secp256k1(ref e) => - write_err!(f, "Schnorr signature has correct len but is malformed"; e), + write_err!(f, "taproot signature has correct len but is malformed"; e), Error::InvalidSignatureSize(sz) => - write!(f, "Invalid Schnorr signature size: {}", sz), + write!(f, "invalid taproot signature size: {}", sz), } } } diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index dc74ca52..309ae9e8 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -127,7 +127,7 @@ pub use crate::blockdata::witness::{self, Witness}; pub use crate::blockdata::{constants, opcodes}; pub use crate::consensus::encode::VarInt; pub use crate::crypto::key::{self, PrivateKey, PublicKey}; -pub use crate::crypto::{ecdsa, schnorr, sighash}; +pub use crate::crypto::sighash; pub use crate::error::Error; pub use crate::hash_types::{Txid, Wtxid, BlockHash, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; pub use crate::merkle_tree::MerkleBlock; diff --git a/bitcoin/src/psbt/error.rs b/bitcoin/src/psbt/error.rs index 47bd4df7..6968785e 100644 --- a/bitcoin/src/psbt/error.rs +++ b/bitcoin/src/psbt/error.rs @@ -87,13 +87,13 @@ pub enum Error { InvalidXOnlyPublicKey, /// Parsing error indicating invalid ECDSA signatures InvalidEcdsaSignature(crate::crypto::ecdsa::Error), - /// Parsing error indicating invalid Schnorr signatures - InvalidSchnorrSignature(crate::crypto::schnorr::Error), + /// Parsing error indicating invalid taproot signatures + InvalidTaprootSignature(crate::crypto::taproot::Error), /// Parsing error indicating invalid control block InvalidControlBlock, /// Parsing error indicating invalid leaf version InvalidLeafVersion, - /// Parsing error indicating a Taproot error + /// Parsing error indicating a taproot error Taproot(&'static str), /// Error related to an xpub key XPubKey(&'static str), @@ -136,7 +136,7 @@ impl fmt::Display for Error { Error::InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e), Error::InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"), Error::InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e), - Error::InvalidSchnorrSignature(ref e) => write_err!(f, "invalid Schnorr signature"; e), + Error::InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e), Error::InvalidControlBlock => f.write_str("invalid control block"), Error::InvalidLeafVersion => f.write_str("invalid leaf version"), Error::Taproot(s) => write!(f, "taproot error - {}", s), @@ -179,7 +179,7 @@ impl std::error::Error for Error { | InvalidSecp256k1PublicKey(_) | InvalidXOnlyPublicKey | InvalidEcdsaSignature(_) - | InvalidSchnorrSignature(_) + | InvalidTaprootSignature(_) | InvalidControlBlock | InvalidLeafVersion | Taproot(_) diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs index 83753b7b..20882b07 100644 --- a/bitcoin/src/psbt/map/input.rs +++ b/bitcoin/src/psbt/map/input.rs @@ -11,7 +11,7 @@ use secp256k1::XOnlyPublicKey; use crate::blockdata::script::ScriptBuf; use crate::blockdata::witness::Witness; use crate::blockdata::transaction::{Transaction, TxOut}; -use crate::crypto::{ecdsa, schnorr}; +use crate::crypto::{ecdsa, taproot}; use crate::crypto::key::PublicKey; use crate::hashes::{self, hash160, ripemd160, sha256, sha256d}; use crate::bip32::KeySource; @@ -47,9 +47,9 @@ const PSBT_IN_SHA256: u8 = 0x0b; const PSBT_IN_HASH160: u8 = 0x0c; /// Type: HASH256 preimage PSBT_IN_HASH256 = 0x0d const PSBT_IN_HASH256: u8 = 0x0d; -/// Type: Schnorr Signature in Key Spend PSBT_IN_TAP_KEY_SIG = 0x13 +/// Type: Taproot Signature in Key Spend PSBT_IN_TAP_KEY_SIG = 0x13 const PSBT_IN_TAP_KEY_SIG: u8 = 0x13; -/// Type: Schnorr Signature in Script Spend PSBT_IN_TAP_SCRIPT_SIG = 0x14 +/// Type: Taproot Signature in Script Spend PSBT_IN_TAP_SCRIPT_SIG = 0x14 const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14; /// Type: Taproot Leaf Script PSBT_IN_TAP_LEAF_SCRIPT = 0x14 const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15; @@ -109,11 +109,11 @@ pub struct Input { /// HAS256 hash to preimage map. #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub hash256_preimages: BTreeMap>, - /// Serialized schnorr signature with sighash type for key spend. - pub tap_key_sig: Option, + /// Serialized taproot signature with sighash type for key spend. + pub tap_key_sig: Option, /// Map of `|` with signature. #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] - pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), schnorr::Signature>, + pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), taproot::Signature>, /// Map of Control blocks to Script version pair. #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_scripts: BTreeMap, @@ -146,9 +146,9 @@ pub struct PsbtSighashType { impl fmt::Display for PsbtSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.schnorr_hash_ty() { + match self.taproot_hash_ty() { Err(_) => write!(f, "{:#x}", self.inner), - Ok(schnorr_hash_ty) => fmt::Display::fmt(&schnorr_hash_ty, f), + Ok(taproot_hash_ty) => fmt::Display::fmt(&taproot_hash_ty, f), } } } @@ -160,7 +160,7 @@ impl FromStr for PsbtSighashType { fn from_str(s: &str) -> Result { // We accept strings of form: "SIGHASH_ALL" etc. // - // NB: some of Schnorr sighash types are non-standard for pre-taproot + // NB: some of Taproot sighash types are non-standard for pre-taproot // inputs. We also do not support SIGHASH_RESERVED in verbatim form // ("0xFF" string should be used instead). if let Ok(ty) = TapSighashType::from_str(s) { @@ -182,8 +182,8 @@ impl From for PsbtSighashType { } impl From for PsbtSighashType { - fn from(schnorr_hash_ty: TapSighashType) -> Self { - PsbtSighashType { inner: schnorr_hash_ty as u32 } + fn from(taproot_hash_ty: TapSighashType) -> Self { + PsbtSighashType { inner: taproot_hash_ty as u32 } } } @@ -196,7 +196,7 @@ impl PsbtSighashType { /// Returns the [`TapSighashType`] if the [`PsbtSighashType`] can be /// converted to one. - pub fn schnorr_hash_ty(self) -> Result { + pub fn taproot_hash_ty(self) -> Result { if self.inner > 0xffu32 { Err(sighash::Error::InvalidSighashType(self.inner)) } else { @@ -239,10 +239,10 @@ impl Input { /// /// # Errors /// - /// If the `sighash_type` field is set to a invalid Schnorr sighash value. - pub fn schnorr_hash_ty(&self) -> Result { + /// If the `sighash_type` field is set to a invalid Taproot sighash value. + pub fn taproot_hash_ty(&self) -> Result { self.sighash_type - .map(|sighash_type| sighash_type.schnorr_hash_ty()) + .map(|sighash_type| sighash_type.taproot_hash_ty()) .unwrap_or(Ok(TapSighashType::Default)) } @@ -312,12 +312,12 @@ impl Input { } PSBT_IN_TAP_KEY_SIG => { impl_psbt_insert_pair! { - self.tap_key_sig <= | + self.tap_key_sig <= | } } PSBT_IN_TAP_SCRIPT_SIG => { impl_psbt_insert_pair! { - self.tap_script_sigs <= | + self.tap_script_sigs <= | } } PSBT_IN_TAP_LEAF_SCRIPT => { @@ -543,8 +543,8 @@ mod test { } #[test] - fn psbt_sighash_type_schnorr() { - for schnorr in &[ + fn psbt_sighash_type_taproot() { + for tap in &[ TapSighashType::Default, TapSighashType::All, TapSighashType::None, @@ -553,11 +553,11 @@ mod test { TapSighashType::NonePlusAnyoneCanPay, TapSighashType::SinglePlusAnyoneCanPay, ] { - let sighash = PsbtSighashType::from(*schnorr); + let sighash = PsbtSighashType::from(*tap); let s = format!("{}", sighash); let back = PsbtSighashType::from_str(&s).unwrap(); assert_eq!(back, sighash); - assert_eq!(back.schnorr_hash_ty().unwrap(), *schnorr); + assert_eq!(back.taproot_hash_ty().unwrap(), *tap); } } @@ -570,6 +570,6 @@ mod test { assert_eq!(back, sighash); assert_eq!(back.ecdsa_hash_ty(), Err(NonStandardSighashType(nonstd))); - assert_eq!(back.schnorr_hash_ty(), Err(sighash::Error::InvalidSighashType(nonstd))); + assert_eq!(back.taproot_hash_ty(), Err(sighash::Error::InvalidSighashType(nonstd))); } } diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 62d756e9..d2fba494 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1376,9 +1376,9 @@ mod tests { assert_eq!(err.to_string(), "invalid xonly public key"); let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757011342173bb3d36c074afb716fec6307a069a2e450b995f3c82785945ab8df0e24260dcd703b0cbf34de399184a9481ac2b3586db6601f026a77f7e4938481bc34751701aa000000").unwrap_err(); #[cfg(feature = "std")] - assert_eq!(err.to_string(), "invalid Schnorr signature"); + assert_eq!(err.to_string(), "invalid taproot signature"); #[cfg(not(feature = "std"))] - assert_eq!(err.to_string(), "invalid Schnorr signature: Invalid Schnorr signature size: 66"); + assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 66"); let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err(); assert_eq!(err.to_string(), "invalid xonly public key"); let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err(); @@ -1392,14 +1392,14 @@ mod tests { assert_eq!(err.to_string(), "hash parse error: invalid slice length 33 (expected 32)"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094289756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb01010000").unwrap_err(); #[cfg(feature = "std")] - assert_eq!(err.to_string(), "invalid Schnorr signature"); + assert_eq!(err.to_string(), "invalid taproot signature"); #[cfg(not(feature = "std"))] - assert_eq!(err.to_string(), "invalid Schnorr signature: Invalid Schnorr signature size: 66"); + assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 66"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err(); #[cfg(feature = "std")] - assert_eq!(err.to_string(), "invalid Schnorr signature"); + assert_eq!(err.to_string(), "invalid taproot signature"); #[cfg(not(feature = "std"))] - assert_eq!(err.to_string(), "invalid Schnorr signature: Invalid Schnorr signature size: 57"); + assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 57"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err(); assert_eq!(err.to_string(), "invalid control block"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err(); diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index bcd9bebd..493e2c70 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -19,7 +19,7 @@ use crate::consensus::encode::{self, serialize, Decodable, Encodable, deserializ use secp256k1::{self, XOnlyPublicKey}; use crate::bip32::{ChildNumber, Fingerprint, KeySource}; use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; -use crate::crypto::{ecdsa, schnorr}; +use crate::crypto::{ecdsa, taproot}; use crate::psbt::{Error, PartiallySignedTransaction}; use crate::taproot::{TapNodeHash, TapLeafHash, ControlBlock, LeafVersion}; use crate::crypto::key::PublicKey; @@ -283,24 +283,24 @@ impl Deserialize for XOnlyPublicKey { } } -impl Serialize for schnorr::Signature { +impl Serialize for taproot::Signature { fn serialize(&self) -> Vec { self.to_vec() } } -impl Deserialize for schnorr::Signature { +impl Deserialize for taproot::Signature { fn deserialize(bytes: &[u8]) -> Result { - schnorr::Signature::from_slice(bytes) + taproot::Signature::from_slice(bytes) .map_err(|e| match e { - schnorr::Error::InvalidSighashType(flag) => { + taproot::Error::InvalidSighashType(flag) => { Error::NonStandardSighashType(flag as u32) } - schnorr::Error::InvalidSignatureSize(_) => { - Error::InvalidSchnorrSignature(e) + taproot::Error::InvalidSignatureSize(_) => { + Error::InvalidTaprootSignature(e) } - schnorr::Error::Secp256k1(..) => { - Error::InvalidSchnorrSignature(e) + taproot::Error::Secp256k1(..) => { + Error::InvalidTaprootSignature(e) } }) } diff --git a/bitcoin/tests/data/serde/schnorr_sig_bincode b/bitcoin/tests/data/serde/taproot_sig_bincode similarity index 100% rename from bitcoin/tests/data/serde/schnorr_sig_bincode rename to bitcoin/tests/data/serde/taproot_sig_bincode diff --git a/bitcoin/tests/data/serde/schnorr_sig_hex b/bitcoin/tests/data/serde/taproot_sig_hex similarity index 100% rename from bitcoin/tests/data/serde/schnorr_sig_hex rename to bitcoin/tests/data/serde/taproot_sig_hex diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index d06aafc4..254a2016 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -31,6 +31,7 @@ use bitcoin::blockdata::locktime::{absolute, relative}; use bitcoin::blockdata::witness::Witness; use bitcoin::consensus::encode::deserialize; use bitcoin::crypto::key::UntweakedPublicKey; +use bitcoin::crypto::{ecdsa, taproot}; use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey}; @@ -38,7 +39,7 @@ use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::taproot::{ControlBlock, LeafVersion, TaprootBuilder, TaprootSpendInfo}; use bitcoin::{ - ecdsa, schnorr, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target, + Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target, Transaction, TxIn, TxOut, Txid, Work, }; use secp256k1::Secp256k1; @@ -339,15 +340,15 @@ fn serde_regression_proprietary_key() { } #[test] -fn serde_regression_schnorr_sig() { - let s = include_str!("data/serde/schnorr_sig_hex"); - let sig = schnorr::Signature { +fn serde_regression_taproot_sig() { + let s = include_str!("data/serde/taproot_sig_hex"); + let sig = taproot::Signature { sig: secp256k1::schnorr::Signature::from_str(s.trim()).unwrap(), hash_ty: TapSighashType::All, }; let got = serialize(&sig).unwrap(); - let want = include_bytes!("data/serde/schnorr_sig_bincode") as &[_]; + let want = include_bytes!("data/serde/taproot_sig_bincode") as &[_]; assert_eq!(got, want) }