Merge rust-bitcoin/rust-bitcoin#702: Separate signature hash types
8361129518
Add SchnorrSig type (sanket1729)94cfe79170
Rename existing SigHashType to EcdsaSigHashType (sanket1729)648b3975a5
Add SchnorrSigHashType::from_u8 (sanket1729)410e8bf46c
Rename sighash::SigHashType::SigHashType to SchnorrSigHashType (sanket1729)fa112a793a
Add EcdsaSig (sanket1729) Pull request description: Fixes #670 . Separates `SchnorrSigHashType` and `LegacySigHashType`. Also adds the following new structs: ```rust pub struct SchnorrSig { /// The underlying schnorr signature pub sig: secp256k1::schnorrsig::Signature, /// The corresponding hash type pub hash_ty: SchnorrSigHashType, } pub struct EcdsaSig { /// The underlying DER serialized Signature pub sig: secp256k1::Signature, /// The corresponding hash type pub hash_ty: LegacySigHashType, } ``` This code is currently minimal to aid reviews. We can at a later point implement (Encodeable, psbt::Serialize, FromHex, ToHex) etc in follow-up PRs. ACKs for top commit: Kixunil: ACK8361129518
RCasatta: ACK8361129518
Tree-SHA512: 800ddcb3677a4f19e9d1c2a7eb7e95b0a677e9135e1e99f9e42956fc6a3fc94f639403076b4925b3adba6fdd95f56a99c2e47d0310675ad51ce5e7453c7355b6
This commit is contained in:
commit
970f574968
|
@ -333,10 +333,10 @@ impl Transaction {
|
||||||
let sighash_type : u32 = sighash_type.into();
|
let sighash_type : u32 = sighash_type.into();
|
||||||
assert!(input_index < self.input.len()); // Panic on OOB
|
assert!(input_index < self.input.len()); // Panic on OOB
|
||||||
|
|
||||||
let (sighash, anyone_can_pay) = SigHashType::from_u32_consensus(sighash_type).split_anyonecanpay_flag();
|
let (sighash, anyone_can_pay) = EcdsaSigHashType::from_u32_consensus(sighash_type).split_anyonecanpay_flag();
|
||||||
|
|
||||||
// Special-case sighash_single bug because this is easy enough.
|
// Special-case sighash_single bug because this is easy enough.
|
||||||
if sighash == SigHashType::Single && input_index >= self.output.len() {
|
if sighash == EcdsaSigHashType::Single && input_index >= self.output.len() {
|
||||||
writer.write_all(&[1, 0, 0, 0, 0, 0, 0, 0,
|
writer.write_all(&[1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -365,22 +365,22 @@ impl Transaction {
|
||||||
tx.input.push(TxIn {
|
tx.input.push(TxIn {
|
||||||
previous_output: input.previous_output,
|
previous_output: input.previous_output,
|
||||||
script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() },
|
script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() },
|
||||||
sequence: if n != input_index && (sighash == SigHashType::Single || sighash == SigHashType::None) { 0 } else { input.sequence },
|
sequence: if n != input_index && (sighash == EcdsaSigHashType::Single || sighash == EcdsaSigHashType::None) { 0 } else { input.sequence },
|
||||||
witness: vec![],
|
witness: vec![],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ..then all outputs
|
// ..then all outputs
|
||||||
tx.output = match sighash {
|
tx.output = match sighash {
|
||||||
SigHashType::All => self.output.clone(),
|
EcdsaSigHashType::All => self.output.clone(),
|
||||||
SigHashType::Single => {
|
EcdsaSigHashType::Single => {
|
||||||
let output_iter = self.output.iter()
|
let output_iter = self.output.iter()
|
||||||
.take(input_index + 1) // sign all outputs up to and including this one, but erase
|
.take(input_index + 1) // sign all outputs up to and including this one, but erase
|
||||||
.enumerate() // all of them except for this one
|
.enumerate() // all of them except for this one
|
||||||
.map(|(n, out)| if n == input_index { out.clone() } else { TxOut::default() });
|
.map(|(n, out)| if n == input_index { out.clone() } else { TxOut::default() });
|
||||||
output_iter.collect()
|
output_iter.collect()
|
||||||
}
|
}
|
||||||
SigHashType::None => vec![],
|
EcdsaSigHashType::None => vec![],
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
// hash the result
|
// hash the result
|
||||||
|
@ -673,10 +673,15 @@ impl fmt::Display for NonStandardSigHashType {
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl error::Error for NonStandardSigHashType {}
|
impl error::Error for NonStandardSigHashType {}
|
||||||
|
|
||||||
|
/// Legacy Hashtype of an input's signature
|
||||||
|
#[deprecated(since="0.28.0", note="Please use [`EcdsaSigHashType`] instead")]
|
||||||
|
pub type SigHashType = EcdsaSigHashType;
|
||||||
|
|
||||||
/// Hashtype of an input's signature, encoded in the last byte of the signature
|
/// Hashtype of an input's signature, encoded in the last byte of the signature
|
||||||
/// Fixed values so they can be casted as integer types for encoding
|
/// Fixed values so they can be casted as integer types for encoding
|
||||||
|
/// See also [`crate::SchnorrSigHashType`]
|
||||||
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
||||||
pub enum SigHashType {
|
pub enum EcdsaSigHashType {
|
||||||
/// 0x1: Sign all outputs
|
/// 0x1: Sign all outputs
|
||||||
All = 0x01,
|
All = 0x01,
|
||||||
/// 0x2: Sign no outputs --- anyone can choose the destination
|
/// 0x2: Sign no outputs --- anyone can choose the destination
|
||||||
|
@ -693,54 +698,54 @@ pub enum SigHashType {
|
||||||
/// 0x83: Sign one output and only this input (see `Single` for what "one output" means)
|
/// 0x83: Sign one output and only this input (see `Single` for what "one output" means)
|
||||||
SinglePlusAnyoneCanPay = 0x83
|
SinglePlusAnyoneCanPay = 0x83
|
||||||
}
|
}
|
||||||
serde_string_impl!(SigHashType, "a SigHashType data");
|
serde_string_impl!(EcdsaSigHashType, "a EcdsaSigHashType data");
|
||||||
|
|
||||||
impl fmt::Display for SigHashType {
|
impl fmt::Display for EcdsaSigHashType {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let s = match self {
|
let s = match self {
|
||||||
SigHashType::All => "SIGHASH_ALL",
|
EcdsaSigHashType::All => "SIGHASH_ALL",
|
||||||
SigHashType::None => "SIGHASH_NONE",
|
EcdsaSigHashType::None => "SIGHASH_NONE",
|
||||||
SigHashType::Single => "SIGHASH_SINGLE",
|
EcdsaSigHashType::Single => "SIGHASH_SINGLE",
|
||||||
SigHashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY",
|
EcdsaSigHashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY",
|
||||||
SigHashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY",
|
EcdsaSigHashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY",
|
||||||
SigHashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY",
|
EcdsaSigHashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY",
|
||||||
};
|
};
|
||||||
f.write_str(s)
|
f.write_str(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl str::FromStr for SigHashType {
|
impl str::FromStr for EcdsaSigHashType {
|
||||||
type Err = String;
|
type Err = String;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s.as_ref() {
|
match s.as_ref() {
|
||||||
"SIGHASH_ALL" => Ok(SigHashType::All),
|
"SIGHASH_ALL" => Ok(EcdsaSigHashType::All),
|
||||||
"SIGHASH_NONE" => Ok(SigHashType::None),
|
"SIGHASH_NONE" => Ok(EcdsaSigHashType::None),
|
||||||
"SIGHASH_SINGLE" => Ok(SigHashType::Single),
|
"SIGHASH_SINGLE" => Ok(EcdsaSigHashType::Single),
|
||||||
"SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(SigHashType::AllPlusAnyoneCanPay),
|
"SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(EcdsaSigHashType::AllPlusAnyoneCanPay),
|
||||||
"SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(SigHashType::NonePlusAnyoneCanPay),
|
"SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSigHashType::NonePlusAnyoneCanPay),
|
||||||
"SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SigHashType::SinglePlusAnyoneCanPay),
|
"SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSigHashType::SinglePlusAnyoneCanPay),
|
||||||
_ => Err("can't recognize SIGHASH string".to_string())
|
_ => Err("can't recognize SIGHASH string".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SigHashType {
|
impl EcdsaSigHashType {
|
||||||
/// Break the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean
|
/// Break the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean
|
||||||
pub(crate) fn split_anyonecanpay_flag(self) -> (SigHashType, bool) {
|
pub(crate) fn split_anyonecanpay_flag(self) -> (EcdsaSigHashType, bool) {
|
||||||
match self {
|
match self {
|
||||||
SigHashType::All => (SigHashType::All, false),
|
EcdsaSigHashType::All => (EcdsaSigHashType::All, false),
|
||||||
SigHashType::None => (SigHashType::None, false),
|
EcdsaSigHashType::None => (EcdsaSigHashType::None, false),
|
||||||
SigHashType::Single => (SigHashType::Single, false),
|
EcdsaSigHashType::Single => (EcdsaSigHashType::Single, false),
|
||||||
SigHashType::AllPlusAnyoneCanPay => (SigHashType::All, true),
|
EcdsaSigHashType::AllPlusAnyoneCanPay => (EcdsaSigHashType::All, true),
|
||||||
SigHashType::NonePlusAnyoneCanPay => (SigHashType::None, true),
|
EcdsaSigHashType::NonePlusAnyoneCanPay => (EcdsaSigHashType::None, true),
|
||||||
SigHashType::SinglePlusAnyoneCanPay => (SigHashType::Single, true)
|
EcdsaSigHashType::SinglePlusAnyoneCanPay => (EcdsaSigHashType::Single, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a 4-byte uint32 as a sighash type.
|
/// Reads a 4-byte uint32 as a sighash type.
|
||||||
#[deprecated(since="0.26.1", note="please use `from_u32_consensus` or `from_u32_standard` instead")]
|
#[deprecated(since="0.26.1", note="please use `from_u32_consensus` or `from_u32_standard` instead")]
|
||||||
pub fn from_u32(n: u32) -> SigHashType {
|
pub fn from_u32(n: u32) -> EcdsaSigHashType {
|
||||||
Self::from_u32_consensus(n)
|
Self::from_u32_consensus(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,7 +753,7 @@ impl SigHashType {
|
||||||
///
|
///
|
||||||
/// **Note**: this replicates consensus behaviour, for current standardness rules correctness
|
/// **Note**: this replicates consensus behaviour, for current standardness rules correctness
|
||||||
/// you probably want [Self::from_u32_standard].
|
/// you probably want [Self::from_u32_standard].
|
||||||
pub fn from_u32_consensus(n: u32) -> SigHashType {
|
pub fn from_u32_consensus(n: u32) -> EcdsaSigHashType {
|
||||||
// In Bitcoin Core, the SignatureHash function will mask the (int32) value with
|
// In Bitcoin Core, the SignatureHash function will mask the (int32) value with
|
||||||
// 0x1f to (apparently) deactivate ACP when checking for SINGLE and NONE bits.
|
// 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.
|
// We however want to be matching also against on ACP-masked ALL, SINGLE, and NONE.
|
||||||
|
@ -756,29 +761,29 @@ impl SigHashType {
|
||||||
let mask = 0x1f | 0x80;
|
let mask = 0x1f | 0x80;
|
||||||
match n & mask {
|
match n & mask {
|
||||||
// "real" sighashes
|
// "real" sighashes
|
||||||
0x01 => SigHashType::All,
|
0x01 => EcdsaSigHashType::All,
|
||||||
0x02 => SigHashType::None,
|
0x02 => EcdsaSigHashType::None,
|
||||||
0x03 => SigHashType::Single,
|
0x03 => EcdsaSigHashType::Single,
|
||||||
0x81 => SigHashType::AllPlusAnyoneCanPay,
|
0x81 => EcdsaSigHashType::AllPlusAnyoneCanPay,
|
||||||
0x82 => SigHashType::NonePlusAnyoneCanPay,
|
0x82 => EcdsaSigHashType::NonePlusAnyoneCanPay,
|
||||||
0x83 => SigHashType::SinglePlusAnyoneCanPay,
|
0x83 => EcdsaSigHashType::SinglePlusAnyoneCanPay,
|
||||||
// catchalls
|
// catchalls
|
||||||
x if x & 0x80 == 0x80 => SigHashType::AllPlusAnyoneCanPay,
|
x if x & 0x80 == 0x80 => EcdsaSigHashType::AllPlusAnyoneCanPay,
|
||||||
_ => SigHashType::All
|
_ => EcdsaSigHashType::All
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a 4-byte uint32 as a standard sighash type, returning an error if the type
|
/// Read a 4-byte uint32 as a standard sighash type, returning an error if the type
|
||||||
/// is non standard.
|
/// is non standard.
|
||||||
pub fn from_u32_standard(n: u32) -> Result<SigHashType, NonStandardSigHashType> {
|
pub fn from_u32_standard(n: u32) -> Result<EcdsaSigHashType, NonStandardSigHashType> {
|
||||||
match n {
|
match n {
|
||||||
// Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198
|
// Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198
|
||||||
0x01 => Ok(SigHashType::All),
|
0x01 => Ok(EcdsaSigHashType::All),
|
||||||
0x02 => Ok(SigHashType::None),
|
0x02 => Ok(EcdsaSigHashType::None),
|
||||||
0x03 => Ok(SigHashType::Single),
|
0x03 => Ok(EcdsaSigHashType::Single),
|
||||||
0x81 => Ok(SigHashType::AllPlusAnyoneCanPay),
|
0x81 => Ok(EcdsaSigHashType::AllPlusAnyoneCanPay),
|
||||||
0x82 => Ok(SigHashType::NonePlusAnyoneCanPay),
|
0x82 => Ok(EcdsaSigHashType::NonePlusAnyoneCanPay),
|
||||||
0x83 => Ok(SigHashType::SinglePlusAnyoneCanPay),
|
0x83 => Ok(EcdsaSigHashType::SinglePlusAnyoneCanPay),
|
||||||
_ => Err(NonStandardSigHashType)
|
_ => Err(NonStandardSigHashType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -787,8 +792,8 @@ impl SigHashType {
|
||||||
pub fn as_u32(self) -> u32 { self as u32 }
|
pub fn as_u32(self) -> u32 { self as u32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SigHashType> for u32 {
|
impl From<EcdsaSigHashType> for u32 {
|
||||||
fn from(t: SigHashType) -> u32 {
|
fn from(t: EcdsaSigHashType) -> u32 {
|
||||||
t.as_u32()
|
t.as_u32()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,7 +812,7 @@ mod tests {
|
||||||
use hashes::hex::FromHex;
|
use hashes::hex::FromHex;
|
||||||
|
|
||||||
use hash_types::*;
|
use hash_types::*;
|
||||||
use SigHashType;
|
use super::EcdsaSigHashType;
|
||||||
use util::sighash::SigHashCache;
|
use util::sighash::SigHashCache;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1088,15 +1093,15 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sighashtype_fromstr_display() {
|
fn test_sighashtype_fromstr_display() {
|
||||||
let sighashtypes = vec![("SIGHASH_ALL", SigHashType::All),
|
let sighashtypes = vec![("SIGHASH_ALL", EcdsaSigHashType::All),
|
||||||
("SIGHASH_NONE", SigHashType::None),
|
("SIGHASH_NONE", EcdsaSigHashType::None),
|
||||||
("SIGHASH_SINGLE", SigHashType::Single),
|
("SIGHASH_SINGLE", EcdsaSigHashType::Single),
|
||||||
("SIGHASH_ALL|SIGHASH_ANYONECANPAY", SigHashType::AllPlusAnyoneCanPay),
|
("SIGHASH_ALL|SIGHASH_ANYONECANPAY", EcdsaSigHashType::AllPlusAnyoneCanPay),
|
||||||
("SIGHASH_NONE|SIGHASH_ANYONECANPAY", SigHashType::NonePlusAnyoneCanPay),
|
("SIGHASH_NONE|SIGHASH_ANYONECANPAY", EcdsaSigHashType::NonePlusAnyoneCanPay),
|
||||||
("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", SigHashType::SinglePlusAnyoneCanPay)];
|
("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", EcdsaSigHashType::SinglePlusAnyoneCanPay)];
|
||||||
for (s, sht) in sighashtypes {
|
for (s, sht) in sighashtypes {
|
||||||
assert_eq!(sht.to_string(), s);
|
assert_eq!(sht.to_string(), s);
|
||||||
assert_eq!(SigHashType::from_str(s).unwrap(), sht);
|
assert_eq!(EcdsaSigHashType::from_str(s).unwrap(), sht);
|
||||||
}
|
}
|
||||||
let sht_mistakes = vec![
|
let sht_mistakes = vec![
|
||||||
"SIGHASH_ALL | SIGHASH_ANYONECANPAY",
|
"SIGHASH_ALL | SIGHASH_ANYONECANPAY",
|
||||||
|
@ -1111,7 +1116,7 @@ mod tests {
|
||||||
"SigHash_NONE",
|
"SigHash_NONE",
|
||||||
];
|
];
|
||||||
for s in sht_mistakes {
|
for s in sht_mistakes {
|
||||||
assert_eq!(SigHashType::from_str(s).unwrap_err(), "can't recognize SIGHASH string");
|
assert_eq!(EcdsaSigHashType::from_str(s).unwrap_err(), "can't recognize SIGHASH string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1120,10 +1125,10 @@ mod tests {
|
||||||
fn test_sighashtype_standard() {
|
fn test_sighashtype_standard() {
|
||||||
let nonstandard_hashtype = 0x04;
|
let nonstandard_hashtype = 0x04;
|
||||||
// This type is not well defined, by consensus it becomes ALL
|
// This type is not well defined, by consensus it becomes ALL
|
||||||
assert_eq!(SigHashType::from_u32(nonstandard_hashtype), SigHashType::All);
|
assert_eq!(EcdsaSigHashType::from_u32(nonstandard_hashtype), EcdsaSigHashType::All);
|
||||||
assert_eq!(SigHashType::from_u32_consensus(nonstandard_hashtype), SigHashType::All);
|
assert_eq!(EcdsaSigHashType::from_u32_consensus(nonstandard_hashtype), EcdsaSigHashType::All);
|
||||||
// But it's policy-invalid to use it!
|
// But it's policy-invalid to use it!
|
||||||
assert_eq!(SigHashType::from_u32_standard(nonstandard_hashtype), Err(NonStandardSigHashType));
|
assert_eq!(EcdsaSigHashType::from_u32_standard(nonstandard_hashtype), Err(NonStandardSigHashType));
|
||||||
}
|
}
|
||||||
|
|
||||||
// These test vectors were stolen from libbtc, which is Copyright 2014 Jonas Schnelli MIT
|
// These test vectors were stolen from libbtc, which is Copyright 2014 Jonas Schnelli MIT
|
||||||
|
|
|
@ -123,7 +123,7 @@ pub use blockdata::transaction::Transaction;
|
||||||
pub use blockdata::transaction::TxIn;
|
pub use blockdata::transaction::TxIn;
|
||||||
pub use blockdata::transaction::TxOut;
|
pub use blockdata::transaction::TxOut;
|
||||||
pub use blockdata::transaction::OutPoint;
|
pub use blockdata::transaction::OutPoint;
|
||||||
pub use blockdata::transaction::SigHashType;
|
pub use blockdata::transaction::EcdsaSigHashType;
|
||||||
pub use consensus::encode::VarInt;
|
pub use consensus::encode::VarInt;
|
||||||
pub use network::constants::Network;
|
pub use network::constants::Network;
|
||||||
pub use util::Error;
|
pub use util::Error;
|
||||||
|
@ -133,9 +133,10 @@ pub use util::amount::Amount;
|
||||||
pub use util::amount::Denomination;
|
pub use util::amount::Denomination;
|
||||||
pub use util::amount::SignedAmount;
|
pub use util::amount::SignedAmount;
|
||||||
pub use util::merkleblock::MerkleBlock;
|
pub use util::merkleblock::MerkleBlock;
|
||||||
|
pub use util::sighash::SchnorrSigHashType;
|
||||||
|
|
||||||
pub use util::ecdsa;
|
pub use util::ecdsa::{self, EcdsaSig, EcdsaSigError};
|
||||||
pub use util::schnorr;
|
pub use util::schnorr::{self, SchnorrSig, SchnorrSigError};
|
||||||
#[deprecated(since = "0.26.1", note = "Please use `ecdsa::PrivateKey` instead")]
|
#[deprecated(since = "0.26.1", note = "Please use `ecdsa::PrivateKey` instead")]
|
||||||
pub use util::ecdsa::PrivateKey;
|
pub use util::ecdsa::PrivateKey;
|
||||||
#[deprecated(since = "0.26.1", note = "Please use `ecdsa::PublicKey` instead")]
|
#[deprecated(since = "0.26.1", note = "Please use `ecdsa::PublicKey` instead")]
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
use hashes::Hash;
|
use hashes::Hash;
|
||||||
use hash_types::SigHash;
|
use hash_types::SigHash;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{Transaction, TxIn, SigHashType};
|
use blockdata::transaction::{Transaction, TxIn, EcdsaSigHashType};
|
||||||
use consensus::{encode, Encodable};
|
use consensus::{encode, Encodable};
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
@ -131,7 +131,7 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
value: u64,
|
value: u64,
|
||||||
sighash_type: SigHashType,
|
sighash_type: EcdsaSigHashType,
|
||||||
) -> Result<(), encode::Error> {
|
) -> Result<(), encode::Error> {
|
||||||
self.cache
|
self.cache
|
||||||
.segwit_encode_signing_data_to(writer, input_index, script_code, value, sighash_type.into())
|
.segwit_encode_signing_data_to(writer, input_index, script_code, value, sighash_type.into())
|
||||||
|
@ -146,7 +146,7 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
value: u64,
|
value: u64,
|
||||||
sighash_type: SigHashType
|
sighash_type: EcdsaSigHashType
|
||||||
) -> SigHash {
|
) -> SigHash {
|
||||||
let mut enc = SigHash::engine();
|
let mut enc = SigHash::engine();
|
||||||
self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type)
|
self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type)
|
||||||
|
@ -165,7 +165,7 @@ impl<R: DerefMut<Target=Transaction>> SigHashCache<R> {
|
||||||
/// panics if `input_index` is out of bounds with respect of the number of inputs
|
/// panics if `input_index` is out of bounds with respect of the number of inputs
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use bitcoin::blockdata::transaction::{Transaction, SigHashType};
|
/// use bitcoin::blockdata::transaction::{Transaction, EcdsaSigHashType};
|
||||||
/// use bitcoin::util::bip143::SigHashCache;
|
/// use bitcoin::util::bip143::SigHashCache;
|
||||||
/// use bitcoin::Script;
|
/// use bitcoin::Script;
|
||||||
///
|
///
|
||||||
|
@ -175,7 +175,7 @@ impl<R: DerefMut<Target=Transaction>> SigHashCache<R> {
|
||||||
/// let mut sig_hasher = SigHashCache::new(&mut tx_to_sign);
|
/// let mut sig_hasher = SigHashCache::new(&mut tx_to_sign);
|
||||||
/// for inp in 0..input_count {
|
/// for inp in 0..input_count {
|
||||||
/// let prevout_script = Script::new();
|
/// let prevout_script = Script::new();
|
||||||
/// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, 42, SigHashType::All);
|
/// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, 42, EcdsaSigHashType::All);
|
||||||
/// // ... sign the sighash
|
/// // ... sign the sighash
|
||||||
/// sig_hasher.access_witness(inp).push(Vec::new());
|
/// sig_hasher.access_witness(inp).push(Vec::new());
|
||||||
/// }
|
/// }
|
||||||
|
@ -212,7 +212,7 @@ mod tests {
|
||||||
let raw_expected = SigHash::from_hex(expected_result).unwrap();
|
let raw_expected = SigHash::from_hex(expected_result).unwrap();
|
||||||
let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap();
|
let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap();
|
||||||
let mut cache = SigHashCache::new(&tx);
|
let mut cache = SigHashCache::new(&tx);
|
||||||
let sighash_type = SigHashType::from_u32_consensus(hash_type);
|
let sighash_type = EcdsaSigHashType::from_u32_consensus(hash_type);
|
||||||
let actual_result = cache.signature_hash(input_index, &script, value, sighash_type);
|
let actual_result = cache.signature_hash(input_index, &script, value, sighash_type);
|
||||||
assert_eq!(actual_result, expected_result);
|
assert_eq!(actual_result, expected_result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ use hashes::{Hash, hash160};
|
||||||
use hash_types::{PubkeyHash, WPubkeyHash};
|
use hash_types::{PubkeyHash, WPubkeyHash};
|
||||||
use util::base58;
|
use util::base58;
|
||||||
use util::key::Error;
|
use util::key::Error;
|
||||||
|
use blockdata::transaction::EcdsaSigHashType;
|
||||||
|
|
||||||
|
|
||||||
/// A Bitcoin ECDSA public key
|
/// A Bitcoin ECDSA public key
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -413,6 +415,72 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An ECDSA signature with the corresponding hash type.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub struct EcdsaSig {
|
||||||
|
/// The underlying ECDSA Signature
|
||||||
|
pub sig: secp256k1::Signature,
|
||||||
|
/// The corresponding hash type
|
||||||
|
pub hash_ty: EcdsaSigHashType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EcdsaSig {
|
||||||
|
|
||||||
|
/// Deserialize from slice
|
||||||
|
pub fn from_slice(sl: &[u8]) -> Result<Self, EcdsaSigError> {
|
||||||
|
let (hash_ty, sig) = sl.split_last()
|
||||||
|
.ok_or(EcdsaSigError::EmptySignature)?;
|
||||||
|
let hash_ty = EcdsaSigHashType::from_u32_standard(*hash_ty as u32)
|
||||||
|
.map_err(|_| EcdsaSigError::NonStandardSigHashType(*hash_ty))?;
|
||||||
|
let sig = secp256k1::Signature::from_der(sig)
|
||||||
|
.map_err(EcdsaSigError::Secp256k1)?;
|
||||||
|
Ok(EcdsaSig { sig, hash_ty })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize EcdsaSig
|
||||||
|
pub fn to_vec(&self) -> Vec<u8> {
|
||||||
|
// TODO: add support to serialize to a writer to SerializedSig
|
||||||
|
let mut ser_sig = self.sig.serialize_der().to_vec();
|
||||||
|
ser_sig.push(self.hash_ty.as_u32() as u8);
|
||||||
|
ser_sig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A key-related error.
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
pub enum EcdsaSigError {
|
||||||
|
/// Base58 encoding error
|
||||||
|
NonStandardSigHashType(u8),
|
||||||
|
/// Empty Signature
|
||||||
|
EmptySignature,
|
||||||
|
/// secp256k1-related error
|
||||||
|
Secp256k1(secp256k1::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl fmt::Display for EcdsaSigError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
EcdsaSigError::NonStandardSigHashType(hash_ty) =>
|
||||||
|
write!(f, "Non standard signature hash type {}", hash_ty),
|
||||||
|
EcdsaSigError::Secp256k1(ref e) =>
|
||||||
|
write!(f, "Invalid Ecdsa signature: {}", e),
|
||||||
|
EcdsaSigError::EmptySignature =>
|
||||||
|
write!(f, "Empty ECDSA signature"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
impl ::std::error::Error for EcdsaSigError {}
|
||||||
|
|
||||||
|
impl From<secp256k1::Error> for EcdsaSigError {
|
||||||
|
fn from(e: secp256k1::Error) -> EcdsaSigError {
|
||||||
|
EcdsaSigError::Secp256k1(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use io;
|
use io;
|
||||||
|
|
|
@ -17,7 +17,7 @@ use prelude::*;
|
||||||
use io;
|
use io;
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{SigHashType, Transaction, TxOut};
|
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
use util::bip32::KeySource;
|
use util::bip32::KeySource;
|
||||||
use hashes::{self, hash160, ripemd160, sha256, sha256d};
|
use hashes::{self, hash160, ripemd160, sha256, sha256d};
|
||||||
|
@ -76,7 +76,7 @@ pub struct Input {
|
||||||
pub partial_sigs: BTreeMap<PublicKey, Vec<u8>>,
|
pub partial_sigs: BTreeMap<PublicKey, Vec<u8>>,
|
||||||
/// The sighash type to be used for this input. Signatures for this input
|
/// The sighash type to be used for this input. Signatures for this input
|
||||||
/// must use the sighash type.
|
/// must use the sighash type.
|
||||||
pub sighash_type: Option<SigHashType>,
|
pub sighash_type: Option<EcdsaSigHashType>,
|
||||||
/// The redeem script for this input.
|
/// The redeem script for this input.
|
||||||
pub redeem_script: Option<Script>,
|
pub redeem_script: Option<Script>,
|
||||||
/// The witness script for this input.
|
/// The witness script for this input.
|
||||||
|
@ -137,7 +137,7 @@ impl Map for Input {
|
||||||
}
|
}
|
||||||
PSBT_IN_SIGHASH_TYPE => {
|
PSBT_IN_SIGHASH_TYPE => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.sighash_type <= <raw_key: _>|<raw_value: SigHashType>
|
self.sighash_type <= <raw_key: _>|<raw_value: EcdsaSigHashType>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_REDEEM_SCRIPT => {
|
PSBT_IN_REDEEM_SCRIPT => {
|
||||||
|
|
|
@ -507,7 +507,7 @@ mod tests {
|
||||||
use hash_types::Txid;
|
use hash_types::Txid;
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{SigHashType, Transaction, TxIn, TxOut, OutPoint};
|
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxIn, TxOut, OutPoint};
|
||||||
use consensus::encode::serialize_hex;
|
use consensus::encode::serialize_hex;
|
||||||
use util::psbt::map::{Map, Input, Output};
|
use util::psbt::map::{Map, Input, Output};
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
|
@ -733,7 +733,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(&psbt.inputs[0].sighash_type).as_ref().unwrap(),
|
(&psbt.inputs[0].sighash_type).as_ref().unwrap(),
|
||||||
&SigHashType::All
|
&EcdsaSigHashType::All
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ use prelude::*;
|
||||||
use io;
|
use io;
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{SigHashType, Transaction, TxOut};
|
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
||||||
use consensus::encode::{self, serialize, Decodable};
|
use consensus::encode::{self, serialize, Decodable};
|
||||||
use util::bip32::{ChildNumber, Fingerprint, KeySource};
|
use util::bip32::{ChildNumber, Fingerprint, KeySource};
|
||||||
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
||||||
|
@ -126,16 +126,16 @@ impl Deserialize for Vec<u8> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for SigHashType {
|
impl Serialize for EcdsaSigHashType {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
serialize(&self.as_u32())
|
serialize(&self.as_u32())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for SigHashType {
|
impl Deserialize for EcdsaSigHashType {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
||||||
let raw: u32 = encode::deserialize(bytes)?;
|
let raw: u32 = encode::deserialize(bytes)?;
|
||||||
let rv: SigHashType = SigHashType::from_u32_consensus(raw);
|
let rv: EcdsaSigHashType = EcdsaSigHashType::from_u32_consensus(raw);
|
||||||
|
|
||||||
if rv.as_u32() == raw {
|
if rv.as_u32() == raw {
|
||||||
Ok(rv)
|
Ok(rv)
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
//! Schnorr key types.
|
//! Schnorr key types.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
pub use secp256k1::schnorrsig::{PublicKey, KeyPair};
|
pub use secp256k1::schnorrsig::{PublicKey, KeyPair};
|
||||||
use secp256k1::{Secp256k1, Verification, constants};
|
use secp256k1::{self, Secp256k1, Verification, constants};
|
||||||
use hashes::Hash;
|
use hashes::Hash;
|
||||||
use util::taproot::{TapBranchHash, TapTweakHash};
|
use util::taproot::{TapBranchHash, TapTweakHash};
|
||||||
use core::fmt;
|
use SchnorrSigHashType;
|
||||||
|
|
||||||
/// Untweaked Schnorr public key
|
/// Untweaked Schnorr public key
|
||||||
pub type UntweakedPublicKey = PublicKey;
|
pub type UntweakedPublicKey = PublicKey;
|
||||||
|
@ -104,3 +107,87 @@ impl TweakedPublicKey {
|
||||||
self.0.serialize()
|
self.0.serialize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A BIP340-341 serialized schnorr signature with the corresponding hash type.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct SchnorrSig {
|
||||||
|
/// The underlying schnorr signature
|
||||||
|
pub sig: secp256k1::schnorrsig::Signature,
|
||||||
|
/// The corresponding hash type
|
||||||
|
pub hash_ty: SchnorrSigHashType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SchnorrSig {
|
||||||
|
|
||||||
|
/// Deserialize from slice
|
||||||
|
pub fn from_slice(sl: &[u8]) -> Result<Self, SchnorrSigError> {
|
||||||
|
match sl.len() {
|
||||||
|
64 => {
|
||||||
|
// default type
|
||||||
|
let sig = secp256k1::schnorrsig::Signature::from_slice(sl)
|
||||||
|
.map_err(SchnorrSigError::Secp256k1)?;
|
||||||
|
return Ok( SchnorrSig { sig, hash_ty : SchnorrSigHashType::Default });
|
||||||
|
},
|
||||||
|
65 => {
|
||||||
|
let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
|
||||||
|
let hash_ty = SchnorrSigHashType::from_u8(*hash_ty)
|
||||||
|
.map_err(|_| SchnorrSigError::InvalidSighashType(*hash_ty))?;
|
||||||
|
let sig = secp256k1::schnorrsig::Signature::from_slice(sig)
|
||||||
|
.map_err(SchnorrSigError::Secp256k1)?;
|
||||||
|
Ok(SchnorrSig { sig, hash_ty })
|
||||||
|
}
|
||||||
|
len => {
|
||||||
|
Err(SchnorrSigError::InvalidSchnorrSigSize(len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize SchnorrSig
|
||||||
|
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)]
|
||||||
|
pub enum SchnorrSigError {
|
||||||
|
/// Base58 encoding error
|
||||||
|
InvalidSighashType(u8),
|
||||||
|
/// Signature has valid size but does not parse correctly
|
||||||
|
Secp256k1(secp256k1::Error),
|
||||||
|
/// Invalid schnorr signature size
|
||||||
|
InvalidSchnorrSigSize(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl fmt::Display for SchnorrSigError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
SchnorrSigError::InvalidSighashType(hash_ty) =>
|
||||||
|
write!(f, "Invalid signature hash type {}", hash_ty),
|
||||||
|
SchnorrSigError::Secp256k1(ref e) =>
|
||||||
|
write!(f, "Schnorr Signature has correct len, but is malformed : {}", e),
|
||||||
|
SchnorrSigError::InvalidSchnorrSigSize(sz) =>
|
||||||
|
write!(f, "Invalid Schnorr signature size: {}", sz),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
impl ::std::error::Error for SchnorrSigError {}
|
||||||
|
|
||||||
|
impl From<secp256k1::Error> for SchnorrSigError {
|
||||||
|
|
||||||
|
fn from(e: secp256k1::Error) -> SchnorrSigError {
|
||||||
|
SchnorrSigError::Secp256k1(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
//! and legacy (before Bip143).
|
//! and legacy (before Bip143).
|
||||||
//!
|
//!
|
||||||
|
|
||||||
pub use blockdata::transaction::SigHashType as LegacySigHashType;
|
pub use blockdata::transaction::EcdsaSigHashType;
|
||||||
use consensus::{encode, Encodable};
|
use consensus::{encode, Encodable};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
@ -79,7 +79,7 @@ struct TaprootCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains outputs of previous transactions.
|
/// Contains outputs of previous transactions.
|
||||||
/// In the case [`SigHashType`] variant is `ANYONECANPAY`, [`Prevouts::One`] may be provided
|
/// In the case [`SchnorrSigHashType`] variant is `ANYONECANPAY`, [`Prevouts::One`] may be provided
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
pub enum Prevouts<'u> {
|
pub enum Prevouts<'u> {
|
||||||
/// `One` variant allows to provide the single Prevout needed. It's useful for example
|
/// `One` variant allows to provide the single Prevout needed. It's useful for example
|
||||||
|
@ -104,8 +104,8 @@ pub struct ScriptPath<'s> {
|
||||||
/// Hashtype of an input's signature, encoded in the last byte of the signature
|
/// Hashtype of an input's signature, encoded in the last byte of the signature
|
||||||
/// Fixed values so they can be casted as integer types for encoding
|
/// Fixed values so they can be casted as integer types for encoding
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
pub enum SigHashType {
|
pub enum SchnorrSigHashType {
|
||||||
/// 0x0: Used when not explicitly specified, defaulting to [`SigHashType::All`]
|
/// 0x0: Used when not explicitly specified, defaulting to [`SchnorrSigHashType::All`]
|
||||||
Default = 0x00,
|
Default = 0x00,
|
||||||
/// 0x1: Sign all outputs
|
/// 0x1: Sign all outputs
|
||||||
All = 0x01,
|
All = 0x01,
|
||||||
|
@ -164,6 +164,9 @@ pub enum Error {
|
||||||
|
|
||||||
/// Annex must be at least one byte long and the first bytes must be `0x50`
|
/// Annex must be at least one byte long and the first bytes must be `0x50`
|
||||||
WrongAnnex,
|
WrongAnnex,
|
||||||
|
|
||||||
|
/// Invalid Sighash type
|
||||||
|
InvalidSigHashType(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -176,6 +179,7 @@ impl fmt::Display for Error {
|
||||||
Error::PrevoutIndex => write!(f, "The index requested is greater than available prevouts or different from the provided [Provided::Anyone] index"),
|
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::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::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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,31 +233,45 @@ impl<'s> ScriptPath<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LegacySigHashType> for SigHashType {
|
impl From<EcdsaSigHashType> for SchnorrSigHashType {
|
||||||
fn from(s: LegacySigHashType) -> Self {
|
fn from(s: EcdsaSigHashType) -> Self {
|
||||||
match s {
|
match s {
|
||||||
LegacySigHashType::All => SigHashType::All,
|
EcdsaSigHashType::All => SchnorrSigHashType::All,
|
||||||
LegacySigHashType::None => SigHashType::None,
|
EcdsaSigHashType::None => SchnorrSigHashType::None,
|
||||||
LegacySigHashType::Single => SigHashType::Single,
|
EcdsaSigHashType::Single => SchnorrSigHashType::Single,
|
||||||
LegacySigHashType::AllPlusAnyoneCanPay => SigHashType::AllPlusAnyoneCanPay,
|
EcdsaSigHashType::AllPlusAnyoneCanPay => SchnorrSigHashType::AllPlusAnyoneCanPay,
|
||||||
LegacySigHashType::NonePlusAnyoneCanPay => SigHashType::NonePlusAnyoneCanPay,
|
EcdsaSigHashType::NonePlusAnyoneCanPay => SchnorrSigHashType::NonePlusAnyoneCanPay,
|
||||||
LegacySigHashType::SinglePlusAnyoneCanPay => SigHashType::SinglePlusAnyoneCanPay,
|
EcdsaSigHashType::SinglePlusAnyoneCanPay => SchnorrSigHashType::SinglePlusAnyoneCanPay,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SigHashType {
|
impl SchnorrSigHashType {
|
||||||
/// Break the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean
|
/// Break the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean
|
||||||
pub(crate) fn split_anyonecanpay_flag(self) -> (SigHashType, bool) {
|
pub(crate) fn split_anyonecanpay_flag(self) -> (SchnorrSigHashType, bool) {
|
||||||
match self {
|
match self {
|
||||||
SigHashType::Default => (SigHashType::Default, false),
|
SchnorrSigHashType::Default => (SchnorrSigHashType::Default, false),
|
||||||
SigHashType::All => (SigHashType::All, false),
|
SchnorrSigHashType::All => (SchnorrSigHashType::All, false),
|
||||||
SigHashType::None => (SigHashType::None, false),
|
SchnorrSigHashType::None => (SchnorrSigHashType::None, false),
|
||||||
SigHashType::Single => (SigHashType::Single, false),
|
SchnorrSigHashType::Single => (SchnorrSigHashType::Single, false),
|
||||||
SigHashType::AllPlusAnyoneCanPay => (SigHashType::All, true),
|
SchnorrSigHashType::AllPlusAnyoneCanPay => (SchnorrSigHashType::All, true),
|
||||||
SigHashType::NonePlusAnyoneCanPay => (SigHashType::None, true),
|
SchnorrSigHashType::NonePlusAnyoneCanPay => (SchnorrSigHashType::None, true),
|
||||||
SigHashType::SinglePlusAnyoneCanPay => (SigHashType::Single, true),
|
SchnorrSigHashType::SinglePlusAnyoneCanPay => (SchnorrSigHashType::Single, true),
|
||||||
SigHashType::Reserved => (SigHashType::Reserved, false),
|
SchnorrSigHashType::Reserved => (SchnorrSigHashType::Reserved, false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a [`SchnorrSigHashType`] from raw u8
|
||||||
|
pub fn from_u8(hash_ty: u8) -> Result<Self, Error> {
|
||||||
|
match hash_ty {
|
||||||
|
0x00 => Ok(SchnorrSigHashType::Default),
|
||||||
|
0x01 => Ok(SchnorrSigHashType::All),
|
||||||
|
0x02 => Ok(SchnorrSigHashType::None),
|
||||||
|
0x03 => Ok(SchnorrSigHashType::Single),
|
||||||
|
0x81 => Ok(SchnorrSigHashType::AllPlusAnyoneCanPay),
|
||||||
|
0x82 => Ok(SchnorrSigHashType::NonePlusAnyoneCanPay),
|
||||||
|
0x83 => Ok(SchnorrSigHashType::SinglePlusAnyoneCanPay),
|
||||||
|
x => Err(Error::InvalidSigHashType(x)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,7 +299,7 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
prevouts: &Prevouts,
|
prevouts: &Prevouts,
|
||||||
annex: Option<Annex>,
|
annex: Option<Annex>,
|
||||||
script_path: Option<ScriptPath>,
|
script_path: Option<ScriptPath>,
|
||||||
sighash_type: SigHashType,
|
sighash_type: SchnorrSigHashType,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
prevouts.check_all(&self.tx)?;
|
prevouts.check_all(&self.tx)?;
|
||||||
|
|
||||||
|
@ -321,7 +339,7 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
|
|
||||||
// If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE:
|
// 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.
|
// sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format.
|
||||||
if sighash != SigHashType::None && sighash != SigHashType::Single {
|
if sighash != SchnorrSigHashType::None && sighash != SchnorrSigHashType::Single {
|
||||||
self.common_cache().outputs.consensus_encode(&mut writer)?;
|
self.common_cache().outputs.consensus_encode(&mut writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +394,7 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
// * Data about this output:
|
// * Data about this output:
|
||||||
// If hash_type & 3 equals SIGHASH_SINGLE:
|
// If hash_type & 3 equals SIGHASH_SINGLE:
|
||||||
// sha_single_output (32): the SHA256 of the corresponding output in CTxOut format.
|
// sha_single_output (32): the SHA256 of the corresponding output in CTxOut format.
|
||||||
if sighash == SigHashType::Single {
|
if sighash == SchnorrSigHashType::Single {
|
||||||
let mut enc = sha256::Hash::engine();
|
let mut enc = sha256::Hash::engine();
|
||||||
self.tx
|
self.tx
|
||||||
.output
|
.output
|
||||||
|
@ -420,7 +438,7 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
prevouts: &Prevouts,
|
prevouts: &Prevouts,
|
||||||
annex: Option<Annex>,
|
annex: Option<Annex>,
|
||||||
script_path: Option<ScriptPath>,
|
script_path: Option<ScriptPath>,
|
||||||
sighash_type: SigHashType,
|
sighash_type: SchnorrSigHashType,
|
||||||
) -> Result<TapSighashHash, Error> {
|
) -> Result<TapSighashHash, Error> {
|
||||||
let mut enc = TapSighashHash::engine();
|
let mut enc = TapSighashHash::engine();
|
||||||
self.taproot_encode_signing_data_to(
|
self.taproot_encode_signing_data_to(
|
||||||
|
@ -442,7 +460,7 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
value: u64,
|
value: u64,
|
||||||
sighash_type: LegacySigHashType,
|
sighash_type: EcdsaSigHashType,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let zero_hash = sha256d::Hash::default();
|
let zero_hash = sha256d::Hash::default();
|
||||||
|
|
||||||
|
@ -457,8 +475,8 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !anyone_can_pay
|
if !anyone_can_pay
|
||||||
&& sighash != LegacySigHashType::Single
|
&& sighash != EcdsaSigHashType::Single
|
||||||
&& sighash != LegacySigHashType::None
|
&& sighash != EcdsaSigHashType::None
|
||||||
{
|
{
|
||||||
self.segwit_cache()
|
self.segwit_cache()
|
||||||
.sequences
|
.sequences
|
||||||
|
@ -484,9 +502,9 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
txin.sequence.consensus_encode(&mut writer)?;
|
txin.sequence.consensus_encode(&mut writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if sighash != LegacySigHashType::Single && sighash != LegacySigHashType::None {
|
if sighash != EcdsaSigHashType::Single && sighash != EcdsaSigHashType::None {
|
||||||
self.segwit_cache().outputs.consensus_encode(&mut writer)?;
|
self.segwit_cache().outputs.consensus_encode(&mut writer)?;
|
||||||
} else if sighash == LegacySigHashType::Single && input_index < self.tx.output.len() {
|
} else if sighash == EcdsaSigHashType::Single && input_index < self.tx.output.len() {
|
||||||
let mut single_enc = SigHash::engine();
|
let mut single_enc = SigHash::engine();
|
||||||
self.tx.output[input_index].consensus_encode(&mut single_enc)?;
|
self.tx.output[input_index].consensus_encode(&mut single_enc)?;
|
||||||
SigHash::from_engine(single_enc).consensus_encode(&mut writer)?;
|
SigHash::from_engine(single_enc).consensus_encode(&mut writer)?;
|
||||||
|
@ -505,7 +523,7 @@ impl<R: Deref<Target = Transaction>> SigHashCache<R> {
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
script_code: &Script,
|
script_code: &Script,
|
||||||
value: u64,
|
value: u64,
|
||||||
sighash_type: LegacySigHashType,
|
sighash_type: EcdsaSigHashType,
|
||||||
) -> Result<SigHash, Error> {
|
) -> Result<SigHash, Error> {
|
||||||
let mut enc = SigHash::engine();
|
let mut enc = SigHash::engine();
|
||||||
self.segwit_encode_signing_data_to(
|
self.segwit_encode_signing_data_to(
|
||||||
|
@ -627,7 +645,7 @@ impl<R: DerefMut<Target = Transaction>> SigHashCache<R> {
|
||||||
///
|
///
|
||||||
/// This allows in-line signing such as
|
/// This allows in-line signing such as
|
||||||
/// ```
|
/// ```
|
||||||
/// use bitcoin::blockdata::transaction::{Transaction, SigHashType};
|
/// use bitcoin::blockdata::transaction::{Transaction, EcdsaSigHashType};
|
||||||
/// use bitcoin::util::sighash::SigHashCache;
|
/// use bitcoin::util::sighash::SigHashCache;
|
||||||
/// use bitcoin::Script;
|
/// use bitcoin::Script;
|
||||||
///
|
///
|
||||||
|
@ -637,7 +655,7 @@ impl<R: DerefMut<Target = Transaction>> SigHashCache<R> {
|
||||||
/// let mut sig_hasher = SigHashCache::new(&mut tx_to_sign);
|
/// let mut sig_hasher = SigHashCache::new(&mut tx_to_sign);
|
||||||
/// for inp in 0..input_count {
|
/// for inp in 0..input_count {
|
||||||
/// let prevout_script = Script::new();
|
/// let prevout_script = Script::new();
|
||||||
/// let _sighash = sig_hasher.segwit_signature_hash(inp, &prevout_script, 42, SigHashType::All);
|
/// let _sighash = sig_hasher.segwit_signature_hash(inp, &prevout_script, 42, EcdsaSigHashType::All);
|
||||||
/// // ... sign the sighash
|
/// // ... sign the sighash
|
||||||
/// sig_hasher.witness_mut(inp).unwrap().push(Vec::new());
|
/// sig_hasher.witness_mut(inp).unwrap().push(Vec::new());
|
||||||
/// }
|
/// }
|
||||||
|
@ -681,10 +699,11 @@ impl<'a> Encodable for Annex<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
use consensus::deserialize;
|
use consensus::deserialize;
|
||||||
use hashes::hex::FromHex;
|
use hashes::hex::FromHex;
|
||||||
use hashes::{Hash, HashEngine};
|
use hashes::{Hash, HashEngine};
|
||||||
use util::sighash::{Annex, Error, Prevouts, ScriptPath, SigHashCache, SigHashType};
|
use util::sighash::{Annex, Error, Prevouts, ScriptPath, SigHashCache};
|
||||||
use util::taproot::TapSighashHash;
|
use util::taproot::TapSighashHash;
|
||||||
use {Script, Transaction, TxIn, TxOut};
|
use {Script, Transaction, TxIn, TxOut};
|
||||||
|
|
||||||
|
@ -709,7 +728,7 @@ mod tests {
|
||||||
"01365724000000000023542156b39dab4f8f3508e0432cfb41fab110170acaa2d4c42539cb90a4dc7c093bc500",
|
"01365724000000000023542156b39dab4f8f3508e0432cfb41fab110170acaa2d4c42539cb90a4dc7c093bc500",
|
||||||
0,
|
0,
|
||||||
"33ca0ebfb4a945eeee9569fc0f5040221275f88690b7f8592ada88ce3bdf6703",
|
"33ca0ebfb4a945eeee9569fc0f5040221275f88690b7f8592ada88ce3bdf6703",
|
||||||
SigHashType::Default, None,None,
|
SchnorrSigHashType::Default, None,None,
|
||||||
);
|
);
|
||||||
|
|
||||||
test_taproot_sighash(
|
test_taproot_sighash(
|
||||||
|
@ -717,7 +736,7 @@ mod tests {
|
||||||
"02591f220000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece48fb310000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece",
|
"02591f220000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece48fb310000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece",
|
||||||
1,
|
1,
|
||||||
"626ab955d58c9a8a600a0c580549d06dc7da4e802eb2a531f62a588e430967a8",
|
"626ab955d58c9a8a600a0c580549d06dc7da4e802eb2a531f62a588e430967a8",
|
||||||
SigHashType::All, None,None,
|
SchnorrSigHashType::All, None,None,
|
||||||
);
|
);
|
||||||
|
|
||||||
test_taproot_sighash(
|
test_taproot_sighash(
|
||||||
|
@ -725,7 +744,7 @@ mod tests {
|
||||||
"01c4811000000000002251201bf9297d0a2968ae6693aadd0fa514717afefd218087a239afb7418e2d22e65c",
|
"01c4811000000000002251201bf9297d0a2968ae6693aadd0fa514717afefd218087a239afb7418e2d22e65c",
|
||||||
0,
|
0,
|
||||||
"dfa9437f9c9a1d1f9af271f79f2f5482f287cdb0d2e03fa92c8a9b216cc6061c",
|
"dfa9437f9c9a1d1f9af271f79f2f5482f287cdb0d2e03fa92c8a9b216cc6061c",
|
||||||
SigHashType::AllPlusAnyoneCanPay, None,None,
|
SchnorrSigHashType::AllPlusAnyoneCanPay, None,None,
|
||||||
);
|
);
|
||||||
|
|
||||||
test_taproot_sighash(
|
test_taproot_sighash(
|
||||||
|
@ -733,7 +752,7 @@ mod tests {
|
||||||
"0144c84d0000000000225120e3f2107989c88e67296ab2faca930efa2e3a5bd3ff0904835a11c9e807458621",
|
"0144c84d0000000000225120e3f2107989c88e67296ab2faca930efa2e3a5bd3ff0904835a11c9e807458621",
|
||||||
0,
|
0,
|
||||||
"3129de36a5d05fff97ffca31eb75fcccbbbc27b3147a7a36a9e4b45d8b625067",
|
"3129de36a5d05fff97ffca31eb75fcccbbbc27b3147a7a36a9e4b45d8b625067",
|
||||||
SigHashType::None, None,None,
|
SchnorrSigHashType::None, None,None,
|
||||||
);
|
);
|
||||||
|
|
||||||
test_taproot_sighash(
|
test_taproot_sighash(
|
||||||
|
@ -741,7 +760,7 @@ mod tests {
|
||||||
"013fed110000000000225120eb536ae8c33580290630fc495046e998086a64f8f33b93b07967d9029b265c55",
|
"013fed110000000000225120eb536ae8c33580290630fc495046e998086a64f8f33b93b07967d9029b265c55",
|
||||||
0,
|
0,
|
||||||
"2441e8b0e063a2083ee790f14f2045022f07258ddde5ee01de543c9e789d80ae",
|
"2441e8b0e063a2083ee790f14f2045022f07258ddde5ee01de543c9e789d80ae",
|
||||||
SigHashType::NonePlusAnyoneCanPay, None,None,
|
SchnorrSigHashType::NonePlusAnyoneCanPay, None,None,
|
||||||
);
|
);
|
||||||
|
|
||||||
test_taproot_sighash(
|
test_taproot_sighash(
|
||||||
|
@ -749,7 +768,7 @@ mod tests {
|
||||||
"01efa558000000000022512007071ea3dc7e331b0687d0193d1e6d6ed10e645ef36f10ef8831d5e522ac9e80",
|
"01efa558000000000022512007071ea3dc7e331b0687d0193d1e6d6ed10e645ef36f10ef8831d5e522ac9e80",
|
||||||
0,
|
0,
|
||||||
"30239345177cadd0e3ea413d49803580abb6cb27971b481b7788a78d35117a88",
|
"30239345177cadd0e3ea413d49803580abb6cb27971b481b7788a78d35117a88",
|
||||||
SigHashType::Single, None,None,
|
SchnorrSigHashType::Single, None,None,
|
||||||
);
|
);
|
||||||
|
|
||||||
test_taproot_sighash(
|
test_taproot_sighash(
|
||||||
|
@ -757,7 +776,7 @@ mod tests {
|
||||||
"0107af4e00000000002251202c36d243dfc06cb56a248e62df27ecba7417307511a81ae61aa41c597a929c69",
|
"0107af4e00000000002251202c36d243dfc06cb56a248e62df27ecba7417307511a81ae61aa41c597a929c69",
|
||||||
0,
|
0,
|
||||||
"bf9c83f26c6dd16449e4921f813f551c4218e86f2ec906ca8611175b41b566df",
|
"bf9c83f26c6dd16449e4921f813f551c4218e86f2ec906ca8611175b41b566df",
|
||||||
SigHashType::SinglePlusAnyoneCanPay, None,None,
|
SchnorrSigHashType::SinglePlusAnyoneCanPay, None,None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,7 +787,7 @@ mod tests {
|
||||||
"01ea49260000000000225120ab5e9800806bf18cb246edcf5fe63441208fe955a4b5a35bbff65f5db622a010",
|
"01ea49260000000000225120ab5e9800806bf18cb246edcf5fe63441208fe955a4b5a35bbff65f5db622a010",
|
||||||
0,
|
0,
|
||||||
"3b003000add359a364a156e73e02846782a59d0d95ca8c4638aaad99f2ef915c",
|
"3b003000add359a364a156e73e02846782a59d0d95ca8c4638aaad99f2ef915c",
|
||||||
SigHashType::SinglePlusAnyoneCanPay,
|
SchnorrSigHashType::SinglePlusAnyoneCanPay,
|
||||||
Some("507b979802e62d397acb29f56743a791894b99372872fc5af06a4f6e8d242d0615cda53062bb20e6ec79756fe39183f0c128adfe85559a8fa042b042c018aa8010143799e44f0893c40e1e"),
|
Some("507b979802e62d397acb29f56743a791894b99372872fc5af06a4f6e8d242d0615cda53062bb20e6ec79756fe39183f0c128adfe85559a8fa042b042c018aa8010143799e44f0893c40e1e"),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -781,7 +800,7 @@ mod tests {
|
||||||
"011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182",
|
"011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182",
|
||||||
0,
|
0,
|
||||||
"d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e",
|
"d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e",
|
||||||
SigHashType::All,
|
SchnorrSigHashType::All,
|
||||||
None,
|
None,
|
||||||
Some("20cc4e1107aea1d170c5ff5b6817e1303010049724fb3caa7941792ea9d29b3e2bacab"),
|
Some("20cc4e1107aea1d170c5ff5b6817e1303010049724fb3caa7941792ea9d29b3e2bacab"),
|
||||||
);
|
);
|
||||||
|
@ -794,7 +813,7 @@ mod tests {
|
||||||
"011458360000000000225120a7baec3fb9f84614e3899fcc010c638f80f13539344120e1f4d8b68a9a011a13",
|
"011458360000000000225120a7baec3fb9f84614e3899fcc010c638f80f13539344120e1f4d8b68a9a011a13",
|
||||||
0,
|
0,
|
||||||
"a0042aa434f9a75904b64043f2a283f8b4c143c7f4f7f49a6cbe5b9f745f4c15",
|
"a0042aa434f9a75904b64043f2a283f8b4c143c7f4f7f49a6cbe5b9f745f4c15",
|
||||||
SigHashType::All,
|
SchnorrSigHashType::All,
|
||||||
Some("50a6272b470e1460e3332ade7bb14b81671c564fb6245761bd5bd531394b28860e0b3808ab229fb51791fb6ae6fa82d915b2efb8f6df83ae1f5ab3db13e30928875e2a22b749d89358de481f19286cd4caa792ce27f9559082d227a731c5486882cc707f83da361c51b7aadd9a0cf68fe7480c410fa137b454482d9a1ebf0f96d760b4d61426fc109c6e8e99a508372c45caa7b000a41f8251305da3f206c1849985ba03f3d9592832b4053afbd23ab25d0465df0bc25a36c223aacf8e04ec736a418c72dc319e4da3e972e349713ca600965e7c665f2090d5a70e241ac164115a1f5639f28b1773327715ca307ace64a2de7f0e3df70a2ffee3857689f909c0dad46d8a20fa373a4cc6eed6d4c9806bf146f0d76baae1"),
|
Some("50a6272b470e1460e3332ade7bb14b81671c564fb6245761bd5bd531394b28860e0b3808ab229fb51791fb6ae6fa82d915b2efb8f6df83ae1f5ab3db13e30928875e2a22b749d89358de481f19286cd4caa792ce27f9559082d227a731c5486882cc707f83da361c51b7aadd9a0cf68fe7480c410fa137b454482d9a1ebf0f96d760b4d61426fc109c6e8e99a508372c45caa7b000a41f8251305da3f206c1849985ba03f3d9592832b4053afbd23ab25d0465df0bc25a36c223aacf8e04ec736a418c72dc319e4da3e972e349713ca600965e7c665f2090d5a70e241ac164115a1f5639f28b1773327715ca307ace64a2de7f0e3df70a2ffee3857689f909c0dad46d8a20fa373a4cc6eed6d4c9806bf146f0d76baae1"),
|
||||||
Some("7520ab9160dd8299dc1367659be3e8f66781fe440d52940c7f8d314a89b9f2698d406ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6eadac"),
|
Some("7520ab9160dd8299dc1367659be3e8f66781fe440d52940c7f8d314a89b9f2698d406ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6eadac"),
|
||||||
);
|
);
|
||||||
|
@ -811,27 +830,27 @@ mod tests {
|
||||||
let mut c = SigHashCache::new(&dumb_tx);
|
let mut c = SigHashCache::new(&dumb_tx);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c.taproot_signature_hash(0, &Prevouts::All(&vec![]), None, None, SigHashType::All),
|
c.taproot_signature_hash(0, &Prevouts::All(&vec![]), None, None, SchnorrSigHashType::All),
|
||||||
Err(Error::PrevoutsSize)
|
Err(Error::PrevoutsSize)
|
||||||
);
|
);
|
||||||
let two = vec![TxOut::default(), TxOut::default()];
|
let two = vec![TxOut::default(), TxOut::default()];
|
||||||
let too_many_prevouts = Prevouts::All(&two);
|
let too_many_prevouts = Prevouts::All(&two);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c.taproot_signature_hash(0, &too_many_prevouts, None, None, SigHashType::All),
|
c.taproot_signature_hash(0, &too_many_prevouts, None, None, SchnorrSigHashType::All),
|
||||||
Err(Error::PrevoutsSize)
|
Err(Error::PrevoutsSize)
|
||||||
);
|
);
|
||||||
let tx_out = TxOut::default();
|
let tx_out = TxOut::default();
|
||||||
let prevout = Prevouts::One(1, &tx_out);
|
let prevout = Prevouts::One(1, &tx_out);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c.taproot_signature_hash(0, &prevout, None, None, SigHashType::All),
|
c.taproot_signature_hash(0, &prevout, None, None, SchnorrSigHashType::All),
|
||||||
Err(Error::PrevoutKind)
|
Err(Error::PrevoutKind)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c.taproot_signature_hash(0, &prevout, None, None, SigHashType::AllPlusAnyoneCanPay),
|
c.taproot_signature_hash(0, &prevout, None, None, SchnorrSigHashType::AllPlusAnyoneCanPay),
|
||||||
Err(Error::PrevoutIndex)
|
Err(Error::PrevoutIndex)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c.taproot_signature_hash(10, &prevout, None, None, SigHashType::AllPlusAnyoneCanPay),
|
c.taproot_signature_hash(10, &prevout, None, None, SchnorrSigHashType::AllPlusAnyoneCanPay),
|
||||||
Err(Error::IndexOutOfInputsBounds {
|
Err(Error::IndexOutOfInputsBounds {
|
||||||
index: 10,
|
index: 10,
|
||||||
inputs_size: 1
|
inputs_size: 1
|
||||||
|
@ -839,7 +858,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
let prevout = Prevouts::One(0, &tx_out);
|
let prevout = Prevouts::One(0, &tx_out);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c.taproot_signature_hash(0, &prevout, None, None, SigHashType::SinglePlusAnyoneCanPay),
|
c.taproot_signature_hash(0, &prevout, None, None, SchnorrSigHashType::SinglePlusAnyoneCanPay),
|
||||||
Err(Error::SingleWithoutCorrespondingOutput {
|
Err(Error::SingleWithoutCorrespondingOutput {
|
||||||
index: 0,
|
index: 0,
|
||||||
outputs_size: 0
|
outputs_size: 0
|
||||||
|
@ -866,7 +885,7 @@ mod tests {
|
||||||
prevout_hex: &str,
|
prevout_hex: &str,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
expected_hash: &str,
|
expected_hash: &str,
|
||||||
sighash_type: SigHashType,
|
sighash_type: SchnorrSigHashType,
|
||||||
annex_hex: Option<&str>,
|
annex_hex: Option<&str>,
|
||||||
script_hex: Option<&str>,
|
script_hex: Option<&str>,
|
||||||
) {
|
) {
|
||||||
|
|
Loading…
Reference in New Issue