Merge rust-bitcoin/rust-bitcoin#1597: Move sighash types around

be7b3754a9 Rename schnorr module to taproot (Tobin C. Harding)
9f39e872bc Rename SchnorrSighashType to TapSighashType (Tobin C. Harding)
f5c26693c5 Make match arms more terse (Tobin C. Harding)
40c246743b Split Sighash into LegacySighash and SegwitV0Sighash (Tobin C. Harding)
e38d843536 Do not use deprecated function in rustdoc example (Tobin C. Harding)
98130f49f1 Rename TapSighashHash to TapSighash (Tobin C. Harding)
7e4da3c0ab Move taproot keys to the keys module (Tobin C. Harding)
c5fe315a93 Move sighash to crypto module (Tobin C. Harding)

Pull request description:

  This PR is now part 1 of great sighash clean up. It does not attempt to split ecdsa into two parts as discussed below, that is WIP and will be done in a separate PR after this upcoming release. Does however create `LegacySighash` and `SegwitV0Sighash` types.

  This PR moves us along the road by doing:

  - Move `sighash` to the `crypto` module, where I should have put it ages ago :)
  - Move the taproot keys to the `keys` module
  - Rename the `schnorr` module -> `taproot`
  - Rename `TapSighashHash` -> `TapSighash`
  - Rename `SchnorrSighashType` -> `TapSighashType`
  - Fix a bunch of other schnorr usage (including pub/priv methods).

  This leaves us in a situation where we have taproot sig and sighash type, and non-taproot ones prefixed with "ecdsa". Its not uniform but it kind of makes sense.

  Fix: #1542
  Fix: #1550

ACKs for top commit:
  Kixunil:
    ACK be7b3754a9
  apoelstra:
    ACK be7b3754a9

Tree-SHA512: 4c52bea9ba71713afa181d625153d73d3c5b7c6f5786248960958982332a6a79501cd26e13a66bfb9700d9b8f59717446abb795ecbfbd8d60d9d59a38c1d718b
This commit is contained in:
Andrew Poelstra 2023-02-20 13:42:01 +00:00
commit 090c376fdf
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
20 changed files with 649 additions and 615 deletions

View File

