diff --git a/CHANGELOG.md b/CHANGELOG.md index 683d456b56..bbc269bf44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ The previous release changed the behavior of `Display` for `ChildNumber`, assuming that any correct usage would not be affected. [Issue 608](https://github.com/rust-bitcoin/rust-bitcoin/issues/608) goes into the details of why this isn't -the case and how we broke both `rust-miniscript` and BDK. +the case and how we broke both `rust-miniscript` and BDK. # 0.26.1 - 2021-06-06 (yanked, see explanation above) diff --git a/Cargo.toml b/Cargo.toml index 6807491b26..0f9050d62f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitcoin" -version = "0.28.0-rc.1" +version = "0.28.0-rc.2" authors = ["Andrew Poelstra "] license = "CC0-1.0" homepage = "https://github.com/rust-bitcoin/rust-bitcoin/" diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 5d7343cd69..dd448fd8b8 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -43,7 +43,7 @@ use OutPoint; use util::key::PublicKey; use util::address::WitnessVersion; use util::taproot::{LeafVersion, TapBranchHash, TapLeafHash}; -use secp256k1::{Secp256k1, Verification}; +use secp256k1::{Secp256k1, Verification, XOnlyPublicKey}; use schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey}; /// A Bitcoin script. @@ -919,6 +919,11 @@ impl Builder { } } + /// Adds instructions to push an XOnly public key onto the stack. + pub fn push_x_only_key(self, x_only_key: &XOnlyPublicKey) -> Builder { + self.push_slice(&x_only_key.serialize()) + } + /// Adds a single opcode to the script. pub fn push_opcode(mut self, data: opcodes::All) -> Builder { self.0.push(data.into_u8()); @@ -1117,6 +1122,17 @@ mod test { script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]); } + #[test] + fn script_x_only_key() { + // Notice the "20" which prepends the keystr. That 20 is hexidecimal for "32". The Builder automatically adds the 32 opcode + // to our script in order to give a heads up to the script compiler that it should add the next 32 bytes to the stack. + // From: https://github.com/bitcoin-core/btcdeb/blob/e8c2750c4a4702768c52d15640ed03bf744d2601/doc/tapscript-example.md?plain=1#L43 + let keystr = "209997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be"; + let x_only_key = XOnlyPublicKey::from_str(&keystr[2..]).unwrap(); + let script = Builder::new().push_x_only_key(&x_only_key); + assert_eq!(script.0, Vec::from_hex(keystr).unwrap()); + } + #[test] fn script_builder() { // from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index a84bcac5ce..d4cd54d6bc 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -39,11 +39,11 @@ use blockdata::script::Script; use blockdata::witness::Witness; use consensus::{encode, Decodable, Encodable}; use consensus::encode::MAX_VEC_SIZE; -use hash_types::{SigHash, Txid, Wtxid}; +use hash_types::{Sighash, Txid, Wtxid}; use VarInt; #[cfg(doc)] -use util::sighash::SchnorrSigHashType; +use util::sighash::SchnorrSighashType; /// Used for signature hash for invalid use of SIGHASH_SINGLE. const UINT256_ONE: [u8; 32] = [ @@ -319,10 +319,10 @@ impl Transaction { /// sighash flag can be computed. /// /// To actually produce a scriptSig, this hash needs to be run through an ECDSA signer, the - /// [`EcdsaSigHashType`] appended to the resulting sig, and a script written around this, but + /// [`EcdsaSighashType`] appended to the resulting sig, and a script written around this, but /// this is the general (and hard) part. /// - /// The `sighash_type` supports an arbitrary `u32` value, instead of just [`EcdsaSigHashType`], + /// The `sighash_type` supports an arbitrary `u32` value, instead of just [`EcdsaSighashType`], /// because internally 4 bytes are being hashed, even though only the lowest byte is appended to /// signature in a transaction. /// @@ -356,7 +356,7 @@ impl Transaction { return Ok(()) } - let (sighash, anyone_can_pay) = EcdsaSigHashType::from_u32_consensus(sighash_type).split_anyonecanpay_flag(); + let (sighash, anyone_can_pay) = EcdsaSighashType::from_consensus(sighash_type).split_anyonecanpay_flag(); // Build tx to sign let mut tx = Transaction { @@ -379,22 +379,22 @@ impl Transaction { tx.input.push(TxIn { previous_output: input.previous_output, script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() }, - sequence: if n != input_index && (sighash == EcdsaSigHashType::Single || sighash == EcdsaSigHashType::None) { 0 } else { input.sequence }, + sequence: if n != input_index && (sighash == EcdsaSighashType::Single || sighash == EcdsaSighashType::None) { 0 } else { input.sequence }, witness: Witness::default(), }); } } // ..then all outputs tx.output = match sighash { - EcdsaSigHashType::All => self.output.clone(), - EcdsaSigHashType::Single => { + EcdsaSighashType::All => self.output.clone(), + EcdsaSighashType::Single => { let output_iter = self.output.iter() .take(input_index + 1) // sign all outputs up to and including this one, but erase .enumerate() // all of them except for this one .map(|(n, out)| if n == input_index { out.clone() } else { TxOut::default() }); output_iter.collect() } - EcdsaSigHashType::None => vec![], + EcdsaSighashType::None => vec![], _ => unreachable!() }; // hash the result @@ -407,10 +407,10 @@ impl Transaction { /// Computes a signature hash for a given input index with a given sighash flag. /// /// To actually produce a scriptSig, this hash needs to be run through an ECDSA signer, the - /// [`EcdsaSigHashType`] appended to the resulting sig, and a script written around this, but + /// [`EcdsaSighashType`] appended to the resulting sig, and a script written around this, but /// this is the general (and hard) part. /// - /// The `sighash_type` supports an arbitrary `u32` value, instead of just [`EcdsaSigHashType`], + /// The `sighash_type` supports an arbitrary `u32` value, instead of just [`EcdsaSighashType`], /// because internally 4 bytes are being hashed, even though only the lowest byte is appended to /// signature in a transaction. /// @@ -432,20 +432,20 @@ impl Transaction { input_index: usize, script_pubkey: &Script, sighash_u32: u32 - ) -> SigHash { + ) -> Sighash { if self.is_invalid_use_of_sighash_single(sighash_u32, input_index) { - return SigHash::from_slice(&UINT256_ONE).expect("const-size array"); + return Sighash::from_slice(&UINT256_ONE).expect("const-size array"); } - let mut engine = SigHash::engine(); + let mut engine = Sighash::engine(); self.encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_u32) .expect("engines don't error"); - SigHash::from_engine(engine) + Sighash::from_engine(engine) } fn is_invalid_use_of_sighash_single(&self, sighash: u32, input_index: usize) -> bool { - let ty = EcdsaSigHashType::from_u32_consensus(sighash); - ty == EcdsaSigHashType::Single && input_index >= self.output.len() + let ty = EcdsaSighashType::from_consensus(sighash); + ty == EcdsaSighashType::Single && input_index >= self.output.len() } /// Returns the "weight" of this transaction, as defined by BIP141. @@ -723,9 +723,9 @@ impl Decodable for Transaction { /// This type is consensus valid but an input including it would prevent the transaction from /// being relayed on today's Bitcoin network. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct NonStandardSigHashType(pub u32); +pub struct NonStandardSighashType(pub u32); -impl fmt::Display for NonStandardSigHashType { +impl fmt::Display for NonStandardSighashType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Non standard sighash type {}", self.0) } @@ -733,18 +733,18 @@ impl fmt::Display for NonStandardSigHashType { #[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; +#[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. /// /// Fixed values so they can be cast as integer types for encoding (see also -/// [`SchnorrSigHashType`]). +/// [`SchnorrSighashType`]). #[derive(PartialEq, Eq, Debug, Copy, Clone)] -pub enum EcdsaSigHashType { +pub enum EcdsaSighashType { /// 0x1: Sign all outputs. All = 0x01, /// 0x2: Sign no outputs --- anyone can choose the destination. @@ -761,66 +761,67 @@ pub enum EcdsaSigHashType { /// 0x83: Sign one output and only this input (see `Single` for what "one output" means). SinglePlusAnyoneCanPay = 0x83 } -serde_string_impl!(EcdsaSigHashType, "a EcdsaSigHashType data"); +serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data"); -impl fmt::Display for EcdsaSigHashType { +impl fmt::Display for EcdsaSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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", + 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", }; f.write_str(s) } } -impl str::FromStr for EcdsaSigHashType { - type Err = SigHashTypeParseError; +impl str::FromStr for EcdsaSighashType { + type Err = SighashTypeParseError; fn from_str(s: &str) -> Result { 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), - _ => Err(SigHashTypeParseError{ unrecognized: s.to_owned() }), + "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), + _ => Err(SighashTypeParseError { unrecognized: s.to_owned() }), } } } -impl 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) { + pub(crate) fn split_anyonecanpay_flag(self) -> (EcdsaSighashType, bool) { 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) + 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) } } - /// 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")] - pub fn from_u32(n: u32) -> EcdsaSigHashType { - Self::from_u32_consensus(n) + /// Creates a [`EcdsaSighashType`] from a raw `u32`. + #[deprecated(since="0.28.0", note="please use `from_consensus`")] + pub fn from_u32_consensus(n: u32) -> EcdsaSighashType { + EcdsaSighashType::from_consensus(n) } - /// Reads a 4-byte uint32 as a sighash type. + /// Creates a [`EcdsaSighashType`] from a raw `u32`. /// /// **Note**: this replicates consensus behaviour, for current standardness rules correctness - /// you probably want [Self::from_u32_standard]. + /// you probably want [`Self::from_standard`]. + /// /// This might cause unexpected behavior because it does not roundtrip. That is, - /// `EcdsaSigHashType::from_u32_consensus(n) as u32 != n` for non-standard values of - /// `n`. While verifying signatures, the user should retain the `n` and use it compute the - /// signature hash message. - pub fn from_u32_consensus(n: u32) -> EcdsaSigHashType { + /// `EcdsaSighashType::from_consensus(n) as u32 != n` for non-standard values of `n`. While + /// verifying signatures, the user should retain the `n` and use it compute the signature hash + /// message. + pub fn from_consensus(n: u32) -> 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. @@ -828,53 +829,58 @@ 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 => EcdsaSighashType::All, + 0x02 => EcdsaSighashType::None, + 0x03 => EcdsaSighashType::Single, + 0x81 => EcdsaSighashType::AllPlusAnyoneCanPay, + 0x82 => EcdsaSighashType::NonePlusAnyoneCanPay, + 0x83 => EcdsaSighashType::SinglePlusAnyoneCanPay, // catchalls - x if x & 0x80 == 0x80 => EcdsaSigHashType::AllPlusAnyoneCanPay, - _ => EcdsaSigHashType::All + x if x & 0x80 == 0x80 => EcdsaSighashType::AllPlusAnyoneCanPay, + _ => EcdsaSighashType::All } } - /// Read a 4-byte uint32 as a standard sighash type, returning an error if the type - /// is non standard. - pub fn from_u32_standard(n: u32) -> Result { + /// Creates a [`EcdsaSighashType`] from a raw `u32`. + #[deprecated(since="0.28.0", note="please use `from_standard`")] + pub fn from_u32_standard(n: u32) -> Result { + EcdsaSighashType::from_standard(n) + } + + /// Creates a [`EcdsaSighashType`] from a raw `u32`. + /// + /// # Errors + /// + /// If `n` is a non-standard sighash value. + pub fn from_standard(n: u32) -> Result { 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), - non_standard => Err(NonStandardSigHashType(non_standard)) + 0x01 => Ok(EcdsaSighashType::All), + 0x02 => Ok(EcdsaSighashType::None), + 0x03 => Ok(EcdsaSighashType::Single), + 0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), + 0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), + 0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), + non_standard => Err(NonStandardSighashType(non_standard)) } } - /// Converts to a u32 - pub fn as_u32(self) -> u32 { self as u32 } -} - -impl From for u32 { - fn from(t: EcdsaSigHashType) -> u32 { - t.as_u32() - } + /// Converts [`EcdsaSighashType`] to a `u32` sighash flag. + /// + /// The returned value is guaranteed to be a valid according to standardness rules. + pub fn to_u32(self) -> u32 { self as u32 } } -/// Error returned when parsing `SigHashType` fails. +/// Error returned for failure during parsing one of the sighash types. /// /// This is currently returned for unrecognized sighash strings. #[derive(Debug, Clone)] -pub struct SigHashTypeParseError { +pub struct SighashTypeParseError { /// The unrecognized string we attempted to parse. pub unrecognized: String, } -impl fmt::Display for SigHashTypeParseError { +impl fmt::Display for SighashTypeParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Unrecognized SIGHASH string '{}'", self.unrecognized) } @@ -882,7 +888,7 @@ impl fmt::Display for SigHashTypeParseError { #[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg(feature = "std")] -impl ::std::error::Error for SigHashTypeParseError {} +impl ::std::error::Error for SighashTypeParseError {} #[cfg(test)] mod tests { @@ -898,8 +904,8 @@ mod tests { use hashes::hex::FromHex; use hash_types::*; - use super::EcdsaSigHashType; - use util::sighash::SigHashCache; + use super::EcdsaSighashType; + use util::sighash::SighashCache; #[test] fn test_outpoint() { @@ -1161,16 +1167,16 @@ mod tests { #[test] fn test_sighashtype_fromstr_display() { let sighashtypes = vec![ - ("SIGHASH_ALL", EcdsaSigHashType::All), - ("SIGHASH_NONE", EcdsaSigHashType::None), - ("SIGHASH_SINGLE", EcdsaSigHashType::Single), - ("SIGHASH_ALL|SIGHASH_ANYONECANPAY", EcdsaSigHashType::AllPlusAnyoneCanPay), - ("SIGHASH_NONE|SIGHASH_ANYONECANPAY", EcdsaSigHashType::NonePlusAnyoneCanPay), - ("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", EcdsaSigHashType::SinglePlusAnyoneCanPay) + ("SIGHASH_ALL", EcdsaSighashType::All), + ("SIGHASH_NONE", EcdsaSighashType::None), + ("SIGHASH_SINGLE", EcdsaSighashType::Single), + ("SIGHASH_ALL|SIGHASH_ANYONECANPAY", EcdsaSighashType::AllPlusAnyoneCanPay), + ("SIGHASH_NONE|SIGHASH_ANYONECANPAY", EcdsaSighashType::NonePlusAnyoneCanPay), + ("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", EcdsaSighashType::SinglePlusAnyoneCanPay) ]; for (s, sht) in sighashtypes { assert_eq!(sht.to_string(), s); - assert_eq!(EcdsaSigHashType::from_str(s).unwrap(), sht); + assert_eq!(EcdsaSighashType::from_str(s).unwrap(), sht); } let sht_mistakes = vec![ "SIGHASH_ALL | SIGHASH_ANYONECANPAY", @@ -1185,7 +1191,7 @@ mod tests { "SigHash_NONE", ]; for s in sht_mistakes { - assert_eq!(EcdsaSigHashType::from_str(s).unwrap_err().to_string(), format!("Unrecognized SIGHASH string '{}'", s)); + assert_eq!(EcdsaSighashType::from_str(s).unwrap_err().to_string(), format!("Unrecognized SIGHASH string '{}'", s)); } } @@ -1194,10 +1200,9 @@ mod tests { fn test_sighashtype_standard() { let nonstandard_hashtype = 0x04; // This type is not well defined, by consensus it becomes ALL - assert_eq!(EcdsaSigHashType::from_u32(nonstandard_hashtype), EcdsaSigHashType::All); - assert_eq!(EcdsaSigHashType::from_u32_consensus(nonstandard_hashtype), EcdsaSigHashType::All); + assert_eq!(EcdsaSighashType::from_u32_consensus(nonstandard_hashtype), EcdsaSighashType::All); // But it's policy-invalid to use it! - assert_eq!(EcdsaSigHashType::from_u32_standard(nonstandard_hashtype), Err(NonStandardSigHashType(0x04))); + assert_eq!(EcdsaSighashType::from_u32_standard(nonstandard_hashtype), Err(NonStandardSighashType(0x04))); } #[test] @@ -1218,7 +1223,7 @@ mod tests { }; let script = Script::new(); let got = tx.signature_hash(1, &script, SIGHASH_SINGLE); - let want = SigHash::from_slice(&UINT256_ONE).unwrap(); + let want = Sighash::from_slice(&UINT256_ONE).unwrap(); assert_eq!(got, want) } @@ -1228,14 +1233,14 @@ mod tests { let script = Script::from(Vec::from_hex(script).unwrap()); let mut raw_expected = Vec::from_hex(expected_result).unwrap(); raw_expected.reverse(); - let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap(); + let expected_result = Sighash::from_slice(&raw_expected[..]).unwrap(); let actual_result = if raw_expected[0] % 2 == 0 { // tx.signature_hash and cache.legacy_signature_hash are the same, this if helps to test // both the codepaths without repeating the test code tx.signature_hash(input_index, &script, hash_type as u32) } else { - let cache = SigHashCache::new(&tx); + let cache = SighashCache::new(&tx); cache.legacy_signature_hash(input_index, &script, hash_type as u32).unwrap() }; diff --git a/src/hash_types.rs b/src/hash_types.rs index 19a59c9a0e..425ea5f893 100644 --- a/src/hash_types.rs +++ b/src/hash_types.rs @@ -42,7 +42,7 @@ macro_rules! impl_hashencode { hash_newtype!(Txid, sha256d::Hash, 32, doc="A bitcoin transaction hash/transaction ID."); 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"); +hash_newtype!(Sighash, sha256d::Hash, 32, doc="Hash of the transaction according to the signature algorithm"); 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."); @@ -61,7 +61,7 @@ hash_newtype!(FilterHeader, sha256d::Hash, 32, doc="Filter header, as defined in impl_hashencode!(Txid); impl_hashencode!(Wtxid); impl_hashencode!(BlockHash); -impl_hashencode!(SigHash); +impl_hashencode!(Sighash); impl_hashencode!(TxMerkleNode); impl_hashencode!(WitnessMerkleNode); diff --git a/src/lib.rs b/src/lib.rs index 26725f865f..0b7bc883dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,7 +123,7 @@ pub use blockdata::transaction::Transaction; pub use blockdata::transaction::TxIn; pub use blockdata::transaction::TxOut; pub use blockdata::transaction::OutPoint; -pub use blockdata::transaction::EcdsaSigHashType; +pub use blockdata::transaction::EcdsaSighashType; pub use blockdata::witness::Witness; pub use consensus::encode::VarInt; pub use network::constants::Network; @@ -134,7 +134,7 @@ pub use util::amount::Amount; pub use util::amount::Denomination; pub use util::amount::SignedAmount; pub use util::merkleblock::MerkleBlock; -pub use util::sighash::SchnorrSigHashType; +pub use util::sighash::SchnorrSighashType; pub use util::ecdsa::{self, EcdsaSig, EcdsaSigError}; pub use util::schnorr::{self, SchnorrSig, SchnorrSigError}; diff --git a/src/util/address.rs b/src/util/address.rs index a24c11c2fe..982ae118f3 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -39,9 +39,9 @@ use core::num::ParseIntError; use core::str::FromStr; #[cfg(feature = "std")] use std::error; -use secp256k1::{Secp256k1, Verification}; +use secp256k1::{Secp256k1, Verification, XOnlyPublicKey}; use bech32; -use hashes::Hash; +use hashes::{sha256, Hash, HashEngine}; use hash_types::{PubkeyHash, ScriptHash}; use blockdata::{script, opcodes}; use blockdata::constants::{PUBKEY_ADDRESS_PREFIX_MAIN, SCRIPT_ADDRESS_PREFIX_MAIN, PUBKEY_ADDRESS_PREFIX_TEST, SCRIPT_ADDRESS_PREFIX_TEST, MAX_SCRIPT_ELEMENT_SIZE}; @@ -714,6 +714,37 @@ impl Address { (Network::Testnet, _) | (Network::Regtest, _) | (Network::Signet, _) => true } } + + /// Returns true if the given pubkey is directly related to the address payload. + /// + /// This is determined by directly comparing the address payload with either the + /// hash of the given public key or the segwit redeem hash generated from the + /// given key. For taproot addresses, the supplied key is assumed to be tweaked + pub fn is_related_to_pubkey(&self, pubkey: &PublicKey) -> bool { + let pubkey_hash = pubkey.pubkey_hash(); + let payload = self.payload_as_bytes(); + let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner); + + (*pubkey_hash == *payload) || (xonly_pubkey.serialize() == *payload) || (*segwit_redeem_hash(&pubkey_hash) == *payload) + } + + /// Returns true if the supplied xonly public key can be used to derive the address. + /// + /// This will only work for Taproot addresses. The Public Key is + /// assumed to have already been tweaked. + pub fn is_related_to_xonly_pubkey(&self, xonly_pubkey: &XOnlyPublicKey) -> bool { + let payload = self.payload_as_bytes(); + payload == xonly_pubkey.serialize() + } + + /// Return the address payload as a byte slice + fn payload_as_bytes(&self) -> &[u8] { + match &self.payload { + Payload::ScriptHash(hash) => hash, + Payload::PubkeyHash(hash) => hash, + Payload::WitnessProgram { program, .. } => program, + } + } } // Alternate formatting `{:#}` is used to return uppercase version of bech32 addresses which should @@ -857,6 +888,14 @@ impl fmt::Debug for Address { } } +/// Convert a byte array of a pubkey hash into a segwit redeem hash +fn segwit_redeem_hash(pubkey_hash: &[u8]) -> ::hashes::hash160::Hash { + let mut sha_engine = sha256::Hash::engine(); + sha_engine.input(&[0, 20]); + sha_engine.input(pubkey_hash); + ::hashes::hash160::Hash::from_engine(sha_engine) +} + #[cfg(test)] mod tests { use core::str::FromStr; @@ -1260,4 +1299,95 @@ mod tests { assert_eq!(address.address_type(), Some(AddressType::P2tr)); roundtrips(&address); } + + #[test] + fn test_is_related_to_pubkey_p2wpkh() { + let address_string = "bc1qhvd6suvqzjcu9pxjhrwhtrlj85ny3n2mqql5w4"; + let address = Address::from_str(address_string).expect("address"); + + let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b"; + let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey"); + + let result = address.is_related_to_pubkey(&pubkey); + assert!(result); + + let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey"); + assert!(!address.is_related_to_pubkey(&unused_pubkey)) + } + + #[test] + fn test_is_related_to_pubkey_p2shwpkh() { + let address_string = "3EZQk4F8GURH5sqVMLTFisD17yNeKa7Dfs"; + let address = Address::from_str(address_string).expect("address"); + + let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b"; + let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey"); + + let result = address.is_related_to_pubkey(&pubkey); + assert!(result); + + let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey"); + assert!(!address.is_related_to_pubkey(&unused_pubkey)) + } + + #[test] + fn test_is_related_to_pubkey_p2pkh() { + let address_string = "1J4LVanjHMu3JkXbVrahNuQCTGCRRgfWWx"; + let address = Address::from_str(address_string).expect("address"); + + let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b"; + let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey"); + + let result = address.is_related_to_pubkey(&pubkey); + assert!(result); + + let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey"); + assert!(!address.is_related_to_pubkey(&unused_pubkey)) + } + + #[test] + fn test_is_related_to_pubkey_p2pkh_uncompressed_key() { + let address_string = "msvS7KzhReCDpQEJaV2hmGNvuQqVUDuC6p"; + let address = Address::from_str(address_string).expect("address"); + + let pubkey_string = "04e96e22004e3db93530de27ccddfdf1463975d2138ac018fc3e7ba1a2e5e0aad8e424d0b55e2436eb1d0dcd5cb2b8bcc6d53412c22f358de57803a6a655fbbd04"; + let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey"); + + let result = address.is_related_to_pubkey(&pubkey); + assert!(result); + + let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey"); + assert!(!address.is_related_to_pubkey(&unused_pubkey)) + } + + #[test] + fn test_is_related_to_pubkey_p2tr(){ + let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b"; + let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey"); + let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner); + let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(xonly_pubkey); + let address = Address::p2tr_tweaked(tweaked_pubkey, Network::Bitcoin); + + assert_eq!(address, Address::from_str("bc1pgllnmtxs0g058qz7c6qgaqq4qknwrqj9z7rqn9e2dzhmcfmhlu4sfadf5e").expect("address")); + + let result = address.is_related_to_pubkey(&pubkey); + assert!(result); + + let unused_pubkey = PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").expect("pubkey"); + assert!(!address.is_related_to_pubkey(&unused_pubkey)); + } + + #[test] + fn test_is_related_to_xonly_pubkey(){ + let pubkey_string = "0347ff3dacd07a1f43805ec6808e801505a6e18245178609972a68afbc2777ff2b"; + let pubkey = PublicKey::from_str(pubkey_string).expect("pubkey"); + let xonly_pubkey = XOnlyPublicKey::from(pubkey.inner); + let tweaked_pubkey = TweakedPublicKey::dangerous_assume_tweaked(xonly_pubkey); + let address = Address::p2tr_tweaked(tweaked_pubkey, Network::Bitcoin); + + assert_eq!(address, Address::from_str("bc1pgllnmtxs0g058qz7c6qgaqq4qknwrqj9z7rqn9e2dzhmcfmhlu4sfadf5e").expect("address")); + + let result = address.is_related_to_xonly_pubkey(&xonly_pubkey); + assert!(result); + } } diff --git a/src/util/bip143.rs b/src/util/bip143.rs index c238a5ec2f..7cd2ab9c8d 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -20,10 +20,10 @@ //! use hashes::Hash; -use hash_types::SigHash; +use hash_types::Sighash; use blockdata::script::Script; use blockdata::witness::Witness; -use blockdata::transaction::{Transaction, TxIn, EcdsaSigHashType}; +use blockdata::transaction::{Transaction, TxIn, EcdsaSighashType}; use consensus::{encode, Encodable}; use io; @@ -33,16 +33,16 @@ use util::sighash; /// Parts of a sighash which are common across inputs or signatures, and which are /// sufficient (in conjunction with a private key) to sign the transaction #[derive(Clone, PartialEq, Eq, Debug)] -#[deprecated(since = "0.24.0", note = "please use [sighash::SigHashCache] instead")] +#[deprecated(since = "0.24.0", note = "please use [sighash::SighashCache] instead")] pub struct SighashComponents { tx_version: i32, tx_locktime: u32, /// Hash of all the previous outputs - pub hash_prevouts: SigHash, + pub hash_prevouts: Sighash, /// Hash of all the input sequence nos - pub hash_sequence: SigHash, + pub hash_sequence: Sighash, /// Hash of all the outputs in this transaction - pub hash_outputs: SigHash, + pub hash_outputs: Sighash, } #[allow(deprecated)] @@ -53,27 +53,27 @@ impl SighashComponents { /// script_sig and witnesses. pub fn new(tx: &Transaction) -> SighashComponents { let hash_prevouts = { - let mut enc = SigHash::engine(); + let mut enc = Sighash::engine(); for txin in &tx.input { txin.previous_output.consensus_encode(&mut enc).expect("engines don't error"); } - SigHash::from_engine(enc) + Sighash::from_engine(enc) }; let hash_sequence = { - let mut enc = SigHash::engine(); + let mut enc = Sighash::engine(); for txin in &tx.input { txin.sequence.consensus_encode(&mut enc).expect("engines don't error"); } - SigHash::from_engine(enc) + Sighash::from_engine(enc) }; let hash_outputs = { - let mut enc = SigHash::engine(); + let mut enc = Sighash::engine(); for txout in &tx.output { txout.consensus_encode(&mut enc).expect("engines don't error"); } - SigHash::from_engine(enc) + Sighash::from_engine(enc) }; SighashComponents { @@ -87,8 +87,8 @@ impl SighashComponents { /// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given /// input. - pub fn sighash_all(&self, txin: &TxIn, script_code: &Script, value: u64) -> SigHash { - let mut enc = SigHash::engine(); + pub fn sighash_all(&self, txin: &TxIn, script_code: &Script, value: u64) -> Sighash { + let mut enc = Sighash::engine(); self.tx_version.consensus_encode(&mut enc).expect("engines don't error"); self.hash_prevouts.consensus_encode(&mut enc).expect("engines don't error"); self.hash_sequence.consensus_encode(&mut enc).expect("engines don't error"); @@ -102,14 +102,14 @@ impl SighashComponents { self.hash_outputs.consensus_encode(&mut enc).expect("engines don't error"); self.tx_locktime.consensus_encode(&mut enc).expect("engines don't error"); 1u32.consensus_encode(&mut enc).expect("engines don't error"); // hashtype - SigHash::from_engine(enc) + Sighash::from_engine(enc) } } /// A replacement for SigHashComponents which supports all sighash modes -#[deprecated(since = "0.27.0", note = "please use [sighash::SigHashCache] instead")] +#[deprecated(since = "0.28.0", note = "please use [sighash::SighashCache] instead")] pub struct SigHashCache> { - cache: sighash::SigHashCache, + cache: sighash::SighashCache, } #[allow(deprecated)] @@ -119,7 +119,7 @@ impl> SigHashCache { /// For the generated sighashes to be valid, no fields in the transaction may change except for /// script_sig and witnesses. pub fn new(tx: R) -> Self { - Self { cache: sighash::SigHashCache::new(tx) } + Self { cache: sighash::SighashCache::new(tx) } } /// Encode the BIP143 signing data for any flag type into a given object implementing a @@ -130,7 +130,7 @@ impl> SigHashCache { input_index: usize, script_code: &Script, value: u64, - sighash_type: EcdsaSigHashType, + sighash_type: EcdsaSighashType, ) -> Result<(), encode::Error> { self.cache .segwit_encode_signing_data_to(writer, input_index, script_code, value, sighash_type) @@ -145,12 +145,12 @@ impl> SigHashCache { input_index: usize, script_code: &Script, value: u64, - sighash_type: EcdsaSigHashType - ) -> SigHash { - let mut enc = SigHash::engine(); + sighash_type: EcdsaSighashType + ) -> Sighash { + let mut enc = Sighash::engine(); self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type) .expect("engines don't error"); - SigHash::from_engine(enc) + Sighash::from_engine(enc) } } @@ -164,7 +164,7 @@ impl> SigHashCache { /// panics if `input_index` is out of bounds with respect of the number of inputs /// /// ``` - /// use bitcoin::blockdata::transaction::{Transaction, EcdsaSigHashType}; + /// use bitcoin::blockdata::transaction::{Transaction, EcdsaSighashType}; /// use bitcoin::util::bip143::SigHashCache; /// use bitcoin::Script; /// @@ -174,7 +174,7 @@ impl> SigHashCache { /// let mut sig_hasher = SigHashCache::new(&mut tx_to_sign); /// for inp in 0..input_count { /// let prevout_script = Script::new(); - /// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, 42, EcdsaSigHashType::All); + /// let _sighash = sig_hasher.signature_hash(inp, &prevout_script, 42, EcdsaSighashType::All); /// // ... sign the sighash /// sig_hasher.access_witness(inp).push(&[]); /// } @@ -188,7 +188,7 @@ impl> SigHashCache { #[allow(deprecated)] mod tests { use std::str::FromStr; - use hash_types::SigHash; + use hash_types::Sighash; use blockdata::script::Script; use blockdata::transaction::Transaction; use consensus::encode::deserialize; @@ -208,10 +208,10 @@ mod tests { fn run_test_sighash_bip143(tx: &str, script: &str, input_index: usize, value: u64, hash_type: u32, expected_result: &str) { let tx: Transaction = deserialize(&Vec::::from_hex(tx).unwrap()[..]).unwrap(); let script = Script::from(Vec::::from_hex(script).unwrap()); - let raw_expected = SigHash::from_hex(expected_result).unwrap(); - let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap(); + let raw_expected = Sighash::from_hex(expected_result).unwrap(); + let expected_result = Sighash::from_slice(&raw_expected[..]).unwrap(); let mut cache = SigHashCache::new(&tx); - let sighash_type = EcdsaSigHashType::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); assert_eq!(actual_result, expected_result); } @@ -237,20 +237,20 @@ mod tests { tx_version: 1, tx_locktime: 17, hash_prevouts: hex_hash!( - SigHash, "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37" + Sighash, "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37" ), hash_sequence: hex_hash!( - SigHash, "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b" + Sighash, "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b" ), hash_outputs: hex_hash!( - SigHash, "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5" + Sighash, "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5" ), } ); assert_eq!( comp.sighash_all(&tx.input[1], &witness_script, value), - hex_hash!(SigHash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670") + hex_hash!(Sighash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670") ); } @@ -273,20 +273,20 @@ mod tests { tx_version: 1, tx_locktime: 1170, hash_prevouts: hex_hash!( - SigHash, "b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a" + Sighash, "b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a" ), hash_sequence: hex_hash!( - SigHash, "18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198" + Sighash, "18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198" ), hash_outputs: hex_hash!( - SigHash, "de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83" + Sighash, "de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83" ), } ); assert_eq!( comp.sighash_all(&tx.input[0], &witness_script, value), - hex_hash!(SigHash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6") + hex_hash!(Sighash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6") ); } @@ -316,20 +316,20 @@ mod tests { tx_version: 1, tx_locktime: 0, hash_prevouts: hex_hash!( - SigHash, "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0" + Sighash, "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0" ), hash_sequence: hex_hash!( - SigHash, "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044" + Sighash, "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044" ), hash_outputs: hex_hash!( - SigHash, "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc" + Sighash, "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc" ), } ); assert_eq!( comp.sighash_all(&tx.input[0], &witness_script, value), - hex_hash!(SigHash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c") + hex_hash!(Sighash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c") ); } #[test] diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 5a04b1cc9b..431b368af5 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -20,9 +20,9 @@ use prelude::*; use core::str::FromStr; use core::{fmt, iter}; use hashes::hex::{self, FromHex}; -use blockdata::transaction::NonStandardSigHashType; +use blockdata::transaction::NonStandardSighashType; use secp256k1; -use EcdsaSigHashType; +use EcdsaSighashType; /// An ECDSA signature with the corresponding hash type. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -31,24 +31,24 @@ pub struct EcdsaSig { /// The underlying ECDSA Signature pub sig: secp256k1::ecdsa::Signature, /// The corresponding hash type - pub hash_ty: EcdsaSigHashType, + pub hash_ty: EcdsaSighashType, } impl EcdsaSig { - /// Constructs ECDSA bitcoin signature for [`EcdsaSigHashType::All`] + /// Constructs ECDSA bitcoin signature for [`EcdsaSighashType::All`] pub fn sighash_all(sig: secp256k1::ecdsa::Signature) -> EcdsaSig { EcdsaSig { sig, - hash_ty: EcdsaSigHashType::All + hash_ty: EcdsaSighashType::All } } - /// Deserialize from slice following the standardness rules for [`EcdsaSigHashType`] + /// Deserialize from slice following the standardness rules for [`EcdsaSighashType`] pub fn from_slice(sl: &[u8]) -> Result { 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 as u32))?; + let hash_ty = EcdsaSighashType::from_standard(*hash_ty as u32) + .map_err(|_| EcdsaSigError::NonStandardSighashType(*hash_ty as u32))?; let sig = secp256k1::ecdsa::Signature::from_der(sig) .map_err(EcdsaSigError::Secp256k1)?; Ok(EcdsaSig { sig, hash_ty }) @@ -80,7 +80,7 @@ impl FromStr for EcdsaSig { .ok_or(EcdsaSigError::EmptySignature)?; Ok(EcdsaSig { sig: secp256k1::ecdsa::Signature::from_der(signature)?, - hash_ty: EcdsaSigHashType::from_u32_standard(*sighash_byte as u32)? + hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)? }) } } @@ -91,7 +91,7 @@ pub enum EcdsaSigError { /// Hex encoding error HexEncoding(hex::Error), /// Base58 encoding error - NonStandardSigHashType(u32), + NonStandardSighashType(u32), /// Empty Signature EmptySignature, /// secp256k1-related error @@ -102,7 +102,7 @@ pub enum EcdsaSigError { impl fmt::Display for EcdsaSigError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - EcdsaSigError::NonStandardSigHashType(hash_ty) => + EcdsaSigError::NonStandardSighashType(hash_ty) => write!(f, "Non standard signature hash type {}", hash_ty), EcdsaSigError::Secp256k1(ref e) => write!(f, "Invalid Ecdsa signature: {}", e), @@ -123,9 +123,9 @@ impl From for EcdsaSigError { } } -impl From for EcdsaSigError { - fn from(err: NonStandardSigHashType) -> Self { - EcdsaSigError::NonStandardSigHashType(err.0) +impl From for EcdsaSigError { + fn from(err: NonStandardSighashType) -> Self { + EcdsaSigError::NonStandardSighashType(err.0) } } diff --git a/src/util/psbt/error.rs b/src/util/psbt/error.rs index caab843b2c..c281106de9 100644 --- a/src/util/psbt/error.rs +++ b/src/util/psbt/error.rs @@ -61,8 +61,8 @@ pub enum Error { /// Actual actual: Box, }, - /// Unable to parse as a standard SigHash type. - NonStandardSigHashType(u32), + /// Unable to parse as a standard sighash type. + NonStandardSighashType(u32), /// Parsing errors from bitcoin_hashes HashParseError(hashes::Error), /// The pre-image must hash to the correponding psbt hash @@ -88,7 +88,7 @@ impl fmt::Display for Error { Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"), Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey), Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "different unsigned transaction: expected {}, actual {}", e.txid(), a.txid()), - Error::NonStandardSigHashType(ref sht) => write!(f, "non-standard sighash type: {}", sht), + Error::NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht), Error::InvalidMagic => f.write_str("invalid magic"), Error::InvalidSeparator => f.write_str("invalid separator"), Error::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"), diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index e89fa9c953..a737cbdba0 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -14,11 +14,13 @@ use prelude::*; use io; +use core::fmt; +use core::str::FromStr; use secp256k1; use blockdata::script::Script; use blockdata::witness::Witness; -use blockdata::transaction::{Transaction, TxOut, NonStandardSigHashType}; +use blockdata::transaction::{Transaction, TxOut, NonStandardSighashType, SighashTypeParseError}; use consensus::encode; use hashes::{self, hash160, ripemd160, sha256, sha256d}; use secp256k1::XOnlyPublicKey; @@ -32,7 +34,7 @@ use util::key::PublicKey; use util::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash}; use util::sighash; -use {EcdsaSigHashType, SchnorrSigHashType, EcdsaSig, SchnorrSig}; +use {EcdsaSighashType, SchnorrSighashType, EcdsaSig, SchnorrSig}; /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00; @@ -77,7 +79,7 @@ const PSBT_IN_PROPRIETARY: u8 = 0xFC; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. -#[derive(Clone, Default, Debug, PartialEq)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Input { /// The non-witness transaction this input spends from. Should only be @@ -93,7 +95,7 @@ pub struct Input { pub partial_sigs: BTreeMap, /// The sighash type to be used for this input. Signatures for this input /// must use the sighash type. - pub sighash_type: Option, + pub sighash_type: Option, /// The redeem script for this input. pub redeem_script: Option