@ -81,18 +81,18 @@ 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::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::sighash::{self, TapSighashType, SighashCache};
use bitcoin::taproot::{
LeafVersion, TapLeafHash, TapSighashHash, TaprootBuilder, TaprootSpendInfo,
LeafVersion, TapLeafHash, TapSighash, TaprootBuilder, TaprootSpendInfo,
};
use bitcoin::{
absolute, script, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness,
absolute, script, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
@ -283,8 +283,8 @@ 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())
.unwrap_or(SchnorrSighashType::All);
.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,
&sighash::Prevouts::All(&[TxOut {
@ -300,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,
@ -518,8 +518,8 @@ impl BenefactorWallet {
let hash_ty = input
.sighash_type
.and_then(|psbt_sighash_type| psbt_sighash_type.schnorr_hash_ty().ok())
.unwrap_or(SchnorrSighashType::All);
.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,
&sighash::Prevouts::All(&[TxOut {
@ -536,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,
@ -660,7 +660,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 {
@ -670,7 +670,7 @@ impl BeneficiaryWallet {
*lh,
hash_ty,
)?;
sign_psbt_schnorr(
sign_psbt_taproot(
&secret_key,
*x_only_pubkey,
Some(*lh),
@ -730,13 +730,13 @@ 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<TapLeafHash>,
psbt_input: &mut psbt::Input,
hash: TapSighashHash,
hash_ty: SchnorrSighashType,
hash: TapSighash,
hash_ty: TapSighashType,
secp: &Secp256k1<secp256k1::All>,
) {
let keypair = secp256k1::KeyPair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
@ -747,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);

View File

@ -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};

View File

@ -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.

View File

@ -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.

View File

@ -30,14 +30,15 @@ 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;
use super::Weight;
#[cfg(doc)]
use crate::sighash::{EcdsaSighashType, SchnorrSighashType};
use crate::sighash::{EcdsaSighashType, TapSighashType};
/// A reference to a transaction output.
///
@ -589,16 +590,17 @@ impl<E> EncodeSigningDataResult<E> {
/// ```rust
/// # use bitcoin::consensus::deserialize;
/// # use bitcoin::Transaction;
/// # use bitcoin::hash_types::Sighash;
/// # use bitcoin::crypto::sighash::{LegacySighash, SighashCache};
/// # use bitcoin_hashes::{Hash, hex::FromHex};
/// # let mut writer = Sighash::engine();
/// # let mut writer = LegacySighash::engine();
/// # let input_index = 0;
/// # let script_pubkey = bitcoin::ScriptBuf::new();
/// # let sighash_u32 = 0u32;
/// # 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
@ -835,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);

View File

@ -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<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> 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<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> (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<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> 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<TweakedPublicKey> for XOnlyPublicKey {
#[inline]
fn from(pair: TweakedPublicKey) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> for KeyPair {
#[inline]
fn from(pair: TweakedKeyPair) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> for TweakedPublicKey {
#[inline]
fn from(pair: TweakedKeyPair) -> Self {
TweakedPublicKey::from_keypair(pair)
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -8,4 +8,5 @@
pub mod ecdsa;
pub mod key;
pub mod schnorr;
pub mod sighash;
pub mod taproot;

View File

@ -1,323 +0,0 @@
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
// SPDX-License-Identifier: CC0-1.0
//! Schnorr Bitcoin keys.
//!
//! This module provides Schnorr keys used in Bitcoin, reexporting Secp256k1
//! Schnorr key types.
//!
use core::fmt;
use bitcoin_internals::write_err;
pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verification, Parity};
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<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> 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<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> (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<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> 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<TweakedPublicKey> for XOnlyPublicKey {
#[inline]
fn from(pair: TweakedPublicKey) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> for KeyPair {
#[inline]
fn from(pair: TweakedKeyPair) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> 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))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
pub struct Signature {
/// The underlying schnorr signature
pub sig: secp256k1::schnorr::Signature,
/// The corresponding hash type
pub hash_ty: SchnorrSighashType,
}
impl Signature {
/// Deserialize from slice
pub fn from_slice(sl: &[u8]) -> Result<Self, Error> {
match sl.len() {
64 => {
// default type
let sig = secp256k1::schnorr::Signature::from_slice(sl)
.map_err(Error::Secp256k1)?;
Ok(Signature { sig, hash_ty: SchnorrSighashType::Default })
},
65 => {
let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
let hash_ty = SchnorrSighashType::from_consensus_u8(*hash_ty)
.map_err(|_| Error::InvalidSighashType(*hash_ty))?;
let sig = secp256k1::schnorr::Signature::from_slice(sig)
.map_err(Error::Secp256k1)?;
Ok(Signature { sig, hash_ty })
}
len => {
Err(Error::InvalidSignatureSize(len))
}
}
}
/// Serialize Signature
pub fn to_vec(self) -> Vec<u8> {
// 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 {
// default sighash type, don't add extra sighash byte
} else {
ser_sig.push(self.hash_ty as u8);
}
ser_sig
}
}
/// A schnorr sig related error.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub enum Error {
/// Base58 encoding error
InvalidSighashType(u8),
/// Signature has valid size but does not parse correctly
Secp256k1(secp256k1::Error),
/// Invalid schnorr signature size
InvalidSignatureSize(usize),
}
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),
Error::Secp256k1(ref e) =>
write_err!(f, "Schnorr signature has correct len but is malformed"; e),
Error::InvalidSignatureSize(sz) =>
write!(f, "Invalid Schnorr signature size: {}", sz),
}
}
}
#[cfg(feature = "std")]
#[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::*;
match self {
Secp256k1(e) => Some(e),
InvalidSighashType(_) | InvalidSignatureSize(_) => None,
}
}
}
impl From<secp256k1::Error> for Error {
fn from(e: secp256k1::Error) -> Error {
Error::Secp256k1(e)
}
}

View File

@ -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, TapSighashHash, 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<T: Borrow<Transaction>> {
@ -77,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>
@ -107,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,
@ -127,35 +159,39 @@ 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 TapSighashType::*;
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)
}
}
impl str::FromStr for SchnorrSighashType {
impl str::FromStr for TapSighashType {
type Err = SighashTypeParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use TapSighashType::*;
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() }),
}
}
@ -207,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 taproot signature hash type : {} ", hash_ty),
}
}
}
@ -224,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(_)
@ -301,7 +339,7 @@ impl<'s> From<ScriptPath<'s>> 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.
@ -325,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)
}
@ -341,13 +381,15 @@ impl str::FromStr for EcdsaSighashType {
type Err = SighashTypeParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
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() }),
}
}
@ -356,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),
}
}
@ -376,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.
@ -383,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,
}
}
@ -401,14 +447,16 @@ impl EcdsaSighashType {
///
/// If `n` is a non-standard sighash value.
pub fn from_standard(n: u32) -> Result<EcdsaSighashType, NonStandardSighashType> {
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)),
}
}
@ -419,36 +467,40 @@ impl EcdsaSighashType {
pub fn to_u32(self) -> u32 { self as u32 }
}
impl From<EcdsaSighashType> for SchnorrSighashType {
impl From<EcdsaSighashType> for TapSighashType {
fn from(s: EcdsaSighashType) -> Self {
use TapSighashType::*;
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,
}
}
}
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) {
pub(crate) fn split_anyonecanpay_flag(self) -> (TapSighashType, bool) {
use TapSighashType::*;
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),
}
}
/// Constructs a [`SchnorrSighashType`] from a raw `u8`.
/// Constructs a [`TapSighashType`] from a raw `u8`.
pub fn from_consensus_u8(hash_ty: u8) -> Result<Self, Error> {
use SchnorrSighashType::*;
use TapSighashType::*;
Ok(match hash_ty {
0x00 => Default,
@ -522,7 +574,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
prevouts: &Prevouts<T>,
annex: Option<Annex>,
leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
sighash_type: SchnorrSighashType,
sighash_type: TapSighashType,
) -> Result<(), Error> {
prevouts.check_all(self.tx.borrow())?;
@ -556,7 +608,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
// 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)?;
}
@ -604,7 +656,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
// * 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()
@ -639,9 +691,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
prevouts: &Prevouts<T>,
annex: Option<Annex>,
leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
sighash_type: SchnorrSighashType,
) -> Result<TapSighashHash, Error> {
let mut enc = TapSighashHash::engine();
sighash_type: TapSighashType,
) -> Result<TapSighash, Error> {
let mut enc = TapSighash::engine();
self.taproot_encode_signing_data_to(
&mut enc,
input_index,
@ -650,7 +702,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
leaf_hash_code_separator,
sighash_type,
)?;
Ok(TapSighashHash::from_engine(enc))
Ok(TapSighash::from_engine(enc))
}
/// Computes the BIP341 sighash for a key spend.
@ -658,9 +710,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
&mut self,
input_index: usize,
prevouts: &Prevouts<T>,
sighash_type: SchnorrSighashType,
) -> Result<TapSighashHash, Error> {
let mut enc = TapSighashHash::engine();
sighash_type: TapSighashType,
) -> Result<TapSighash, Error> {
let mut enc = TapSighash::engine();
self.taproot_encode_signing_data_to(
&mut enc,
input_index,
@ -669,7 +721,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
None,
sighash_type,
)?;
Ok(TapSighashHash::from_engine(enc))
Ok(TapSighash::from_engine(enc))
}
/// Computes the BIP341 sighash for a script spend.
@ -681,9 +733,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
input_index: usize,
prevouts: &Prevouts<T>,
leaf_hash: S,
sighash_type: SchnorrSighashType,
) -> Result<TapSighashHash, Error> {
let mut enc = TapSighashHash::engine();
sighash_type: TapSighashType,
) -> Result<TapSighash, Error> {
let mut enc = TapSighash::engine();
self.taproot_encode_signing_data_to(
&mut enc,
input_index,
@ -692,7 +744,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
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
@ -741,9 +793,9 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
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 +813,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
script_code: &Script,
value: u64,
sighash_type: EcdsaSighashType,
) -> Result<Sighash, Error> {
let mut enc = Sighash::engine();
) -> Result<SegwitV0Sighash, Error> {
let mut enc = SegwitV0Sighash::engine();
self.segwit_encode_signing_data_to(
&mut enc,
input_index,
@ -770,7 +822,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
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 +982,15 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
input_index: usize,
script_pubkey: &Script,
sighash_type: u32,
) -> Result<Sighash, Error> {
let mut enc = Sighash::engine();
) -> Result<LegacySighash, Error> {
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 +1120,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, TapSighashHash};
use crate::taproot::TapLeafHash;
extern crate serde_json;
@ -1092,7 +1144,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 +1167,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();
@ -1126,7 +1178,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::<Value>(data).unwrap().as_array().unwrap().clone();
for t in testdata.iter().skip(1) {
@ -1144,9 +1196,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());
}
@ -1159,7 +1211,7 @@ mod tests {
"01365724000000000023542156b39dab4f8f3508e0432cfb41fab110170acaa2d4c42539cb90a4dc7c093bc500",
0,
"33ca0ebfb4a945eeee9569fc0f5040221275f88690b7f8592ada88ce3bdf6703",
SchnorrSighashType::Default, None, None, None
TapSighashType::Default, None, None, None
);
test_taproot_sighash(
@ -1167,7 +1219,7 @@ mod tests {
"02591f220000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece48fb310000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece",
1,
"626ab955d58c9a8a600a0c580549d06dc7da4e802eb2a531f62a588e430967a8",
SchnorrSighashType::All, None, None, None
TapSighashType::All, None, None, None
);
test_taproot_sighash(
@ -1175,7 +1227,7 @@ mod tests {
"01c4811000000000002251201bf9297d0a2968ae6693aadd0fa514717afefd218087a239afb7418e2d22e65c",
0,
"dfa9437f9c9a1d1f9af271f79f2f5482f287cdb0d2e03fa92c8a9b216cc6061c",
SchnorrSighashType::AllPlusAnyoneCanPay, None, None, None
TapSighashType::AllPlusAnyoneCanPay, None, None, None
);
test_taproot_sighash(
@ -1183,7 +1235,7 @@ mod tests {
"0144c84d0000000000225120e3f2107989c88e67296ab2faca930efa2e3a5bd3ff0904835a11c9e807458621",
0,
"3129de36a5d05fff97ffca31eb75fcccbbbc27b3147a7a36a9e4b45d8b625067",
SchnorrSighashType::None, None, None, None
TapSighashType::None, None, None, None
);
test_taproot_sighash(
@ -1191,7 +1243,7 @@ mod tests {
"013fed110000000000225120eb536ae8c33580290630fc495046e998086a64f8f33b93b07967d9029b265c55",
0,
"2441e8b0e063a2083ee790f14f2045022f07258ddde5ee01de543c9e789d80ae",
SchnorrSighashType::NonePlusAnyoneCanPay, None, None, None
TapSighashType::NonePlusAnyoneCanPay, None, None, None
);
test_taproot_sighash(
@ -1199,7 +1251,7 @@ mod tests {
"01efa558000000000022512007071ea3dc7e331b0687d0193d1e6d6ed10e645ef36f10ef8831d5e522ac9e80",
0,
"30239345177cadd0e3ea413d49803580abb6cb27971b481b7788a78d35117a88",
SchnorrSighashType::Single, None, None, None
TapSighashType::Single, None, None, None
);
test_taproot_sighash(
@ -1207,7 +1259,7 @@ mod tests {
"0107af4e00000000002251202c36d243dfc06cb56a248e62df27ecba7417307511a81ae61aa41c597a929c69",
0,
"bf9c83f26c6dd16449e4921f813f551c4218e86f2ec906ca8611175b41b566df",
SchnorrSighashType::SinglePlusAnyoneCanPay, None, None, None
TapSighashType::SinglePlusAnyoneCanPay, None, None, None
);
}
@ -1218,7 +1270,7 @@ mod tests {
"01ea49260000000000225120ab5e9800806bf18cb246edcf5fe63441208fe955a4b5a35bbff65f5db622a010",
0,
"3b003000add359a364a156e73e02846782a59d0d95ca8c4638aaad99f2ef915c",
SchnorrSighashType::SinglePlusAnyoneCanPay,
TapSighashType::SinglePlusAnyoneCanPay,
Some("507b979802e62d397acb29f56743a791894b99372872fc5af06a4f6e8d242d0615cda53062bb20e6ec79756fe39183f0c128adfe85559a8fa042b042c018aa8010143799e44f0893c40e1e"),
None,
None,
@ -1232,7 +1284,7 @@ mod tests {
"011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182",
0,
"d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e",
SchnorrSighashType::All,
TapSighashType::All,
None,
Some("20cc4e1107aea1d170c5ff5b6817e1303010049724fb3caa7941792ea9d29b3e2bacab"),
None,
@ -1246,7 +1298,7 @@ mod tests {
"011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182",
0,
"d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e",
SchnorrSighashType::All,
TapSighashType::All,
None,
None,
Some("15a2530514e399f8b5cf0b3d3112cf5b289eaa3e308ba2071b58392fdc6da68a"),
@ -1260,7 +1312,7 @@ mod tests {
"011458360000000000225120a7baec3fb9f84614e3899fcc010c638f80f13539344120e1f4d8b68a9a011a13",
0,
"a0042aa434f9a75904b64043f2a283f8b4c143c7f4f7f49a6cbe5b9f745f4c15",
SchnorrSighashType::All,
TapSighashType::All,
Some("50a6272b470e1460e3332ade7bb14b81671c564fb6245761bd5bd531394b28860e0b3808ab229fb51791fb6ae6fa82d915b2efb8f6df83ae1f5ab3db13e30928875e2a22b749d89358de481f19286cd4caa792ce27f9559082d227a731c5486882cc707f83da361c51b7aadd9a0cf68fe7480c410fa137b454482d9a1ebf0f96d760b4d61426fc109c6e8e99a508372c45caa7b000a41f8251305da3f206c1849985ba03f3d9592832b4053afbd23ab25d0465df0bc25a36c223aacf8e04ec736a418c72dc319e4da3e972e349713ca600965e7c665f2090d5a70e241ac164115a1f5639f28b1773327715ca307ace64a2de7f0e3df70a2ffee3857689f909c0dad46d8a20fa373a4cc6eed6d4c9806bf146f0d76baae1"),
Some("7520ab9160dd8299dc1367659be3e8f66781fe440d52940c7f8d314a89b9f2698d406ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6eadac"),
None,
@ -1282,27 +1334,27 @@ mod tests {
let empty_vec = vec![];
let empty_prevouts : Prevouts<TxOut> = 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
@ -1310,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
@ -1338,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>,
@ -1387,14 +1439,14 @@ mod tests {
#[cfg(feature = "serde")]
#[test]
fn bip_341_sighash_tests() {
fn sighash_deser_numeric<'de, D>(deserializer: D) -> Result<SchnorrSighashType, D::Error>
fn sighash_deser_numeric<'de, D>(deserializer: D) -> Result<TapSighashType, D::Error>
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",
@ -1444,7 +1496,7 @@ mod tests {
internal_privkey: SecretKey,
merkle_root: Option<TapNodeHash>,
#[serde(deserialize_with = "sighash_deser_numeric")]
hash_type: SchnorrSighashType,
hash_type: TapSighashType,
}
#[derive(serde::Deserialize)]
@ -1456,7 +1508,7 @@ mod tests {
tweaked_privkey: SecretKey,
sig_msg: String,
//precomputed_used: Vec<String>, // unused
sig_hash: TapSighashHash,
sig_hash: TapSighash,
}
#[derive(serde::Deserialize)]
@ -1494,7 +1546,7 @@ mod tests {
//script_pubkey: Vec<ScriptPubKey>, // 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::<TestData>(json_str).expect("JSON was not well-formatted");
@ -1532,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)
};
@ -1578,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",
@ -1606,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)
);
}
@ -1635,7 +1687,7 @@ mod tests {
let mut cache = SighashCache::new(&tx);
assert_eq!(
cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(),
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670".parse::<Sighash>().unwrap(),
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670".parse::<SegwitV0Sighash>().unwrap(),
);
let cache = cache.segwit_cache();
@ -1671,7 +1723,7 @@ mod tests {
let mut cache = SighashCache::new(&tx);
assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6".parse::<Sighash>().unwrap(),
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6".parse::<SegwitV0Sighash>().unwrap(),
);
let cache = cache.segwit_cache();
@ -1712,7 +1764,7 @@ mod tests {
let mut cache = SighashCache::new(&tx);
assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
"185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c".parse::<Sighash>().unwrap(),
"185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c".parse::<SegwitV0Sighash>().unwrap(),
);
let cache = cache.segwit_cache();

View File

@ -0,0 +1,112 @@
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
// SPDX-License-Identifier: CC0-1.0
//! Bitcoin taproot keys.
//!
//! This module provides taproot keys used in Bitcoin (including reexporting secp256k1 keys).
//!
use core::fmt;
use bitcoin_internals::write_err;
pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verification, Parity};
use crate::prelude::*;
use crate::sighash::TapSighashType;
/// 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"))]
pub struct Signature {
/// The underlying schnorr signature
pub sig: secp256k1::schnorr::Signature,
/// The corresponding hash type
pub hash_ty: TapSighashType,
}
impl Signature {
/// Deserialize from slice
pub fn from_slice(sl: &[u8]) -> Result<Self, Error> {
match sl.len() {
64 => {
// default type
let sig = secp256k1::schnorr::Signature::from_slice(sl)
.map_err(Error::Secp256k1)?;
Ok(Signature { sig, hash_ty: TapSighashType::Default })
},
65 => {
let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
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)?;
Ok(Signature { sig, hash_ty })
}
len => {
Err(Error::InvalidSignatureSize(len))
}
}
}
/// Serialize Signature
pub fn to_vec(self) -> Vec<u8> {
// TODO: add support to serialize to a writer to SerializedSig
let mut ser_sig = self.sig.as_ref().to_vec();
if self.hash_ty == TapSighashType::Default {
// default sighash type, don't add extra sighash byte
} else {
ser_sig.push(self.hash_ty as u8);
}
ser_sig
}
}
/// A taproot sig related error.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[non_exhaustive]
pub enum Error {
/// Base58 encoding error
InvalidSighashType(u8),
/// Signature has valid size but does not parse correctly
Secp256k1(secp256k1::Error),
/// Invalid taproot signature size
InvalidSignatureSize(usize),
}
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),
Error::Secp256k1(ref e) =>
write_err!(f, "taproot signature has correct len but is malformed"; e),
Error::InvalidSignatureSize(sz) =>
write!(f, "invalid taproot signature size: {}", sz),
}
}
}
#[cfg(feature = "std")]
#[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::*;
match self {
Secp256k1(e) => Some(e),
InvalidSighashType(_) | InvalidSignatureSize(_) => None,
}
}
}
impl From<secp256k1::Error> for Error {
fn from(e: secp256k1::Error) -> Error {
Error::Secp256k1(e)
}
}

View File

@ -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.");

View File

@ -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::sighash;
pub use crate::error::Error;
pub use crate::hash_types::{Txid, Wtxid, BlockHash, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
pub use crate::merkle_tree::MerkleBlock;

View File

@ -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(_)

View File

@ -11,14 +11,14 @@ 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;
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
@ -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<sha256d::Hash, Vec<u8>>,
/// Serialized schnorr signature with sighash type for key spend.
pub tap_key_sig: Option<schnorr::Signature>,
/// Serialized taproot signature with sighash type for key spend.
pub tap_key_sig: Option<taproot::Signature>,
/// Map of `<xonlypubkey>|<leafhash>` 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<ControlBlock, (ScriptBuf, LeafVersion)>,
@ -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)]
@ -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,10 +160,10 @@ impl FromStr for PsbtSighashType {
fn from_str(s: &str) -> Result<Self, Self::Err> {
// 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) = SchnorrSighashType::from_str(s) {
if let Ok(ty) = TapSighashType::from_str(s) {
return Ok(ty.into());
}
@ -181,9 +181,9 @@ impl From<EcdsaSighashType> for PsbtSighashType {
}
}
impl From<SchnorrSighashType> for PsbtSighashType {
fn from(schnorr_hash_ty: SchnorrSighashType) -> Self {
PsbtSighashType { inner: schnorr_hash_ty as u32 }
impl From<TapSighashType> for PsbtSighashType {
fn from(taproot_hash_ty: TapSighashType) -> Self {
PsbtSighashType { inner: taproot_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<SchnorrSighashType, sighash::Error> {
pub fn taproot_hash_ty(self) -> Result<TapSighashType, sighash::Error> {
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<SchnorrSighashType, sighash::Error> {
/// If the `sighash_type` field is set to a invalid Taproot sighash value.
pub fn taproot_hash_ty(&self) -> Result<TapSighashType, sighash::Error> {
self.sighash_type
.map(|sighash_type| sighash_type.schnorr_hash_ty())
.unwrap_or(Ok(SchnorrSighashType::Default))
.map(|sighash_type| sighash_type.taproot_hash_ty())
.unwrap_or(Ok(TapSighashType::Default))
}
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
@ -312,12 +312,12 @@ impl Input {
}
PSBT_IN_TAP_KEY_SIG => {
impl_psbt_insert_pair! {
self.tap_key_sig <= <raw_key: _>|<raw_value: schnorr::Signature>
self.tap_key_sig <= <raw_key: _>|<raw_value: taproot::Signature>
}
}
PSBT_IN_TAP_SCRIPT_SIG => {
impl_psbt_insert_pair! {
self.tap_script_sigs <= <raw_key: (XOnlyPublicKey, TapLeafHash)>|<raw_value: schnorr::Signature>
self.tap_script_sigs <= <raw_key: (XOnlyPublicKey, TapLeafHash)>|<raw_value: taproot::Signature>
}
}
PSBT_IN_TAP_LEAF_SCRIPT => {
@ -543,21 +543,21 @@ 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,
fn psbt_sighash_type_taproot() {
for tap in &[
TapSighashType::Default,
TapSighashType::All,
TapSighashType::None,
TapSighashType::Single,
TapSighashType::AllPlusAnyoneCanPay,
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)));
}
}

View File

@ -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`.
@ -1373,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();
@ -1389,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();

View File

@ -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<u8> {
self.to_vec()
}
}
impl Deserialize for schnorr::Signature {
impl Deserialize for taproot::Signature {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
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)
}
})
}

View File

@ -13,11 +13,13 @@ 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};
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 [`TapSighashHash`].
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!(TapSighashHash, 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 {
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
@ -1145,7 +1130,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};
@ -1165,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());
@ -1186,7 +1172,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]
@ -1209,7 +1195,7 @@ mod test {
"8aa4229474ab0100b2d6f0687f031d1fc9d8eef92a042ad97d279bff456b15e4"
);
assert_eq!(
TapSighashHash::from_engine(TapSighashTag::engine()).to_string(),
TapSighash::from_engine(TapSighashTag::engine()).to_string(),
"dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803"
);
@ -1231,7 +1217,7 @@ mod test {
"cd8737b5e6047fc3f16f03e8b9959e3440e1bdf6dd02f7bb899c352ad490ea1e"
);
assert_eq!(
TapSighashHash::hash(&[0]).to_string(),
TapSighash::hash(&[0]).to_string(),
"c2fd0de003889a09c4afcf676656a0d8a1fb706313ff7d509afb00c323c010cd"
);
}

View File

@ -30,15 +30,16 @@ 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::crypto::{ecdsa, taproot};
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::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::taproot::{ControlBlock, LeafVersion, TaprootBuilder, TaprootSpendInfo};
use bitcoin::{
ecdsa, 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: SchnorrSighashType::All,
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)
}