From 51fef7612927f2d3072ccdf39f7213610e79c8c6 Mon Sep 17 00:00:00 2001 From: Andrew Ahlers Date: Sun, 20 Feb 2022 20:12:16 +0100 Subject: [PATCH 01/40] feat: Add Address.is_related_to_pubkey() --- src/util/address.rs | 134 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 2 deletions(-) diff --git a/src/util/address.rs b/src/util/address.rs index a1718332c9..e4e6e48d07 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}; @@ -727,6 +727,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 @@ -870,6 +901,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; @@ -1273,4 +1312,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); + } } From e27f8ff5943533a3c7b32753bc0a8ce430b4c0a5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 23 Mar 2022 12:46:10 +0100 Subject: [PATCH 02/40] TapTree iterator implementation --- src/util/psbt/map/output.rs | 42 ++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index e03049c40b..a77a5729e1 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -13,6 +13,7 @@ // use prelude::*; +use core; use io; @@ -25,7 +26,7 @@ use util::psbt::map::Map; use util::psbt::raw; use util::psbt::Error; -use util::taproot::TapLeafHash; +use util::taproot::{LeafInfo, TapLeafHash}; use util::taproot::{NodeInfo, TaprootBuilder}; @@ -117,6 +118,45 @@ impl TapTree { pub fn into_inner(self) -> TaprootBuilder { self.0 } + + /// Returns iterator for a taproot script tree, operating in DFS order over leaf depth and + /// leaf script pairs. + pub fn iter(&self) -> TapTreeIter { + self.into_iter() + } +} + +/// Iterator for a taproot script tree, operating in DFS order over leaf depth and +/// leaf script pairs. +pub struct TapTreeIter<'tree> { + leaf_iter: core::slice::Iter<'tree, LeafInfo>, +} + +impl<'tree> Iterator for TapTreeIter<'tree> { + type Item = (u8, &'tree Script); + + fn next(&mut self) -> Option { + self.leaf_iter.next().map(|leaf_info| { + (leaf_info.merkle_branch.as_inner().len() as u8, &leaf_info.script) + }) + } +} + +impl<'tree> IntoIterator for &'tree TapTree { + type Item = (u8, &'tree Script); + type IntoIter = TapTreeIter<'tree>; + + fn into_iter(self) -> Self::IntoIter { + match (self.0.branch().len(), self.0.branch().last()) { + (1, Some(Some(root))) => { + TapTreeIter { + leaf_iter: root.leaves.iter() + } + } + // This should be unreachable as we Taptree is already finalized + _ => unreachable!("non-finalized tree builder inside TapTree"), + } + } } impl Output { From ec17ec356d1d1e1ddf3ec6b903c3958ffd512131 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Thu, 24 Mar 2022 14:54:58 -0700 Subject: [PATCH 03/40] Move with_huffman_tree logic to TaprootBuilder --- src/util/taproot.rs | 93 ++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index cb9950db7e..7da73a7078 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -191,24 +191,9 @@ pub struct TaprootSpendInfo { } impl TaprootSpendInfo { - /// Create a new [`TaprootSpendInfo`] from a list of script(with default script version) and - /// weights of satisfaction for that script. The weights represent the probability of - /// each branch being taken. If probabilities/weights for each condition are known, - /// constructing the tree as a Huffman tree is the optimal way to minimize average - /// case satisfaction cost. This function takes input an iterator of tuple(u64, &Script) - /// where usize represents the satisfaction weights of the branch. - /// For example, [(3, S1), (2, S2), (5, S3)] would construct a TapTree that has optimal - /// satisfaction weight when probability for S1 is 30%, S2 is 20% and S3 is 50%. - /// - /// # Errors: - /// - /// - When the optimal huffman tree has a depth more than 128 - /// - If the provided list of script weights is empty + /// Create a new [`TaprootSpendInfo`] from a list of script(with default script version). /// - /// # Edge Cases: - /// - If the script weight calculations overflow, a sub-optimal tree may be generated. This - /// should not happen unless you are dealing with billions of branches with weights close to - /// 2^32. + /// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation pub fn with_huffman_tree( secp: &Secp256k1, internal_key: UntweakedPublicKey, @@ -218,29 +203,7 @@ impl TaprootSpendInfo { I: IntoIterator, C: secp256k1::Verification, { - let mut node_weights = BinaryHeap::<(Reverse, NodeInfo)>::new(); - for (p, leaf) in script_weights { - node_weights.push((Reverse(p as u64), NodeInfo::new_leaf_with_ver(leaf, LeafVersion::TapScript))); - } - if node_weights.is_empty() { - return Err(TaprootBuilderError::IncompleteTree); - } - while node_weights.len() > 1 { - // Combine the last two elements and insert a new node - let (p1, s1) = node_weights.pop().expect("len must be at least two"); - let (p2, s2) = node_weights.pop().expect("len must be at least two"); - // Insert the sum of first two in the tree as a new node - // N.B.: p1 + p2 can not practically saturate as you would need to have 2**32 max u32s - // from the input to overflow. However, saturating is a reasonable behavior here as - // huffman tree construction would treat all such elements as "very likely". - let p = Reverse(p1.0.saturating_add(p2.0)); - node_weights.push((p, NodeInfo::combine(s1, s2)?)); - } - // Every iteration of the loop reduces the node_weights.len() by exactly 1 - // Therefore, the loop will eventually terminate with exactly 1 element - debug_assert!(node_weights.len() == 1); - let node = node_weights.pop().expect("huffman tree algorithm is broken").1; - return Ok(Self::from_node_info(secp, internal_key, node)); + TaprootBuilder::with_huffman_tree(script_weights)?.finalize(secp, internal_key) } /// Create a new key spend with internal key and proided merkle root. @@ -396,6 +359,56 @@ impl TaprootBuilder { pub fn new() -> Self { TaprootBuilder { branch: vec![] } } + + /// Create a new [`TaprootBuilder`] from a list of script(with default script version) and + /// weights of satisfaction for that script. The weights represent the probability of + /// each branch being taken. If probabilities/weights for each condition are known, + /// constructing the tree as a Huffman tree is the optimal way to minimize average + /// case satisfaction cost. This function takes input an iterator of tuple(u64, &Script) + /// where usize represents the satisfaction weights of the branch. + /// For example, [(3, S1), (2, S2), (5, S3)] would construct a TapTree that has optimal + /// satisfaction weight when probability for S1 is 30%, S2 is 20% and S3 is 50%. + /// + /// # Errors: + /// + /// - When the optimal huffman tree has a depth more than 128 + /// - If the provided list of script weights is empty + /// + /// # Edge Cases: + /// - If the script weight calculations overflow, a sub-optimal tree may be generated. This + /// should not happen unless you are dealing with billions of branches with weights close to + /// 2^32. + pub fn with_huffman_tree( + script_weights: I, + ) -> Result + where + I: IntoIterator, + { + let mut node_weights = BinaryHeap::<(Reverse, NodeInfo)>::new(); + for (p, leaf) in script_weights { + node_weights.push((Reverse(p as u64), NodeInfo::new_leaf_with_ver(leaf, LeafVersion::TapScript))); + } + if node_weights.is_empty() { + return Err(TaprootBuilderError::IncompleteTree); + } + while node_weights.len() > 1 { + // Combine the last two elements and insert a new node + let (p1, s1) = node_weights.pop().expect("len must be at least two"); + let (p2, s2) = node_weights.pop().expect("len must be at least two"); + // Insert the sum of first two in the tree as a new node + // N.B.: p1 + p2 can not practically saturate as you would need to have 2**32 max u32s + // from the input to overflow. However, saturating is a reasonable behavior here as + // huffman tree construction would treat all such elements as "very likely". + let p = Reverse(p1.0.saturating_add(p2.0)); + node_weights.push((p, NodeInfo::combine(s1, s2)?)); + } + // Every iteration of the loop reduces the node_weights.len() by exactly 1 + // Therefore, the loop will eventually terminate with exactly 1 element + debug_assert!(node_weights.len() == 1); + let node = node_weights.pop().expect("huffman tree algorithm is broken").1; + Ok(TaprootBuilder{branch: vec![Some(node)]}) + } + /// Just like [`TaprootBuilder::add_leaf`] but allows to specify script version pub fn add_leaf_with_ver( self, From 2bd71c37487c70a08e5c7d8a5eaed235230d293e Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 22 Feb 2022 18:56:13 +0000 Subject: [PATCH 04/40] Remove From for u32 We have conversion functions that include suffixes `_consensus` and `_standard` to make it explicit what guarantees are provided by the returned `u32` value. The `From` implementation reduces the clarity of the API. --- src/blockdata/transaction.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index a84bcac5ce..224d90d4bc 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -859,12 +859,6 @@ impl EcdsaSigHashType { pub fn as_u32(self) -> u32 { self as u32 } } -impl From for u32 { - fn from(t: EcdsaSigHashType) -> u32 { - t.as_u32() - } -} - /// Error returned when parsing `SigHashType` fails. /// /// This is currently returned for unrecognized sighash strings. From d1753d7ff1200b78f76cb2c18c5600d57c3057f9 Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 22 Feb 2022 18:02:37 +0000 Subject: [PATCH 05/40] Rename as_u32 -> to_u32 Rust naming conventions stipulate that conversion methods from owned -> owned for `Copy` types use the naming convention `to_`. This change makes the function name objectively better, however it makes no claims of being the 'best' name. We have had much discussion on using `to_standard` vs `to_u32` but are unable to reach consensus. --- src/blockdata/transaction.rs | 6 ++++-- src/util/sighash.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 224d90d4bc..b1015f1398 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -855,8 +855,10 @@ impl EcdsaSigHashType { } } - /// Converts to a u32 - pub fn as_u32(self) -> u32 { self 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. diff --git a/src/util/sighash.rs b/src/util/sighash.rs index 33cb5bb0a6..4a267f6137 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -600,7 +600,7 @@ impl> SigHashCache { } self.tx.lock_time.consensus_encode(&mut writer)?; - sighash_type.as_u32().consensus_encode(&mut writer)?; + sighash_type.to_u32().consensus_encode(&mut writer)?; Ok(()) } From 564682627cb744fa6f88bb66cfa1b92b29642b0d Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Fri, 25 Feb 2022 08:50:45 +0000 Subject: [PATCH 06/40] Remove deprecated conversion method `EcdsaSigHashType::from_u32` was deprecated in v0.26, since we are working on the v0.28 release we can drop this method. --- src/blockdata/transaction.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index b1015f1398..70260420e5 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -806,12 +806,6 @@ impl EcdsaSigHashType { } } - /// 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) - } - /// Reads a 4-byte uint32 as a sighash type. /// /// **Note**: this replicates consensus behaviour, for current standardness rules correctness @@ -1190,7 +1184,6 @@ 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); // But it's policy-invalid to use it! assert_eq!(EcdsaSigHashType::from_u32_standard(nonstandard_hashtype), Err(NonStandardSigHashType(0x04))); From ac462897b1bc7ac6863a2b85ca7732e030838189 Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Fri, 25 Feb 2022 08:59:54 +0000 Subject: [PATCH 07/40] Remove hungarian-ish notation The functions `from_u32_standard` and `from_u32_consensus` smell a bit like hungarian notation. We can look at the method definition to see that the methods accept `u32` arguments without mentioning that in the method names. Remove `_u32_` from the method names. This brings the `from_*` methods in line with the `to_standard` method also. --- src/blockdata/transaction.rs | 34 +++++++++++++++++++++++++--------- src/util/ecdsa.rs | 4 ++-- src/util/psbt/map/input.rs | 2 +- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 70260420e5..e5fb7c05b0 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -444,7 +444,7 @@ impl Transaction { } fn is_invalid_use_of_sighash_single(&self, sighash: u32, input_index: usize) -> bool { - let ty = EcdsaSigHashType::from_u32_consensus(sighash); + let ty = EcdsaSigHashType::from_consensus(sighash); ty == EcdsaSigHashType::Single && input_index >= self.output.len() } @@ -806,15 +806,22 @@ impl EcdsaSigHashType { } } - /// Reads a 4-byte uint32 as a sighash type. + /// 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) + } + + /// 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. @@ -834,9 +841,18 @@ impl EcdsaSigHashType { } } - /// Read a 4-byte uint32 as a standard sighash type, returning an error if the type - /// is non standard. + /// 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), diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 5a04b1cc9b..e4861769d9 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -47,7 +47,7 @@ impl EcdsaSig { 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) + 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)?; @@ -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)? }) } } diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index e89fa9c953..9d275cbe3f 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -171,7 +171,7 @@ impl PsbtSigHashType { /// Returns the [`EcdsaSigHashType`] if the [`PsbtSigHashType`] can be /// converted to one. pub fn ecdsa_hash_ty(self) -> Result { - EcdsaSigHashType::from_u32_standard(self.inner) + EcdsaSigHashType::from_standard(self.inner) } /// Returns the [`SchnorrSigHashType`] if the [`PsbtSigHashType`] can be From e05776f176afacf8088f2fb3b07967544d444ce4 Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 22 Feb 2022 19:34:26 +0000 Subject: [PATCH 08/40] Improve PsbtSigHashType conversion methods Improve the `PsbtSigHashType` conversion methods by doing: - Re-name `inner` -> `to_u32` as per Rust convention - Add `from_u32` method Note, we explicitly do _not_ use suffix 'consensus' because these conversion methods make no guarantees about the validity of the underlying `u32`. --- src/util/psbt/map/input.rs | 15 +++++++++++++-- src/util/psbt/serialize.rs | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index 9d275cbe3f..e71328347d 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -184,8 +184,19 @@ impl PsbtSigHashType { } } - /// Obtains the inner sighash byte from this [`PsbtSigHashType`]. - pub fn inner(self) -> u32 { + /// Creates a [`PsbtSigHashType`] from a raw `u32`. + /// + /// Allows construction of a non-standard or non-valid sighash flag + /// ([`EcdsaSigHashType`], [`SchnorrSigHashType`] respectively). + pub fn from_u32(n: u32) -> PsbtSigHashType { + PsbtSigHashType { inner: n } + } + + + /// Converts [`PsbtSigHashType`] to a raw `u32` sighash flag. + /// + /// No guarantees are made as to the standardness or validity of the returned value. + pub fn to_u32(self) -> u32 { self.inner } } diff --git a/src/util/psbt/serialize.rs b/src/util/psbt/serialize.rs index 0ee01fdff0..8492e8af19 100644 --- a/src/util/psbt/serialize.rs +++ b/src/util/psbt/serialize.rs @@ -193,7 +193,7 @@ impl Deserialize for Vec { impl Serialize for PsbtSigHashType { fn serialize(&self) -> Vec { - serialize(&self.inner()) + serialize(&self.to_u32()) } } From 8e2422f92bcc8f7b8264d262c166826afe8a93ca Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Fri, 25 Feb 2022 10:07:49 +0000 Subject: [PATCH 09/40] Add unit test for deserialize non-standard sighash It is possible, although not immediately obvious, that it is possible to create a `PsbtSigHashType` with a non-standard value. Add a unit test to show this and also catch any regressions if we accidental change this logic. --- src/util/psbt/serialize.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/util/psbt/serialize.rs b/src/util/psbt/serialize.rs index 8492e8af19..bb1443a597 100644 --- a/src/util/psbt/serialize.rs +++ b/src/util/psbt/serialize.rs @@ -367,3 +367,15 @@ impl Deserialize for TapTree { fn key_source_len(key_source: &KeySource) -> usize { 4 + 4 * (key_source.1).as_ref().len() } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_deserialize_non_standard_psbt_sig_hash_type() { + let non_standard_sighash = [222u8, 0u8, 0u8, 0u8]; // 32 byte value. + let sighash = PsbtSigHashType::deserialize(&non_standard_sighash); + assert!(sighash.is_ok()) + } +} From 208eb65f1b02b4f9b55b8246354fb5d29bbbd5ba Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Sat, 26 Mar 2022 22:01:31 -0700 Subject: [PATCH 10/40] Make NodeInfo API public This allows users to create TaprootSpendInfo using NodeInfo. This offers an alternative to TaprootBuilder. --- src/util/taproot.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index cb9950db7e..b137102349 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -296,8 +296,10 @@ impl TaprootSpendInfo { self.output_key_parity } - // Internal function to compute [`TaprootSpendInfo`] from NodeInfo - fn from_node_info( + /// Compute [`TaprootSpendInfo`] from [`NodeInfo`], and internal key. + /// This is useful when you want to manually build a taproot tree wihtout + /// using [`TaprootBuilder`]. + pub fn from_node_info( secp: &Secp256k1, internal_key: UntweakedPublicKey, node: NodeInfo, @@ -497,10 +499,12 @@ impl TaprootBuilder { } } -// Internally used structure to represent the node information in taproot tree +/// Data structure used to represent node information in taproot tree. +/// You can use [`TaprootSpendInfo::from_node_info`] to a get [`TaprootSpendInfo`] +/// from the merkle root [`NodeInfo`]. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub(crate) struct NodeInfo { +pub struct NodeInfo { /// Merkle Hash for this node pub(crate) hash: sha256::Hash, /// information about leaves inside this node @@ -508,16 +512,16 @@ pub(crate) struct NodeInfo { } impl NodeInfo { - // Create a new NodeInfo with omitted/hidden info - fn new_hidden(hash: sha256::Hash) -> Self { + /// Creates a new [`NodeInfo`] with omitted/hidden info. + pub fn new_hidden(hash: sha256::Hash) -> Self { Self { hash: hash, leaves: vec![], } } - // Create a new leaf with NodeInfo - fn new_leaf_with_ver(script: Script, ver: LeafVersion) -> Self { + /// Creates a new leaf [`NodeInfo`] with given [`Script`] and [`LeafVersion`]. + pub fn new_leaf_with_ver(script: Script, ver: LeafVersion) -> Self { let leaf = LeafInfo::new(script, ver); Self { hash: leaf.hash(), @@ -525,8 +529,8 @@ impl NodeInfo { } } - // Combine two NodeInfo's to create a new parent - fn combine(a: Self, b: Self) -> Result { + /// Combines two [`NodeInfo`] to create a new parent. + pub fn combine(a: Self, b: Self) -> Result { let mut all_leaves = Vec::with_capacity(a.leaves.len() + b.leaves.len()); for mut a_leaf in a.leaves { a_leaf.merkle_branch.push(b.hash)?; // add hashing partner From c3d30d51a79e21446730dcb69813469a88bc3c50 Mon Sep 17 00:00:00 2001 From: "Dr. Maxim Orlovsky" Date: Mon, 28 Mar 2022 09:54:13 +0200 Subject: [PATCH 11/40] Remove deprecated method use for sighash conversion Post-merge #796 follow-up. Feel free to add other changes/nits which hadn't get into #796. --- src/blockdata/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index e5fb7c05b0..a76953445b 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -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 { From 7cdcdaad6c4232e15e03cab4bdfc16ba5af4ee85 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 27 Mar 2022 15:01:08 +0200 Subject: [PATCH 12/40] Support SIGHASH_RESERVED in SchnorrSigHashType::from_u8 --- src/util/sighash.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/sighash.rs b/src/util/sighash.rs index 33cb5bb0a6..7e6936b2c0 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -326,6 +326,7 @@ impl SchnorrSigHashType { 0x81 => Ok(SchnorrSigHashType::AllPlusAnyoneCanPay), 0x82 => Ok(SchnorrSigHashType::NonePlusAnyoneCanPay), 0x83 => Ok(SchnorrSigHashType::SinglePlusAnyoneCanPay), + 0xFF => Ok(SchnorrSigHashType::Reserved), x => Err(Error::InvalidSigHashType(x as u32)), } } From 5be1cdb8c75f0927ecceef02416f063f593e4168 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 24 Mar 2022 07:22:28 +0100 Subject: [PATCH 13/40] PsbtSigHashType Display and FromStr implementation --- src/blockdata/transaction.rs | 2 +- src/util/psbt/map/input.rs | 38 +++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index f625d7e163..6bcfd5c04b 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -758,7 +758,7 @@ impl str::FromStr for EcdsaSigHashType { "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() }), + _ => Err(SigHashTypeParseError { unrecognized: s.to_owned() }), } } } diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index e89fa9c953..3bcbea1f99 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; @@ -155,6 +157,40 @@ pub struct PsbtSigHashType { pub (in ::util::psbt) inner: u32, } +impl fmt::Display for PsbtSigHashType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.schnorr_hash_ty() { + Ok(SchnorrSigHashType::Reserved) | Err(_) => write!(f, "{:#x}", self.inner), + Ok(schnorr_hash_ty) => fmt::Display::fmt(&schnorr_hash_ty, f), + } + } +} + +impl FromStr for PsbtSigHashType { + type Err = SigHashTypeParseError; + + #[inline] + fn from_str(s: &str) -> Result { + // We accept strings of form: "SIGHASH_ALL" etc. + // + // NB: some of Schnorr sighash types are non-standard for pre-taproot + // inputs. We also do not support SIGHASH_RESERVED in verbatim form + // ("0xFF" string should be used instead). + match SchnorrSigHashType::from_str(s) { + Ok(SchnorrSigHashType::Reserved) => return Err(SigHashTypeParseError{ unrecognized: s.to_owned() }), + Ok(ty) => return Ok(ty.into()), + Err(_) => {} + } + + // We accept non-standard sighash values. + // TODO: Swap `trim_left_matches` for `trim_start_matches` once MSRV >= 1.30. + if let Ok(inner) = u32::from_str_radix(s.trim_left_matches("0x"), 16) { + return Ok(PsbtSigHashType { inner }); + } + + Err(SigHashTypeParseError{ unrecognized: s.to_owned() }) + } +} impl From for PsbtSigHashType { fn from(ecdsa_hash_ty: EcdsaSigHashType) -> Self { PsbtSigHashType { inner: ecdsa_hash_ty as u32 } From 992857ad0a8bf8a0c6c5ad3d0259404792dabb24 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 26 Mar 2022 02:37:30 +0100 Subject: [PATCH 14/40] PsbtSighashType unit tests --- src/util/psbt/map/input.rs | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index 3bcbea1f99..6d90d559a6 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -525,3 +525,71 @@ where btree_map::Entry::Occupied(_) => Err(psbt::Error::DuplicateKey(raw_key).into()), } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn psbt_sighash_type_ecdsa() { + for ecdsa in &[ + EcdsaSigHashType::All, + EcdsaSigHashType::None, + EcdsaSigHashType::Single, + EcdsaSigHashType::AllPlusAnyoneCanPay, + EcdsaSigHashType::NonePlusAnyoneCanPay, + EcdsaSigHashType::SinglePlusAnyoneCanPay, + ] { + let sighash = PsbtSigHashType::from(*ecdsa); + let s = format!("{}", sighash); + let back = PsbtSigHashType::from_str(&s).unwrap(); + assert_eq!(back, sighash); + assert_eq!(back.ecdsa_hash_ty().unwrap(), *ecdsa); + } + } + + #[test] + fn psbt_sighash_type_schnorr() { + for schnorr in &[ + SchnorrSigHashType::Default, + SchnorrSigHashType::All, + SchnorrSigHashType::None, + SchnorrSigHashType::Single, + SchnorrSigHashType::AllPlusAnyoneCanPay, + SchnorrSigHashType::NonePlusAnyoneCanPay, + SchnorrSigHashType::SinglePlusAnyoneCanPay, + ] { + let sighash = PsbtSigHashType::from(*schnorr); + let s = format!("{}", sighash); + let back = PsbtSigHashType::from_str(&s).unwrap(); + assert_eq!(back, sighash); + assert_eq!(back.schnorr_hash_ty().unwrap(), *schnorr); + } + } + + #[test] + fn psbt_sighash_type_schnorr_notstd() { + for (schnorr, schnorr_str) in &[ + (SchnorrSigHashType::Reserved, "0xff"), + ] { + let sighash = PsbtSigHashType::from(*schnorr); + let s = format!("{}", sighash); + assert_eq!(&s, schnorr_str); + let back = PsbtSigHashType::from_str(&s).unwrap(); + assert_eq!(back, sighash); + assert_eq!(back.schnorr_hash_ty().unwrap(), *schnorr); + } + } + + #[test] + fn psbt_sighash_type_notstd() { + let nonstd = 0xdddddddd; + let sighash = PsbtSigHashType { inner: nonstd }; + let s = format!("{}", sighash); + let back = PsbtSigHashType::from_str(&s).unwrap(); + + assert_eq!(back, sighash); + assert_eq!(back.ecdsa_hash_ty(), Err(NonStandardSigHashType(nonstd))); + assert_eq!(back.schnorr_hash_ty(), Err(sighash::Error::InvalidSigHashType(nonstd))); + } +} From 8dabe3ed64f450fb15832b8332370f10ad62da25 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 28 Mar 2022 17:15:28 +0200 Subject: [PATCH 15/40] Taproot Huffman tree builder u64->u32 fixes --- src/util/taproot.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index 10a9f1f4cf..019f3efd16 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -367,8 +367,8 @@ impl TaprootBuilder { /// weights of satisfaction for that script. The weights represent the probability of /// each branch being taken. If probabilities/weights for each condition are known, /// constructing the tree as a Huffman tree is the optimal way to minimize average - /// case satisfaction cost. This function takes input an iterator of tuple(u64, &Script) - /// where usize represents the satisfaction weights of the branch. + /// case satisfaction cost. This function takes an iterator of (`u32`, &[`Script`]) tuples + /// as an input, where `u32` represents the satisfaction weights of the script branch. /// For example, [(3, S1), (2, S2), (5, S3)] would construct a TapTree that has optimal /// satisfaction weight when probability for S1 is 30%, S2 is 20% and S3 is 50%. /// @@ -387,9 +387,9 @@ impl TaprootBuilder { where I: IntoIterator, { - let mut node_weights = BinaryHeap::<(Reverse, NodeInfo)>::new(); + let mut node_weights = BinaryHeap::<(Reverse, NodeInfo)>::new(); for (p, leaf) in script_weights { - node_weights.push((Reverse(p as u64), NodeInfo::new_leaf_with_ver(leaf, LeafVersion::TapScript))); + node_weights.push((Reverse(p), NodeInfo::new_leaf_with_ver(leaf, LeafVersion::TapScript))); } if node_weights.is_empty() { return Err(TaprootBuilderError::IncompleteTree); @@ -407,7 +407,7 @@ impl TaprootBuilder { } // Every iteration of the loop reduces the node_weights.len() by exactly 1 // Therefore, the loop will eventually terminate with exactly 1 element - debug_assert!(node_weights.len() == 1); + debug_assert_eq!(node_weights.len(), 1); let node = node_weights.pop().expect("huffman tree algorithm is broken").1; Ok(TaprootBuilder{branch: vec![Some(node)]}) } From b3e612a154cd560e897c086f8df1e55872e96a67 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 28 Mar 2022 10:34:06 -0700 Subject: [PATCH 16/40] Remove misc whitespace --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 0d29c8388d4b02ff87edbf2089265c8363f221f2 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Mon, 28 Mar 2022 10:41:12 -0700 Subject: [PATCH 17/40] rust-bitcoin 0.28.0-rc.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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/" From df3297c34ecf01a78f31c428b05ae2b4883c914d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 28 Mar 2022 21:27:51 +0200 Subject: [PATCH 18/40] Implement derives for TweakedKeyPair --- src/util/schnorr.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/util/schnorr.rs b/src/util/schnorr.rs index 535abb9831..b5bbe0f8ef 100644 --- a/src/util/schnorr.rs +++ b/src/util/schnorr.rs @@ -60,9 +60,8 @@ impl fmt::Display for TweakedPublicKey { pub type UntweakedKeyPair = ::KeyPair; /// Tweaked BIP-340 key pair -#[derive(Clone)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "std", derive(Debug))] -// TODO: Add other derives once secp256k1 v0.21.3 released pub struct TweakedKeyPair(::KeyPair); /// A trait for tweaking BIP340 key types (x-only public keys and key pairs). From 174a99cd06a26d3ca6499a95e44e97f400c12362 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Mon, 28 Mar 2022 21:29:04 +0200 Subject: [PATCH 19/40] Implement serde for TweakedKeyPair --- src/util/schnorr.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/schnorr.rs b/src/util/schnorr.rs index b5bbe0f8ef..8542915f7d 100644 --- a/src/util/schnorr.rs +++ b/src/util/schnorr.rs @@ -60,8 +60,9 @@ impl fmt::Display for TweakedPublicKey { pub type UntweakedKeyPair = ::KeyPair; /// Tweaked BIP-340 key pair -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] pub struct TweakedKeyPair(::KeyPair); /// A trait for tweaking BIP340 key types (x-only public keys and key pairs). From 8631474f08becc832161540e28069c5f8e585b35 Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Mon, 28 Mar 2022 14:07:07 +1100 Subject: [PATCH 20/40] Improve docs in taproot module As has been done in other places in the codebase; improve the docs in the `taproot` module by doing: - Use full sentences (capital letters + full stops) - Use back ticks and links for types where appropriate - Fix grammar - Fix stale docs - Use third person for describing functions - Use 100 character line width - Use markdown sections (`# Examples`, `# Returns`) where appropriate - Separate brief heading from extended description when appropriate - Use `///` for all functions/types (both private and public) I also did: - Build the docs and check all the links - Read all the built docs, check for sanity and pretty-ness --- src/util/taproot.rs | 366 +++++++++++++++++++++++--------------------- 1 file changed, 195 insertions(+), 171 deletions(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index 019f3efd16..a3a01a7406 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -53,7 +53,7 @@ const MIDSTATE_TAPTWEAK: [u8; 32] = [ ]; // d129a2f3701c655d6583b6c3b941972795f4e23294fd54f4a2ae8d8547ca590b -/// The SHA-256 midstate value for the TapSigHash hash. +/// The SHA-256 midstate value for the [`TapSighashHash`]. const MIDSTATE_TAPSIGHASH: [u8; 32] = [ 245, 4, 164, 37, 215, 248, 120, 59, 19, 99, 134, 138, 227, 229, 86, 88, 110, 238, 148, 93, 188, 120, 136, 221, 2, 166, 226, 195, 24, 115, 254, 159, @@ -99,8 +99,8 @@ sha256t_hash_newtype!(TapSighashHash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64, ); impl TapTweakHash { - /// Create a new BIP341 [`TapTweakHash`] from key and tweak - /// Produces H_taptweak(P||R) where P is internal key and R is the merkle root + /// Creates a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where + /// `P` is the internal key and `R` is the merkle root. pub fn from_key_and_tweak( internal_key: UntweakedPublicKey, merkle_root: Option, @@ -118,7 +118,7 @@ impl TapTweakHash { } impl TapLeafHash { - /// function to compute leaf hash from components + /// Computes the leaf hash from components. pub fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash { let mut eng = TapLeafHash::engine(); ver.to_consensus() @@ -131,24 +131,24 @@ impl TapLeafHash { } } -/// Maximum depth of a Taproot Tree Script spend path +/// Maximum depth of a taproot tree script spend path. // https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L229 pub const TAPROOT_CONTROL_MAX_NODE_COUNT: usize = 128; -/// Size of a taproot control node +/// Size of a taproot control node. // https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L228 pub const TAPROOT_CONTROL_NODE_SIZE: usize = 32; -/// Tapleaf mask for getting the leaf version from first byte of control block +/// Tapleaf mask for getting the leaf version from first byte of control block. // https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L225 pub const TAPROOT_LEAF_MASK: u8 = 0xfe; -/// Tapscript leaf version +/// Tapscript leaf version. // https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L226 pub const TAPROOT_LEAF_TAPSCRIPT: u8 = 0xc0; -/// Taproot annex prefix +/// Taproot annex prefix. pub const TAPROOT_ANNEX_PREFIX: u8 = 0x50; -/// Tapscript control base size +/// Tapscript control base size. // https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L227 pub const TAPROOT_CONTROL_BASE_SIZE: usize = 33; -/// Tapscript control max size +/// Tapscript control max size. // https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L230 pub const TAPROOT_CONTROL_MAX_SIZE: usize = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT; @@ -156,45 +156,48 @@ pub const TAPROOT_CONTROL_MAX_SIZE: usize = // type alias for versioned tap script corresponding merkle proof type ScriptMerkleProofMap = BTreeMap<(Script, LeafVersion), BTreeSet>; -/// Data structure for representing Taproot spending information. -/// Taproot output corresponds to a combination of a -/// single public key condition (known the internal key), and zero or more -/// general conditions encoded in scripts organized in the form of a binary tree. +/// Represents taproot spending information. /// -/// Taproot can be spent be either: -/// - Spending using the key path i.e., with secret key corresponding to the output_key -/// - By satisfying any of the scripts in the script spent path. Each script can be satisfied by providing -/// a witness stack consisting of the script's inputs, plus the script itself and the control block. +/// Taproot output corresponds to a combination of a single public key condition (known as the +/// internal key), and zero or more general conditions encoded in scripts organized in the form of a +/// binary tree. /// -/// If one or more of the spending conditions consist of just a single key (after aggregation), -/// the most likely one should be made the internal key. -/// See [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) for more details -/// on choosing internal keys for a taproot application +/// Taproot can be spent by either: +/// - Spending using the key path i.e., with secret key corresponding to the tweaked `output_key`. +/// - By satisfying any of the scripts in the script spend path. Each script can be satisfied by +/// providing a witness stack consisting of the script's inputs, plus the script itself and the +/// control block. /// -/// Note: This library currently does not support [annex](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-5) +/// If one or more of the spending conditions consist of just a single key (after aggregation), the +/// most likely key should be made the internal key. +/// See [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) for more details on +/// choosing internal keys for a taproot application. +/// +/// Note: This library currently does not support +/// [annex](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-5). #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TaprootSpendInfo { /// The BIP341 internal key. internal_key: UntweakedPublicKey, - /// The Merkle root of the script tree (None if there are no scripts) + /// The merkle root of the script tree (None if there are no scripts). merkle_root: Option, - /// The sign final output pubkey as per BIP 341 + /// The sign final output pubkey as per BIP 341. output_key_parity: secp256k1::Parity, - /// The tweaked output key + /// The tweaked output key. output_key: TweakedPublicKey, - /// Map from (script, leaf_version) to (sets of) [`TaprootMerkleBranch`]. - /// More than one control block for a given script is only possible if it - /// appears in multiple branches of the tree. In all cases, keeping one should - /// be enough for spending funds, but we keep all of the paths so that - /// a full tree can be constructed again from spending data if required. + /// Map from (script, leaf_version) to (sets of) [`TaprootMerkleBranch`]. More than one control + /// block for a given script is only possible if it appears in multiple branches of the tree. In + /// all cases, keeping one should be enough for spending funds, but we keep all of the paths so + /// that a full tree can be constructed again from spending data if required. script_map: ScriptMerkleProofMap, } impl TaprootSpendInfo { - /// Create a new [`TaprootSpendInfo`] from a list of script(with default script version). + /// Creates a new [`TaprootSpendInfo`] from a list of scripts (with default script version) and + /// weights of satisfaction for that script. /// - /// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation + /// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation. pub fn with_huffman_tree( secp: &Secp256k1, internal_key: UntweakedPublicKey, @@ -207,18 +210,17 @@ impl TaprootSpendInfo { TaprootBuilder::with_huffman_tree(script_weights)?.finalize(secp, internal_key) } - /// Create a new key spend with internal key and proided merkle root. - /// Provide [`None`] for merkle_root if there is no script path. + /// Creates a new key spend with `internal_key` and `merkle_root`. Provide [`None`] for + /// `merkle_root` if there is no script path. /// /// *Note*: As per BIP341 /// - /// When the merkle root is [`None`], the output key commits to an unspendable - /// script path instead of having no script path. This is achieved by computing - /// the output key point as Q = P + int(hashTapTweak(bytes(P)))G. - /// See also [`TaprootSpendInfo::tap_tweak`]. - /// Refer to BIP 341 footnote (Why should the output key always have - /// a taproot commitment, even if there is no script path?) for more details + /// When the merkle root is [`None`], the output key commits to an unspendable script path + /// instead of having no script path. This is achieved by computing the output key point as + /// `Q = P + int(hashTapTweak(bytes(P)))G`. See also [`TaprootSpendInfo::tap_tweak`]. /// + /// Refer to BIP 341 footnote ('Why should the output key always have a taproot commitment, even + /// if there is no script path?') for more details. pub fn new_key_spend( secp: &Secp256k1, internal_key: UntweakedPublicKey, @@ -234,35 +236,36 @@ impl TaprootSpendInfo { } } - /// Obtain the tweak and parity used to compute the output_key + /// Returns the `TapTweakHash` for this [`TaprootSpendInfo`] i.e., the tweak using `internal_key` + /// and `merkle_root`. pub fn tap_tweak(&self) -> TapTweakHash { TapTweakHash::from_key_and_tweak(self.internal_key, self.merkle_root) } - /// Obtain the internal key + /// Returns the internal key for this [`TaprootSpendInfo`]. pub fn internal_key(&self) -> UntweakedPublicKey { self.internal_key } - /// Obtain the merkle root + /// Returns the merkle root for this [`TaprootSpendInfo`]. pub fn merkle_root(&self) -> Option { self.merkle_root } - /// Output key(the key used in script pubkey) from Spend data. See also - /// [`TaprootSpendInfo::output_key_parity`] + /// Returns the output key (the key used in script pubkey) for this [`TaprootSpendInfo`]. pub fn output_key(&self) -> TweakedPublicKey { self.output_key } - /// Parity of the output key. See also [`TaprootSpendInfo::output_key`] + /// Returns the parity of the output key. See also [`TaprootSpendInfo::output_key`]. pub fn output_key_parity(&self) -> secp256k1::Parity { self.output_key_parity } - /// Compute [`TaprootSpendInfo`] from [`NodeInfo`], and internal key. - /// This is useful when you want to manually build a taproot tree wihtout - /// using [`TaprootBuilder`]. + /// Computes the [`TaprootSpendInfo`] from `internal_key` and `node`. + /// + /// This is useful when you want to manually build a taproot tree without using + /// [`TaprootBuilder`]. pub fn from_node_info( secp: &Secp256k1, internal_key: UntweakedPublicKey, @@ -288,14 +291,17 @@ impl TaprootSpendInfo { info } - /// Access the internal script map + /// Returns the internal script map. pub fn as_script_map(&self) -> &ScriptMerkleProofMap { &self.script_map } - /// Obtain a [`ControlBlock`] for particular script with the given version. - /// Returns [`None`] if the script is not contained in the [`TaprootSpendInfo`] - /// If there are multiple ControlBlocks possible, this returns the shortest one. + /// Constructs a [`ControlBlock`] for particular script with the given version. + /// + /// # Returns + /// + /// - If there are multiple control blocks possible, returns the shortest one. + /// - If the script is not contained in the [`TaprootSpendInfo`], returns `None`. pub fn control_block(&self, script_ver: &(Script, LeafVersion)) -> Option { let merkle_branch_set = self.script_map.get(script_ver)?; // Choose the smallest one amongst the multiple script maps @@ -312,22 +318,23 @@ impl TaprootSpendInfo { } } -/// Builder for building taproot iteratively. Users can specify tap leaf or omitted/hidden -/// branches in a DFS(Depth first search) walk to construct this tree. -// Similar to Taproot Builder in bitcoin core +/// Builder for building taproot iteratively. Users can specify tap leaf or omitted/hidden branches +/// in a depth-first search (DFS) walk order to construct this tree. +/// +/// See Wikipedia for more details on [DFS](https://en.wikipedia.org/wiki/Depth-first_search). +// Similar to Taproot Builder in bitcoin core. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TaprootBuilder { - // The following doc-comment is from bitcoin core, but modified for rust - // The comment below describes the current state of the builder for a given tree. + // The following doc-comment is from bitcoin core, but modified for Rust. It describes the + // current state of the builder for a given tree. // - // For each level in the tree, one NodeInfo object may be present. branch at index 0 - // is information about the root; further values are for deeper subtrees being - // explored. + // For each level in the tree, one NodeInfo object may be present. Branch at index 0 is + // information about the root; further values are for deeper subtrees being explored. // - // During the construction of Taptree, for every right branch taken to - // reach the position we're currently working in, there will be a (Some(_)) - // entry in branch corresponding to the left branch at that level. + // During the construction of Taptree, for every right branch taken to reach the position we're + // currently working on, there will be a `(Some(_))` entry in branch corresponding to the left + // branch at that level. // // For example, imagine this tree: - N0 - // / \ @@ -337,50 +344,50 @@ pub struct TaprootBuilder { // / \ // D E // - // Initially, branch is empty. After processing leaf A, it would become - // {None, None, A}. When processing leaf B, an entry at level 2 already - // exists, and it would thus be combined with it to produce a level 1 one, - // resulting in {None, N1}. Adding C and D takes us to {None, N1, C} - // and {None, N1, C, D} respectively. When E is processed, it is combined - // with D, and then C, and then N1, to produce the root, resulting in {N0}. - // - // This structure allows processing with just O(log n) overhead if the leaves - // are computed on the fly. + // Initially, branch is empty. After processing leaf A, it would become {None, None, A}. When + // processing leaf B, an entry at level 2 already exists, and it would thus be combined with it + // to produce a level 1 entry, resulting in {None, N1}. Adding C and D takes us to {None, N1, C} + // and {None, N1, C, D} respectively. When E is processed, it is combined with D, and then C, + // and then N1, to produce the root, resulting in {N0}. // - // As an invariant, there can never be None entries at the end. There can - // also not be more than 128 entries (as that would mean more than 128 levels - // in the tree). The depth of newly added entries will always be at least - // equal to the current size of branch (otherwise it does not correspond - // to a depth-first traversal of a tree). branch is only empty if no entries - // have ever be processed. branch having length 1 corresponds to being done. + // This structure allows processing with just O(log n) overhead if the leaves are computed on + // the fly. // + // As an invariant, there can never be None entries at the end. There can also not be more than + // 128 entries (as that would mean more than 128 levels in the tree). The depth of newly added + // entries will always be at least equal to the current size of branch (otherwise it does not + // correspond to a depth-first traversal of a tree). A branch is only empty if no entries have + // ever be processed. A branch having length 1 corresponds to being done. branch: Vec>, } impl TaprootBuilder { - /// Create a new instance of [`TaprootBuilder`] + /// Creates a new instance of [`TaprootBuilder`]. pub fn new() -> Self { TaprootBuilder { branch: vec![] } } - /// Create a new [`TaprootBuilder`] from a list of script(with default script version) and - /// weights of satisfaction for that script. The weights represent the probability of - /// each branch being taken. If probabilities/weights for each condition are known, - /// constructing the tree as a Huffman tree is the optimal way to minimize average - /// case satisfaction cost. This function takes an iterator of (`u32`, &[`Script`]) tuples - /// as an input, where `u32` represents the satisfaction weights of the script branch. - /// For example, [(3, S1), (2, S2), (5, S3)] would construct a TapTree that has optimal + /// Creates a new [`TaprootSpendInfo`] from a list of scripts (with default script version) and + /// weights of satisfaction for that script. + /// + /// The weights represent the probability of each branch being taken. If probabilities/weights + /// for each condition are known, constructing the tree as a Huffman Tree is the optimal way to + /// minimize average case satisfaction cost. This function takes as input an iterator of + /// `tuple(u32, &Script)` where `u32` represents the satisfaction weights of the branch. For + /// example, [(3, S1), (2, S2), (5, S3)] would construct a [`TapTree`] that has optimal /// satisfaction weight when probability for S1 is 30%, S2 is 20% and S3 is 50%. /// /// # Errors: /// - /// - When the optimal huffman tree has a depth more than 128 - /// - If the provided list of script weights is empty + /// - When the optimal Huffman Tree has a depth more than 128. + /// - If the provided list of script weights is empty. /// /// # Edge Cases: - /// - If the script weight calculations overflow, a sub-optimal tree may be generated. This - /// should not happen unless you are dealing with billions of branches with weights close to - /// 2^32. + /// + /// If the script weight calculations overflow, a sub-optimal tree may be generated. This should + /// not happen unless you are dealing with billions of branches with weights close to 2^32. + /// + /// [`TapTree`]: ::util::psbt::TapTree pub fn with_huffman_tree( script_weights: I, ) -> Result @@ -412,7 +419,8 @@ impl TaprootBuilder { Ok(TaprootBuilder{branch: vec![Some(node)]}) } - /// Just like [`TaprootBuilder::add_leaf`] but allows to specify script version + /// Adds a leaf script at `depth` to the builder with script version `ver`. Errors if the leaves + /// are not provided in DFS walk order. The depth of the root node is 0. pub fn add_leaf_with_ver( self, depth: usize, @@ -423,29 +431,27 @@ impl TaprootBuilder { self.insert(leaf, depth) } - /// Add a leaf script at a depth `depth` to the builder with default script version. - /// This will error if the leave are not provided in a DFS walk order. The depth of the - /// root node is 0 and it's immediate child would be at depth 1. - /// See [`TaprootBuilder::add_leaf_with_ver`] for adding a leaf with specific version - /// See [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search) for more details + /// Adds a leaf script at `depth` to the builder with default script version. Errors if the + /// leaves are not provided in DFS walk order. The depth of the root node is 0. + /// + /// See [`TaprootBuilder::add_leaf_with_ver`] for adding a leaf with specific version. pub fn add_leaf(self, depth: usize, script: Script) -> Result { self.add_leaf_with_ver(depth, script, LeafVersion::TapScript) } - /// Add a hidden/omitted node at a depth `depth` to the builder. - /// This will error if the node are not provided in a DFS walk order. The depth of the - /// root node is 0 and it's immediate child would be at depth 1. + /// Adds a hidden/omitted node at `depth` to the builder. Errors if the leaves are not provided + /// in DFS walk order. The depth of the root node is 0. pub fn add_hidden(self, depth: usize, hash: sha256::Hash) -> Result { let node = NodeInfo::new_hidden(hash); self.insert(node, depth) } - /// Check if the builder is a complete tree + /// Checks if the builder is a complete tree. pub fn is_complete(&self) -> bool { self.branch.len() == 1 && self.branch[0].is_some() } - /// Create [`TaprootSpendInfo`] with the given internal key + /// Creates a [`TaprootSpendInfo`] with the given internal key. pub fn finalize( mut self, secp: &Secp256k1, @@ -466,7 +472,7 @@ impl TaprootBuilder { &self.branch } - // Helper function to insert a leaf at a depth + /// Inserts a leaf at `depth`. fn insert(mut self, mut node: NodeInfo, mut depth: usize) -> Result { // early error on invalid depth. Though this will be checked later // while constructing TaprootMerkelBranch @@ -513,15 +519,16 @@ impl TaprootBuilder { } } -/// Data structure used to represent node information in taproot tree. +/// Represents the node information in taproot tree. +/// /// You can use [`TaprootSpendInfo::from_node_info`] to a get [`TaprootSpendInfo`] /// from the merkle root [`NodeInfo`]. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct NodeInfo { - /// Merkle Hash for this node + /// Merkle hash for this node. pub(crate) hash: sha256::Hash, - /// information about leaves inside this node + /// Information about leaves inside this node. pub(crate) leaves: Vec, } @@ -569,20 +576,20 @@ impl NodeInfo { } } -// Internally used structure to store information about taproot leaf node +/// Store information about taproot leaf node. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub(crate) struct LeafInfo { - // The underlying script + /// The underlying script. pub(crate) script: Script, - // The leaf version + /// The leaf version. pub(crate) ver: LeafVersion, - // The merkle proof(hashing partners) to get this node + /// The merkle proof (hashing partners) to get this node. pub(crate) merkle_branch: TaprootMerkleBranch, } impl LeafInfo { - // Create an instance of Self from Script with default version and no merkle branch + /// Creates an new [`LeafInfo`] from `script` and `ver` and no merkle branch. fn new(script: Script, ver: LeafVersion) -> Self { Self { script: script, @@ -591,27 +598,27 @@ impl LeafInfo { } } - // Compute a leaf hash for the given leaf + /// Computes a leaf hash for this [`LeafInfo`]. fn hash(&self) -> sha256::Hash { let leaf_hash = TapLeafHash::from_script(&self.script, self.ver); sha256::Hash::from_inner(leaf_hash.into_inner()) } } -/// The Merkle proof for inclusion of a tree in a taptree hash -// The type of hash is sha256::Hash because the vector might contain -// both TapBranchHash and TapLeafHash +/// The merkle proof for inclusion of a tree in a taptree hash. +// The type of hash is `sha256::Hash` because the vector might contain both `TapBranchHash` and +// `TapLeafHash`. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TaprootMerkleBranch(Vec); impl TaprootMerkleBranch { - /// Obtain a reference to inner + /// Returns a reference to the inner vector of hashes. pub fn as_inner(&self) -> &[sha256::Hash] { &self.0 } - /// Create a merkle proof from slice + /// Creates a merkle proof from raw data representing a list of hashes. pub fn from_slice(sl: &[u8]) -> Result { if sl.len() % TAPROOT_CONTROL_NODE_SIZE != 0 { Err(TaprootError::InvalidMerkleBranchSize(sl.len())) @@ -630,7 +637,11 @@ impl TaprootMerkleBranch { } } - /// Serialize to a writer. Returns the number of bytes written + /// Serializes to a writer. + /// + /// # Returns + /// + /// The number of bytes written to the writer. pub fn encode(&self, mut writer: Write) -> io::Result { for hash in self.0.iter() { writer.write_all(hash)?; @@ -638,12 +649,12 @@ impl TaprootMerkleBranch { Ok(self.0.len() * sha256::Hash::LEN) } - /// Serialize self as bytes + /// Serializes `self` as bytes. pub fn serialize(&self) -> Vec { self.0.iter().map(|e| e.as_inner()).flatten().map(|x| *x).collect::>() } - // Internal function to append elements to proof + /// Appends elements to proof. fn push(&mut self, h: sha256::Hash) -> Result<(), TaprootBuilderError> { if self.0.len() >= TAPROOT_CONTROL_MAX_NODE_COUNT { Err(TaprootBuilderError::InvalidMerkleTreeDepth(self.0.len())) @@ -653,8 +664,11 @@ impl TaprootMerkleBranch { } } - /// Create a MerkleProof from Vec<[`sha256::Hash`]>. Returns an error when - /// inner proof len is more than TAPROOT_CONTROL_MAX_NODE_COUNT (128) + /// Creates a merkle proof from list of hashes. + /// + /// # Errors + /// + /// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128). pub fn from_inner(inner: Vec) -> Result { if inner.len() > TAPROOT_CONTROL_MAX_NODE_COUNT { Err(TaprootError::InvalidMerkleTreeDepth(inner.len())) @@ -663,35 +677,38 @@ impl TaprootMerkleBranch { } } - /// Consume Self to get Vec<[`sha256::Hash`]> + /// Returns the inner list of hashes. pub fn into_inner(self) -> Vec { self.0 } } -/// Control Block data structure used in Tapscript satisfaction +/// Control block data structure used in Tapscript satisfaction. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ControlBlock { - /// The tapleaf version, + /// The tapleaf version. pub leaf_version: LeafVersion, - /// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY) + /// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY). pub output_key_parity: secp256k1::Parity, - /// The internal key + /// The internal key. pub internal_key: UntweakedPublicKey, - /// The merkle proof of a script associated with this leaf + /// The merkle proof of a script associated with this leaf. pub merkle_branch: TaprootMerkleBranch, } impl ControlBlock { - /// Obtain a ControlBlock from slice. This is an extra witness element - /// that provides the proof that taproot script pubkey is correctly computed - /// with some specified leaf hash. This is the last element in - /// taproot witness when spending a output via script path. + /// Constructs a `ControlBlock` from slice. This is an extra witness element that provides the + /// proof that taproot script pubkey is correctly computed with some specified leaf hash. This + /// is the last element in taproot witness when spending a output via script path. /// - /// # Errors: - /// - If the control block size is not of the form 33 + 32m where - /// 0 <= m <= 128, InvalidControlBlock is returned + /// # Errors + /// + /// - `TaprootError::InvalidControlBlockSize` if `sl` is not of size 1 + 32 + 32N for any N >= 0. + /// - `TaprootError::InvalidParity` if first byte of `sl` is not a valid output key parity. + /// - `TaprootError::InvalidTaprootLeafVersion` if first byte of `sl` is not a valid leaf version. + /// - `TaprootError::InvalidInternalKey` if internal key is invalid (first 32 bytes after the parity byte). + /// - `TaprootError::InvalidMerkleTreeDepth` if merkle tree is too deep (more than 128 levels). pub fn from_slice(sl: &[u8]) -> Result { if sl.len() < TAPROOT_CONTROL_BASE_SIZE || (sl.len() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE != 0 @@ -712,13 +729,17 @@ impl ControlBlock { }) } - /// Obtain the size of control block. Faster and more efficient than calling - /// serialize() followed by len(). Can be handy for fee estimation + /// Returns the size of control block. Faster and more efficient than calling + /// `Self::serialize().len()`. Can be handy for fee estimation. pub fn size(&self) -> usize { TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * self.merkle_branch.as_inner().len() } - /// Serialize to a writer. Returns the number of bytes written + /// Serializes to a writer. + /// + /// # Returns + /// + /// The number of bytes written to the writer. pub fn encode(&self, mut writer: Write) -> io::Result { let first_byte: u8 = i32::from(self.output_key_parity) as u8 | self.leaf_version.to_consensus(); writer.write_all(&[first_byte])?; @@ -727,19 +748,21 @@ impl ControlBlock { Ok(self.size()) } - /// Serialize the control block. This would be required when - /// using ControlBlock as a witness element while spending an output via - /// script path. This serialization does not include the VarInt prefix that would be - /// applied when encoding this element as a witness. + /// Serializes the control block. + /// + /// This would be required when using [`ControlBlock`] as a witness element while spending an + /// output via script path. This serialization does not include the [`::VarInt`] prefix that would + /// be applied when encoding this element as a witness. pub fn serialize(&self) -> Vec { let mut buf = Vec::with_capacity(self.size()); self.encode(&mut buf).expect("writers don't error"); buf } - /// Verify that a control block is correct proof for a given output key and script - /// This only checks that script is contained inside the taptree described by - /// output key, full verification must also execute the script with witness data + /// Verifies that a control block is correct proof for a given output key and script. + /// + /// Only checks that script is contained inside the taptree described by output key. Full + /// verification must also execute the script with witness data. pub fn verify_taproot_commitment( &self, secp: &Secp256k1, @@ -791,7 +814,7 @@ impl FutureLeafVersion { } } - /// Get consensus representation of the future leaf version. + /// Returns the consensus representation of this [`FutureLeafVersion`]. #[inline] pub fn to_consensus(self) -> u8 { self.0 @@ -819,20 +842,21 @@ impl fmt::UpperHex for FutureLeafVersion { } } -/// The leaf version for tapleafs +/// The leaf version for tapleafs. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum LeafVersion { - /// BIP-342 tapscript + /// BIP-342 tapscript. TapScript, - /// Future leaf version + /// Future leaf version. Future(FutureLeafVersion) } impl LeafVersion { - /// Obtain LeafVersion from consensus byte representation. + /// Creates a [`LeafVersion`] from consensus byte representation. /// /// # Errors + /// /// - If the last bit of the `version` is odd. /// - If the `version` is 0x50 ([`TAPROOT_ANNEX_PREFIX`]). // Text from BIP341: @@ -852,7 +876,7 @@ impl LeafVersion { } } - /// Get consensus representation of the [`LeafVersion`]. + /// Returns the consensus representation of this [`LeafVersion`]. pub fn to_consensus(self) -> u8 { match self { LeafVersion::TapScript => TAPROOT_LEAF_TAPSCRIPT, @@ -884,7 +908,7 @@ impl fmt::UpperHex for LeafVersion { } } -/// Serializes LeafVersion as u8 using consensus encoding +/// Serializes [`LeafVersion`] as a `u8` using consensus encoding. #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl ::serde::Serialize for LeafVersion { @@ -896,7 +920,7 @@ impl ::serde::Serialize for LeafVersion { } } -/// Deserializes LeafVersion as u8 using consensus encoding +/// Deserializes [`LeafVersion`] as a `u8` using consensus encoding. #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> ::serde::Deserialize<'de> for LeafVersion { @@ -926,20 +950,20 @@ impl<'de> ::serde::Deserialize<'de> for LeafVersion { } } -/// Detailed error type for taproot builder +/// Detailed error type for taproot builder. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum TaprootBuilderError { - /// Merkle Tree depth must not be more than 128 + /// Merkle tree depth must not be more than 128. InvalidMerkleTreeDepth(usize), - /// Nodes must be added specified in DFS order + /// Nodes must be added specified in DFS walk order. NodeNotInDfsOrder, - /// Two nodes at depth 0 are not allowed + /// Two nodes at depth 0 are not allowed. OverCompleteTree, - /// Invalid taproot internal key + /// Invalid taproot internal key. InvalidInternalKey(secp256k1::Error), - /// Called finalize on an incomplete tree + /// Called finalize on an incomplete tree. IncompleteTree, - /// Called finalize on a empty tree + /// Called finalize on a empty tree. EmptyTree, } @@ -974,22 +998,22 @@ impl fmt::Display for TaprootBuilderError { #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl error::Error for TaprootBuilderError {} -/// Detailed error type for taproot utilities +/// Detailed error type for taproot utilities. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum TaprootError { - /// Proof size must be a multiple of 32 + /// Proof size must be a multiple of 32. InvalidMerkleBranchSize(usize), - /// Merkle Tree depth must not be more than 128 + /// Merkle tree depth must not be more than 128. InvalidMerkleTreeDepth(usize), - /// The last bit of tapleaf version must be zero + /// The last bit of tapleaf version must be zero. InvalidTaprootLeafVersion(u8), - /// Invalid Control Block Size + /// Invalid control block size. InvalidControlBlockSize(usize), - /// Invalid taproot internal key + /// Invalid taproot internal key. InvalidInternalKey(secp256k1::Error), - /// Invalid parity for internal key + /// Invalid parity for internal key. InvalidParity(secp256k1::InvalidParityValue), - /// Empty TapTree + /// Empty tap tree. EmptyTree, } From c25eddd18706bd4fcdad205db804b2af32d815df Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 29 Mar 2022 10:28:29 +1100 Subject: [PATCH 21/40] Remove unnecessary documentation We have some text quoted directly from BIP341, this text is on the net if folk wish to read it, we don't need it in the source code. --- src/util/taproot.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index a3a01a7406..69d381b709 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -859,15 +859,6 @@ impl LeafVersion { /// /// - If the last bit of the `version` is odd. /// - If the `version` is 0x50 ([`TAPROOT_ANNEX_PREFIX`]). - // Text from BIP341: - // In order to support some forms of static analysis that rely on - // being able to identify script spends without access to the output being - // spent, it is recommended to avoid using any leaf versions that would conflict - // with a valid first byte of either a valid P2WPKH pubkey or a valid P2WSH script - // (that is, both v and v | 1 should be an undefined, invalid or disabled opcode - // or an opcode that is not valid as the first opcode). - // The values that comply to this rule are the 32 even values between - // 0xc0 and 0xfe and also 0x66, 0x7e, 0x80, 0x84, 0x96, 0x98, 0xba, 0xbc, 0xbe pub fn from_consensus(version: u8) -> Result { match version { TAPROOT_LEAF_TAPSCRIPT => Ok(LeafVersion::TapScript), From 8d602b87785bf3dd06e71c448b3986072a2016cf Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 29 Mar 2022 10:56:56 +1100 Subject: [PATCH 22/40] Fix deprecated since version We deprecated the `bip143::SigHashCache` in ``` commit 53d0e176d3c79c666cf75952f6f610fa37a105f5 Author: Date: Fri Jul 16 10:44:18 2021 +0200 Deprecate bip143::SigHashCache in favor of sighash::SigHashCache ... ``` This means these changes are unreleased so the deprecated since version should be the upcoming 0.28 release. --- src/util/bip143.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/bip143.rs b/src/util/bip143.rs index c238a5ec2f..ec4c345782 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -107,7 +107,7 @@ impl SighashComponents { } /// 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, } From 552245458389d36caca19dcc8e3ec00975893ab0 Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 29 Mar 2022 08:48:53 +1100 Subject: [PATCH 23/40] Rename EcdsaSigHashType -> EcdsaSighashType Our usage of `SigHash` implies that 'sighash' is _two_ words; 'sighash' is a well known word in the Bitcoin ecosystem it should appear in identifiers as `Sighash`. Rename `EcdsaSigHashType` to `EcdsaSighashType`. --- src/blockdata/transaction.rs | 148 +++++++++++++++++------------------ src/lib.rs | 2 +- src/util/bip143.rs | 12 +-- src/util/ecdsa.rs | 14 ++-- src/util/psbt/map/input.rs | 36 ++++----- src/util/psbt/mod.rs | 8 +- src/util/psbt/serialize.rs | 2 +- src/util/sighash.rs | 34 ++++---- 8 files changed, 128 insertions(+), 128 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 8a34d05c00..9ac6d6b7f9 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -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_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. /// @@ -444,8 +444,8 @@ impl Transaction { } fn is_invalid_use_of_sighash_single(&self, sighash: u32, input_index: usize) -> bool { - let ty = EcdsaSigHashType::from_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. @@ -736,15 +736,15 @@ impl fmt::Display 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`]). #[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,67 +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 { +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), + "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) } } - /// Creates a [`EcdsaSigHashType`] from a raw `u32`. + /// 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) + pub fn from_u32_consensus(n: u32) -> EcdsaSighashType { + EcdsaSighashType::from_consensus(n) } - /// Creates a [`EcdsaSigHashType`] from a raw `u32`. + /// Creates a [`EcdsaSighashType`] from a raw `u32`. /// /// **Note**: this replicates consensus behaviour, for current standardness rules correctness /// you probably want [`Self::from_standard`]. /// /// This might cause unexpected behavior because it does not roundtrip. That is, - /// `EcdsaSigHashType::from_consensus(n) as u32 != n` for non-standard values of `n`. While + /// `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 { + 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. @@ -829,43 +829,43 @@ 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 } } - /// Creates a [`EcdsaSigHashType`] from a raw `u32`. + /// 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) + pub fn from_u32_standard(n: u32) -> Result { + EcdsaSighashType::from_standard(n) } - /// Creates a [`EcdsaSigHashType`] from a raw `u32`. + /// Creates a [`EcdsaSighashType`] from a raw `u32`. /// /// # Errors /// /// If `n` is a non-standard sighash value. - pub fn from_standard(n: u32) -> Result { + 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), + 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 [`EcdsaSigHashType`] to a `u32` sighash flag. + /// 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 } @@ -904,7 +904,7 @@ mod tests { use hashes::hex::FromHex; use hash_types::*; - use super::EcdsaSigHashType; + use super::EcdsaSighashType; use util::sighash::SigHashCache; #[test] @@ -1167,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", @@ -1191,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)); } } @@ -1200,9 +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_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] diff --git a/src/lib.rs b/src/lib.rs index 26725f865f..71ea0ed997 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; diff --git a/src/util/bip143.rs b/src/util/bip143.rs index ec4c345782..1acc9b27a4 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -23,7 +23,7 @@ use hashes::Hash; 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; @@ -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,7 +145,7 @@ impl> SigHashCache { input_index: usize, script_code: &Script, value: u64, - sighash_type: EcdsaSigHashType + sighash_type: EcdsaSighashType ) -> SigHash { let mut enc = SigHash::engine(); self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type) @@ -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(&[]); /// } @@ -211,7 +211,7 @@ mod tests { 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); } diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index e4861769d9..75082dc48d 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -22,7 +22,7 @@ use core::{fmt, iter}; use hashes::hex::{self, FromHex}; 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,23 +31,23 @@ 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_standard(*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)?; @@ -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_standard(*sighash_byte as u32)? + hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)? }) } } diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index dd660d67e2..08622ebfb8 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -34,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; @@ -148,7 +148,7 @@ pub struct Input { /// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash -/// type can be either [`EcdsaSigHashType`] or [`SchnorrSigHashType`] but it is not possible to know +/// type can be either [`EcdsaSighashType`] or [`SchnorrSigHashType`] but it is not possible to know /// directly which signature hash type the user is dealing with. Therefore, the user is responsible /// for converting to/from [`PsbtSigHashType`] from/to the desired signature hash type they need. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -191,8 +191,8 @@ impl FromStr for PsbtSigHashType { Err(SigHashTypeParseError{ unrecognized: s.to_owned() }) } } -impl From for PsbtSigHashType { - fn from(ecdsa_hash_ty: EcdsaSigHashType) -> Self { +impl From for PsbtSigHashType { + fn from(ecdsa_hash_ty: EcdsaSighashType) -> Self { PsbtSigHashType { inner: ecdsa_hash_ty as u32 } } } @@ -204,10 +204,10 @@ impl From for PsbtSigHashType { } impl PsbtSigHashType { - /// Returns the [`EcdsaSigHashType`] if the [`PsbtSigHashType`] can be + /// Returns the [`EcdsaSighashType`] if the [`PsbtSigHashType`] can be /// converted to one. - pub fn ecdsa_hash_ty(self) -> Result { - EcdsaSigHashType::from_standard(self.inner) + pub fn ecdsa_hash_ty(self) -> Result { + EcdsaSighashType::from_standard(self.inner) } /// Returns the [`SchnorrSigHashType`] if the [`PsbtSigHashType`] can be @@ -223,7 +223,7 @@ impl PsbtSigHashType { /// Creates a [`PsbtSigHashType`] from a raw `u32`. /// /// Allows construction of a non-standard or non-valid sighash flag - /// ([`EcdsaSigHashType`], [`SchnorrSigHashType`] respectively). + /// ([`EcdsaSighashType`], [`SchnorrSigHashType`] respectively). pub fn from_u32(n: u32) -> PsbtSigHashType { PsbtSigHashType { inner: n } } @@ -238,16 +238,16 @@ impl PsbtSigHashType { } impl Input { - /// Obtains the [`EcdsaSigHashType`] for this input if one is specified. If no sighash type is - /// specified, returns [`EcdsaSigHashType::All`]. + /// Obtains the [`EcdsaSighashType`] for this input if one is specified. If no sighash type is + /// specified, returns [`EcdsaSighashType::All`]. /// /// # Errors /// /// If the `sighash_type` field is set to a non-standard ECDSA sighash value. - pub fn ecdsa_hash_ty(&self) -> Result { + pub fn ecdsa_hash_ty(&self) -> Result { self.sighash_type .map(|sighash_type| sighash_type.ecdsa_hash_ty()) - .unwrap_or(Ok(EcdsaSigHashType::All)) + .unwrap_or(Ok(EcdsaSighashType::All)) } /// Obtains the [`SchnorrSigHashType`] for this input if one is specified. If no sighash type is @@ -544,12 +544,12 @@ mod test { #[test] fn psbt_sighash_type_ecdsa() { for ecdsa in &[ - EcdsaSigHashType::All, - EcdsaSigHashType::None, - EcdsaSigHashType::Single, - EcdsaSigHashType::AllPlusAnyoneCanPay, - EcdsaSigHashType::NonePlusAnyoneCanPay, - EcdsaSigHashType::SinglePlusAnyoneCanPay, + EcdsaSighashType::All, + EcdsaSighashType::None, + EcdsaSighashType::Single, + EcdsaSighashType::AllPlusAnyoneCanPay, + EcdsaSighashType::NonePlusAnyoneCanPay, + EcdsaSighashType::SinglePlusAnyoneCanPay, ] { let sighash = PsbtSigHashType::from(*ecdsa); let s = format!("{}", sighash); diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index ef3acdc8dc..f78e1ffffa 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -468,7 +468,7 @@ mod tests { //! Create a full PSBT value with various fields filled and make sure it can be JSONized. use hashes::sha256d; use util::psbt::map::Input; - use EcdsaSigHashType; + use EcdsaSighashType; // create some values to use in the PSBT let tx = Transaction { @@ -532,7 +532,7 @@ mod tests { value: 190303501938, script_pubkey: hex_script!("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587"), }), - sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::().unwrap().into()), + sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::().unwrap().into()), redeem_script: Some(vec![0x51].into()), witness_script: None, partial_sigs: vec![( @@ -569,7 +569,7 @@ mod tests { use hash_types::Txid; use blockdata::script::Script; - use blockdata::transaction::{EcdsaSigHashType, Transaction, TxIn, TxOut, OutPoint}; + use blockdata::transaction::{EcdsaSighashType, Transaction, TxIn, TxOut, OutPoint}; use consensus::encode::serialize_hex; use util::psbt::map::{Map, Input, Output}; use util::psbt::raw; @@ -795,7 +795,7 @@ mod tests { ); assert_eq!( (&psbt.inputs[0].sighash_type).as_ref().unwrap().ecdsa_hash_ty().unwrap(), - EcdsaSigHashType::All + EcdsaSighashType::All ); } diff --git a/src/util/psbt/serialize.rs b/src/util/psbt/serialize.rs index bb1443a597..e555d059ae 100644 --- a/src/util/psbt/serialize.rs +++ b/src/util/psbt/serialize.rs @@ -118,7 +118,7 @@ impl Deserialize for EcdsaSig { // // 1) the current implementation of from_u32_consensus(`flag`) does not preserve // the sighash byte `flag` mapping all unknown values to EcdsaSighashType::All or - // EcdsaSigHashType::AllPlusAnyOneCanPay. Therefore, break the invariant + // EcdsaSighashType::AllPlusAnyOneCanPay. Therefore, break the invariant // EcdsaSig::from_slice(&sl[..]).to_vec = sl. // // 2) This would cause to have invalid signatures because the sighash message diff --git a/src/util/sighash.rs b/src/util/sighash.rs index b4482c8943..ef4e3617bf 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -22,7 +22,7 @@ use prelude::*; -pub use blockdata::transaction::{EcdsaSigHashType, SigHashTypeParseError}; +pub use blockdata::transaction::{EcdsaSighashType, SigHashTypeParseError}; use blockdata::witness::Witness; use consensus::{encode, Encodable}; use core::{str, fmt}; @@ -288,15 +288,15 @@ impl<'s> From> for TapLeafHash { } } -impl From for SchnorrSigHashType { - fn from(s: EcdsaSigHashType) -> Self { +impl From for SchnorrSigHashType { + fn from(s: EcdsaSighashType) -> Self { match s { - EcdsaSigHashType::All => SchnorrSigHashType::All, - EcdsaSigHashType::None => SchnorrSigHashType::None, - EcdsaSigHashType::Single => SchnorrSigHashType::Single, - EcdsaSigHashType::AllPlusAnyoneCanPay => SchnorrSigHashType::AllPlusAnyoneCanPay, - EcdsaSigHashType::NonePlusAnyoneCanPay => SchnorrSigHashType::NonePlusAnyoneCanPay, - EcdsaSigHashType::SinglePlusAnyoneCanPay => SchnorrSigHashType::SinglePlusAnyoneCanPay, + EcdsaSighashType::All => SchnorrSigHashType::All, + EcdsaSighashType::None => SchnorrSigHashType::None, + EcdsaSighashType::Single => SchnorrSigHashType::Single, + EcdsaSighashType::AllPlusAnyoneCanPay => SchnorrSigHashType::AllPlusAnyoneCanPay, + EcdsaSighashType::NonePlusAnyoneCanPay => SchnorrSigHashType::NonePlusAnyoneCanPay, + EcdsaSighashType::SinglePlusAnyoneCanPay => SchnorrSigHashType::SinglePlusAnyoneCanPay, } } } @@ -548,7 +548,7 @@ impl> SigHashCache { input_index: usize, script_code: &Script, value: u64, - sighash_type: EcdsaSigHashType, + sighash_type: EcdsaSighashType, ) -> Result<(), Error> { let zero_hash = sha256d::Hash::default(); @@ -563,8 +563,8 @@ impl> SigHashCache { } if !anyone_can_pay - && sighash != EcdsaSigHashType::Single - && sighash != EcdsaSigHashType::None + && sighash != EcdsaSighashType::Single + && sighash != EcdsaSighashType::None { self.segwit_cache() .sequences @@ -590,9 +590,9 @@ impl> SigHashCache { txin.sequence.consensus_encode(&mut writer)?; } - if sighash != EcdsaSigHashType::Single && sighash != EcdsaSigHashType::None { + if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None { self.segwit_cache().outputs.consensus_encode(&mut writer)?; - } else if sighash == EcdsaSigHashType::Single && input_index < self.tx.output.len() { + } else if sighash == EcdsaSighashType::Single && input_index < self.tx.output.len() { let mut single_enc = SigHash::engine(); self.tx.output[input_index].consensus_encode(&mut single_enc)?; SigHash::from_engine(single_enc).consensus_encode(&mut writer)?; @@ -611,7 +611,7 @@ impl> SigHashCache { input_index: usize, script_code: &Script, value: u64, - sighash_type: EcdsaSigHashType, + sighash_type: EcdsaSighashType, ) -> Result { let mut enc = SigHash::engine(); self.segwit_encode_signing_data_to( @@ -735,7 +735,7 @@ impl> SigHashCache { /// /// This allows in-line signing such as /// ``` - /// use bitcoin::blockdata::transaction::{Transaction, EcdsaSigHashType}; + /// use bitcoin::blockdata::transaction::{Transaction, EcdsaSighashType}; /// use bitcoin::util::sighash::SigHashCache; /// use bitcoin::Script; /// @@ -745,7 +745,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.segwit_signature_hash(inp, &prevout_script, 42, EcdsaSigHashType::All); + /// let _sighash = sig_hasher.segwit_signature_hash(inp, &prevout_script, 42, EcdsaSighashType::All); /// // ... sign the sighash /// sig_hasher.witness_mut(inp).unwrap().push(&Vec::new()); /// } From 6caba2ed244dd27c432e13070998ca74c3ac27e5 Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 29 Mar 2022 08:52:33 +1100 Subject: [PATCH 24/40] Rename SchnorrSigHashType -> SchnorrSighashType Our usage of `SigHash` implies that 'sighash' is _two_ words; 'sighash' is a well known word in the Bitcoin ecosystem it should appear in identifiers as `Sighash`. Rename `SchnorrSigHashType` to `SchnorrSighashType`. --- src/blockdata/transaction.rs | 4 +- src/lib.rs | 2 +- src/util/psbt/map/input.rs | 46 +++++----- src/util/schnorr.rs | 10 +-- src/util/sighash.rs | 170 +++++++++++++++++------------------ 5 files changed, 116 insertions(+), 116 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 9ac6d6b7f9..984e1ac88a 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -43,7 +43,7 @@ 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] = [ @@ -742,7 +742,7 @@ 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 { /// 0x1: Sign all outputs. diff --git a/src/lib.rs b/src/lib.rs index 71ea0ed997..0b7bc883dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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/psbt/map/input.rs b/src/util/psbt/map/input.rs index 08622ebfb8..6362748d2b 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -34,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; @@ -148,7 +148,7 @@ pub struct Input { /// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash -/// type can be either [`EcdsaSighashType`] or [`SchnorrSigHashType`] but it is not possible to know +/// type can be either [`EcdsaSighashType`] or [`SchnorrSighashType`] but it is not possible to know /// directly which signature hash type the user is dealing with. Therefore, the user is responsible /// for converting to/from [`PsbtSigHashType`] from/to the desired signature hash type they need. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -160,7 +160,7 @@ pub struct PsbtSigHashType { impl fmt::Display for PsbtSigHashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.schnorr_hash_ty() { - Ok(SchnorrSigHashType::Reserved) | Err(_) => write!(f, "{:#x}", self.inner), + Ok(SchnorrSighashType::Reserved) | Err(_) => write!(f, "{:#x}", self.inner), Ok(schnorr_hash_ty) => fmt::Display::fmt(&schnorr_hash_ty, f), } } @@ -176,8 +176,8 @@ impl FromStr for PsbtSigHashType { // NB: some of Schnorr sighash types are non-standard for pre-taproot // inputs. We also do not support SIGHASH_RESERVED in verbatim form // ("0xFF" string should be used instead). - match SchnorrSigHashType::from_str(s) { - Ok(SchnorrSigHashType::Reserved) => return Err(SigHashTypeParseError{ unrecognized: s.to_owned() }), + match SchnorrSighashType::from_str(s) { + Ok(SchnorrSighashType::Reserved) => return Err(SigHashTypeParseError{ unrecognized: s.to_owned() }), Ok(ty) => return Ok(ty.into()), Err(_) => {} } @@ -197,8 +197,8 @@ impl From for PsbtSigHashType { } } -impl From for PsbtSigHashType { - fn from(schnorr_hash_ty: SchnorrSigHashType) -> Self { +impl From for PsbtSigHashType { + fn from(schnorr_hash_ty: SchnorrSighashType) -> Self { PsbtSigHashType { inner: schnorr_hash_ty as u32 } } } @@ -210,20 +210,20 @@ impl PsbtSigHashType { EcdsaSighashType::from_standard(self.inner) } - /// Returns the [`SchnorrSigHashType`] if the [`PsbtSigHashType`] can be + /// Returns the [`SchnorrSighashType`] if the [`PsbtSigHashType`] can be /// converted to one. - pub fn schnorr_hash_ty(self) -> Result { + pub fn schnorr_hash_ty(self) -> Result { if self.inner > 0xffu32 { Err(sighash::Error::InvalidSigHashType(self.inner)) } else { - SchnorrSigHashType::from_u8(self.inner as u8) + SchnorrSighashType::from_u8(self.inner as u8) } } /// Creates a [`PsbtSigHashType`] from a raw `u32`. /// /// Allows construction of a non-standard or non-valid sighash flag - /// ([`EcdsaSighashType`], [`SchnorrSigHashType`] respectively). + /// ([`EcdsaSighashType`], [`SchnorrSighashType`] respectively). pub fn from_u32(n: u32) -> PsbtSigHashType { PsbtSigHashType { inner: n } } @@ -250,16 +250,16 @@ impl Input { .unwrap_or(Ok(EcdsaSighashType::All)) } - /// Obtains the [`SchnorrSigHashType`] for this input if one is specified. If no sighash type is - /// specified, returns [`SchnorrSigHashType::Default`]. + /// Obtains the [`SchnorrSighashType`] for this input if one is specified. If no sighash type is + /// specified, returns [`SchnorrSighashType::Default`]. /// /// # Errors /// /// If the `sighash_type` field is set to a invalid Schnorr sighash value. - pub fn schnorr_hash_ty(&self) -> Result { + pub fn schnorr_hash_ty(&self) -> Result { self.sighash_type .map(|sighash_type| sighash_type.schnorr_hash_ty()) - .unwrap_or(Ok(SchnorrSigHashType::Default)) + .unwrap_or(Ok(SchnorrSighashType::Default)) } pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { @@ -562,13 +562,13 @@ mod test { #[test] fn psbt_sighash_type_schnorr() { for schnorr in &[ - SchnorrSigHashType::Default, - SchnorrSigHashType::All, - SchnorrSigHashType::None, - SchnorrSigHashType::Single, - SchnorrSigHashType::AllPlusAnyoneCanPay, - SchnorrSigHashType::NonePlusAnyoneCanPay, - SchnorrSigHashType::SinglePlusAnyoneCanPay, + SchnorrSighashType::Default, + SchnorrSighashType::All, + SchnorrSighashType::None, + SchnorrSighashType::Single, + SchnorrSighashType::AllPlusAnyoneCanPay, + SchnorrSighashType::NonePlusAnyoneCanPay, + SchnorrSighashType::SinglePlusAnyoneCanPay, ] { let sighash = PsbtSigHashType::from(*schnorr); let s = format!("{}", sighash); @@ -581,7 +581,7 @@ mod test { #[test] fn psbt_sighash_type_schnorr_notstd() { for (schnorr, schnorr_str) in &[ - (SchnorrSigHashType::Reserved, "0xff"), + (SchnorrSighashType::Reserved, "0xff"), ] { let sighash = PsbtSigHashType::from(*schnorr); let s = format!("{}", sighash); diff --git a/src/util/schnorr.rs b/src/util/schnorr.rs index 8542915f7d..20b7894c46 100644 --- a/src/util/schnorr.rs +++ b/src/util/schnorr.rs @@ -25,7 +25,7 @@ use secp256k1::{XOnlyPublicKey as _XOnlyPublicKey, KeyPair as _KeyPair}; use secp256k1::{self, Secp256k1, Verification, constants}; use hashes::Hash; use util::taproot::{TapBranchHash, TapTweakHash}; -use SchnorrSigHashType; +use SchnorrSighashType; /// Deprecated re-export of [`secp256k1::XOnlyPublicKey`] #[deprecated(since = "0.28.0", note = "Please use `util::key::XOnlyPublicKey` instead")] @@ -220,7 +220,7 @@ pub struct SchnorrSig { /// The underlying schnorr signature pub sig: secp256k1::schnorr::Signature, /// The corresponding hash type - pub hash_ty: SchnorrSigHashType, + pub hash_ty: SchnorrSighashType, } impl SchnorrSig { @@ -231,11 +231,11 @@ impl SchnorrSig { // default type let sig = secp256k1::schnorr::Signature::from_slice(sl) .map_err(SchnorrSigError::Secp256k1)?; - return Ok( SchnorrSig { sig, hash_ty : SchnorrSigHashType::Default }); + 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) + let hash_ty = SchnorrSighashType::from_u8(*hash_ty) .map_err(|_| SchnorrSigError::InvalidSighashType(*hash_ty))?; let sig = secp256k1::schnorr::Signature::from_slice(sig) .map_err(SchnorrSigError::Secp256k1)?; @@ -251,7 +251,7 @@ impl SchnorrSig { pub fn to_vec(&self) -> Vec { // TODO: add support to serialize to a writer to SerializedSig let mut ser_sig = self.sig.as_ref().to_vec(); - if self.hash_ty == SchnorrSigHashType::Default { + if self.hash_ty == SchnorrSighashType::Default { // default sighash type, don't add extra sighash byte } else { ser_sig.push(self.hash_ty as u8); diff --git a/src/util/sighash.rs b/src/util/sighash.rs index ef4e3617bf..2eb62309b3 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -81,7 +81,7 @@ struct TaprootCache { } /// Contains outputs of previous transactions. -/// In the case [`SchnorrSigHashType`] 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)] pub enum Prevouts<'u, T> where T: 'u + Borrow { /// `One` variant allows to provide the single Prevout needed. It's useful for example @@ -107,8 +107,8 @@ pub struct ScriptPath<'s> { /// Hashtype of an input's signature, encoded in the last byte of the signature /// Fixed values so they can be casted as integer types for encoding #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum SchnorrSigHashType { - /// 0x0: Used when not explicitly specified, defaulting to [`SchnorrSigHashType::All`] +pub enum SchnorrSighashType { + /// 0x0: Used when not explicitly specified, defaulting to [`SchnorrSighashType::All`] Default = 0x00, /// 0x1: Sign all outputs All = 0x01, @@ -129,37 +129,37 @@ pub enum SchnorrSigHashType { /// Reserved for future use, `#[non_exhaustive]` is not available with current MSRV Reserved = 0xFF, } -serde_string_impl!(SchnorrSigHashType, "a SchnorrSigHashType data"); +serde_string_impl!(SchnorrSighashType, "a SchnorrSighashType data"); -impl fmt::Display for SchnorrSigHashType { +impl fmt::Display for SchnorrSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { - SchnorrSigHashType::Default => "SIGHASH_DEFAULT", - SchnorrSigHashType::All => "SIGHASH_ALL", - SchnorrSigHashType::None => "SIGHASH_NONE", - SchnorrSigHashType::Single => "SIGHASH_SINGLE", - SchnorrSigHashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", - SchnorrSigHashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", - SchnorrSigHashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", - SchnorrSigHashType::Reserved => "SIGHASH_RESERVED", + SchnorrSighashType::Default => "SIGHASH_DEFAULT", + SchnorrSighashType::All => "SIGHASH_ALL", + SchnorrSighashType::None => "SIGHASH_NONE", + SchnorrSighashType::Single => "SIGHASH_SINGLE", + SchnorrSighashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", + SchnorrSighashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", + SchnorrSighashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", + SchnorrSighashType::Reserved => "SIGHASH_RESERVED", }; f.write_str(s) } } -impl str::FromStr for SchnorrSigHashType { +impl str::FromStr for SchnorrSighashType { type Err = SigHashTypeParseError; fn from_str(s: &str) -> Result { match s { - "SIGHASH_DEFAULT" => Ok(SchnorrSigHashType::Default), - "SIGHASH_ALL" => Ok(SchnorrSigHashType::All), - "SIGHASH_NONE" => Ok(SchnorrSigHashType::None), - "SIGHASH_SINGLE" => Ok(SchnorrSigHashType::Single), - "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(SchnorrSigHashType::AllPlusAnyoneCanPay), - "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSigHashType::NonePlusAnyoneCanPay), - "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSigHashType::SinglePlusAnyoneCanPay), - "SIGHASH_RESERVED" => Ok(SchnorrSigHashType::Reserved), + "SIGHASH_DEFAULT" => Ok(SchnorrSighashType::Default), + "SIGHASH_ALL" => Ok(SchnorrSighashType::All), + "SIGHASH_NONE" => Ok(SchnorrSighashType::None), + "SIGHASH_SINGLE" => Ok(SchnorrSighashType::Single), + "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::AllPlusAnyoneCanPay), + "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::NonePlusAnyoneCanPay), + "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::SinglePlusAnyoneCanPay), + "SIGHASH_RESERVED" => Ok(SchnorrSighashType::Reserved), _ => Err(SigHashTypeParseError{ unrecognized: s.to_owned() }), } } @@ -288,45 +288,45 @@ impl<'s> From> for TapLeafHash { } } -impl From for SchnorrSigHashType { +impl From for SchnorrSighashType { fn from(s: EcdsaSighashType) -> Self { match s { - EcdsaSighashType::All => SchnorrSigHashType::All, - EcdsaSighashType::None => SchnorrSigHashType::None, - EcdsaSighashType::Single => SchnorrSigHashType::Single, - EcdsaSighashType::AllPlusAnyoneCanPay => SchnorrSigHashType::AllPlusAnyoneCanPay, - EcdsaSighashType::NonePlusAnyoneCanPay => SchnorrSigHashType::NonePlusAnyoneCanPay, - EcdsaSighashType::SinglePlusAnyoneCanPay => SchnorrSigHashType::SinglePlusAnyoneCanPay, + EcdsaSighashType::All => SchnorrSighashType::All, + EcdsaSighashType::None => SchnorrSighashType::None, + EcdsaSighashType::Single => SchnorrSighashType::Single, + EcdsaSighashType::AllPlusAnyoneCanPay => SchnorrSighashType::AllPlusAnyoneCanPay, + EcdsaSighashType::NonePlusAnyoneCanPay => SchnorrSighashType::NonePlusAnyoneCanPay, + EcdsaSighashType::SinglePlusAnyoneCanPay => SchnorrSighashType::SinglePlusAnyoneCanPay, } } } -impl SchnorrSigHashType { +impl SchnorrSighashType { /// Break the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean - pub(crate) fn split_anyonecanpay_flag(self) -> (SchnorrSigHashType, bool) { + pub(crate) fn split_anyonecanpay_flag(self) -> (SchnorrSighashType, bool) { match self { - SchnorrSigHashType::Default => (SchnorrSigHashType::Default, false), - SchnorrSigHashType::All => (SchnorrSigHashType::All, false), - SchnorrSigHashType::None => (SchnorrSigHashType::None, false), - SchnorrSigHashType::Single => (SchnorrSigHashType::Single, false), - SchnorrSigHashType::AllPlusAnyoneCanPay => (SchnorrSigHashType::All, true), - SchnorrSigHashType::NonePlusAnyoneCanPay => (SchnorrSigHashType::None, true), - SchnorrSigHashType::SinglePlusAnyoneCanPay => (SchnorrSigHashType::Single, true), - SchnorrSigHashType::Reserved => (SchnorrSigHashType::Reserved, false), + SchnorrSighashType::Default => (SchnorrSighashType::Default, false), + SchnorrSighashType::All => (SchnorrSighashType::All, false), + SchnorrSighashType::None => (SchnorrSighashType::None, false), + SchnorrSighashType::Single => (SchnorrSighashType::Single, false), + SchnorrSighashType::AllPlusAnyoneCanPay => (SchnorrSighashType::All, true), + SchnorrSighashType::NonePlusAnyoneCanPay => (SchnorrSighashType::None, true), + SchnorrSighashType::SinglePlusAnyoneCanPay => (SchnorrSighashType::Single, true), + SchnorrSighashType::Reserved => (SchnorrSighashType::Reserved, false), } } - /// Create a [`SchnorrSigHashType`] from raw `u8` + /// Create a [`SchnorrSighashType`] from raw `u8` pub fn from_u8(hash_ty: u8) -> Result { 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), - 0xFF => Ok(SchnorrSigHashType::Reserved), + 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), + 0xFF => Ok(SchnorrSighashType::Reserved), x => Err(Error::InvalidSigHashType(x as u32)), } } @@ -355,7 +355,7 @@ impl> SigHashCache { prevouts: &Prevouts, annex: Option, leaf_hash_code_separator: Option<(TapLeafHash, u32)>, - sighash_type: SchnorrSigHashType, + sighash_type: SchnorrSighashType, ) -> Result<(), Error> { prevouts.check_all(&self.tx)?; @@ -395,7 +395,7 @@ impl> SigHashCache { // If hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE: // sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format. - if sighash != SchnorrSigHashType::None && sighash != SchnorrSigHashType::Single { + if sighash != SchnorrSighashType::None && sighash != SchnorrSighashType::Single { self.common_cache().outputs.consensus_encode(&mut writer)?; } @@ -450,7 +450,7 @@ impl> SigHashCache { // * Data about this output: // If hash_type & 3 equals SIGHASH_SINGLE: // sha_single_output (32): the SHA256 of the corresponding output in CTxOut format. - if sighash == SchnorrSigHashType::Single { + if sighash == SchnorrSighashType::Single { let mut enc = sha256::Hash::engine(); self.tx .output @@ -484,7 +484,7 @@ impl> SigHashCache { prevouts: &Prevouts, annex: Option, leaf_hash_code_separator: Option<(TapLeafHash, u32)>, - sighash_type: SchnorrSigHashType, + sighash_type: SchnorrSighashType, ) -> Result { let mut enc = TapSighashHash::engine(); self.taproot_encode_signing_data_to( @@ -503,7 +503,7 @@ impl> SigHashCache { &mut self, input_index: usize, prevouts: &Prevouts, - sighash_type: SchnorrSigHashType, + sighash_type: SchnorrSighashType, ) -> Result { let mut enc = TapSighashHash::engine(); self.taproot_encode_signing_data_to( @@ -526,7 +526,7 @@ impl> SigHashCache { input_index: usize, prevouts: &Prevouts, leaf_hash: S, - sighash_type: SchnorrSigHashType, + sighash_type: SchnorrSighashType, ) -> Result { let mut enc = TapSighashHash::engine(); self.taproot_encode_signing_data_to( @@ -823,7 +823,7 @@ mod tests { "01365724000000000023542156b39dab4f8f3508e0432cfb41fab110170acaa2d4c42539cb90a4dc7c093bc500", 0, "33ca0ebfb4a945eeee9569fc0f5040221275f88690b7f8592ada88ce3bdf6703", - SchnorrSigHashType::Default, None, None, None + SchnorrSighashType::Default, None, None, None ); test_taproot_sighash( @@ -831,7 +831,7 @@ mod tests { "02591f220000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece48fb310000000000225120f25ad35583ea31998d968871d7de1abd2a52f6fe4178b54ea158274806ff4ece", 1, "626ab955d58c9a8a600a0c580549d06dc7da4e802eb2a531f62a588e430967a8", - SchnorrSigHashType::All, None, None, None + SchnorrSighashType::All, None, None, None ); test_taproot_sighash( @@ -839,7 +839,7 @@ mod tests { "01c4811000000000002251201bf9297d0a2968ae6693aadd0fa514717afefd218087a239afb7418e2d22e65c", 0, "dfa9437f9c9a1d1f9af271f79f2f5482f287cdb0d2e03fa92c8a9b216cc6061c", - SchnorrSigHashType::AllPlusAnyoneCanPay, None, None, None + SchnorrSighashType::AllPlusAnyoneCanPay, None, None, None ); test_taproot_sighash( @@ -847,7 +847,7 @@ mod tests { "0144c84d0000000000225120e3f2107989c88e67296ab2faca930efa2e3a5bd3ff0904835a11c9e807458621", 0, "3129de36a5d05fff97ffca31eb75fcccbbbc27b3147a7a36a9e4b45d8b625067", - SchnorrSigHashType::None, None, None, None + SchnorrSighashType::None, None, None, None ); test_taproot_sighash( @@ -855,7 +855,7 @@ mod tests { "013fed110000000000225120eb536ae8c33580290630fc495046e998086a64f8f33b93b07967d9029b265c55", 0, "2441e8b0e063a2083ee790f14f2045022f07258ddde5ee01de543c9e789d80ae", - SchnorrSigHashType::NonePlusAnyoneCanPay, None, None, None + SchnorrSighashType::NonePlusAnyoneCanPay, None, None, None ); test_taproot_sighash( @@ -863,7 +863,7 @@ mod tests { "01efa558000000000022512007071ea3dc7e331b0687d0193d1e6d6ed10e645ef36f10ef8831d5e522ac9e80", 0, "30239345177cadd0e3ea413d49803580abb6cb27971b481b7788a78d35117a88", - SchnorrSigHashType::Single, None, None, None + SchnorrSighashType::Single, None, None, None ); test_taproot_sighash( @@ -871,7 +871,7 @@ mod tests { "0107af4e00000000002251202c36d243dfc06cb56a248e62df27ecba7417307511a81ae61aa41c597a929c69", 0, "bf9c83f26c6dd16449e4921f813f551c4218e86f2ec906ca8611175b41b566df", - SchnorrSigHashType::SinglePlusAnyoneCanPay, None, None, None + SchnorrSighashType::SinglePlusAnyoneCanPay, None, None, None ); } @@ -882,7 +882,7 @@ mod tests { "01ea49260000000000225120ab5e9800806bf18cb246edcf5fe63441208fe955a4b5a35bbff65f5db622a010", 0, "3b003000add359a364a156e73e02846782a59d0d95ca8c4638aaad99f2ef915c", - SchnorrSigHashType::SinglePlusAnyoneCanPay, + SchnorrSighashType::SinglePlusAnyoneCanPay, Some("507b979802e62d397acb29f56743a791894b99372872fc5af06a4f6e8d242d0615cda53062bb20e6ec79756fe39183f0c128adfe85559a8fa042b042c018aa8010143799e44f0893c40e1e"), None, None, @@ -896,7 +896,7 @@ mod tests { "011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182", 0, "d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e", - SchnorrSigHashType::All, + SchnorrSighashType::All, None, Some("20cc4e1107aea1d170c5ff5b6817e1303010049724fb3caa7941792ea9d29b3e2bacab"), None, @@ -910,7 +910,7 @@ mod tests { "011bec34000000000022512028055142ea437db73382e991861446040b61dd2185c4891d7daf6893d79f7182", 0, "d66de5274a60400c7b08c86ba6b7f198f40660079edf53aca89d2a9501317f2e", - SchnorrSigHashType::All, + SchnorrSighashType::All, None, None, Some("15a2530514e399f8b5cf0b3d3112cf5b289eaa3e308ba2071b58392fdc6da68a"), @@ -924,7 +924,7 @@ mod tests { "011458360000000000225120a7baec3fb9f84614e3899fcc010c638f80f13539344120e1f4d8b68a9a011a13", 0, "a0042aa434f9a75904b64043f2a283f8b4c143c7f4f7f49a6cbe5b9f745f4c15", - SchnorrSigHashType::All, + SchnorrSighashType::All, Some("50a6272b470e1460e3332ade7bb14b81671c564fb6245761bd5bd531394b28860e0b3808ab229fb51791fb6ae6fa82d915b2efb8f6df83ae1f5ab3db13e30928875e2a22b749d89358de481f19286cd4caa792ce27f9559082d227a731c5486882cc707f83da361c51b7aadd9a0cf68fe7480c410fa137b454482d9a1ebf0f96d760b4d61426fc109c6e8e99a508372c45caa7b000a41f8251305da3f206c1849985ba03f3d9592832b4053afbd23ab25d0465df0bc25a36c223aacf8e04ec736a418c72dc319e4da3e972e349713ca600965e7c665f2090d5a70e241ac164115a1f5639f28b1773327715ca307ace64a2de7f0e3df70a2ffee3857689f909c0dad46d8a20fa373a4cc6eed6d4c9806bf146f0d76baae1"), Some("7520ab9160dd8299dc1367659be3e8f66781fe440d52940c7f8d314a89b9f2698d406ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6ead6eadac"), None, @@ -945,27 +945,27 @@ mod tests { let empty_vec = vec![]; let empty_prevouts : Prevouts = Prevouts::All(&empty_vec); assert_eq!( - c.taproot_signature_hash(0, &empty_prevouts, None, None, SchnorrSigHashType::All), + c.taproot_signature_hash(0, &empty_prevouts, None, None, SchnorrSighashType::All), Err(Error::PrevoutsSize) ); let two = vec![TxOut::default(), TxOut::default()]; let too_many_prevouts = Prevouts::All(&two); assert_eq!( - c.taproot_signature_hash(0, &too_many_prevouts, None, None, SchnorrSigHashType::All), + c.taproot_signature_hash(0, &too_many_prevouts, None, None, SchnorrSighashType::All), Err(Error::PrevoutsSize) ); let tx_out = TxOut::default(); let prevout = Prevouts::One(1, &tx_out); assert_eq!( - c.taproot_signature_hash(0, &prevout, None, None, SchnorrSigHashType::All), + c.taproot_signature_hash(0, &prevout, None, None, SchnorrSighashType::All), Err(Error::PrevoutKind) ); assert_eq!( - c.taproot_signature_hash(0, &prevout, None, None, SchnorrSigHashType::AllPlusAnyoneCanPay), + c.taproot_signature_hash(0, &prevout, None, None, SchnorrSighashType::AllPlusAnyoneCanPay), Err(Error::PrevoutIndex) ); assert_eq!( - c.taproot_signature_hash(10, &prevout, None, None, SchnorrSigHashType::AllPlusAnyoneCanPay), + c.taproot_signature_hash(10, &prevout, None, None, SchnorrSighashType::AllPlusAnyoneCanPay), Err(Error::IndexOutOfInputsBounds { index: 10, inputs_size: 1 @@ -973,7 +973,7 @@ mod tests { ); let prevout = Prevouts::One(0, &tx_out); assert_eq!( - c.taproot_signature_hash(0, &prevout, None, None, SchnorrSigHashType::SinglePlusAnyoneCanPay), + c.taproot_signature_hash(0, &prevout, None, None, SchnorrSighashType::SinglePlusAnyoneCanPay), Err(Error::SingleWithoutCorrespondingOutput { index: 0, outputs_size: 0 @@ -1000,7 +1000,7 @@ mod tests { prevout_hex: &str, input_index: usize, expected_hash: &str, - sighash_type: SchnorrSigHashType, + sighash_type: SchnorrSighashType, annex_hex: Option<&str>, script_hex: Option<&str>, script_leaf_hash: Option<&str>, @@ -1087,7 +1087,7 @@ mod tests { } else { Some(hex_hash!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap())) }; - let hash_ty = SchnorrSigHashType::from_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap(); + let hash_ty = SchnorrSighashType::from_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap(); let expected_internal_pk = hex_hash!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap()); let expected_tweak = hex_hash!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap()); @@ -1096,9 +1096,9 @@ mod tests { let expected_sig_hash = hex_hash!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap()); let sig_str = inp["expected"]["witness"][0].as_str().unwrap(); let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 { - (secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSigHashType::Default) + (secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSighashType::Default) } else { - let hash_ty = SchnorrSigHashType::from_u8(Vec::::from_hex(&sig_str[128..]).unwrap()[0]).unwrap(); + let hash_ty = SchnorrSighashType::from_u8(Vec::::from_hex(&sig_str[128..]).unwrap()[0]).unwrap(); (secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty) }; @@ -1148,18 +1148,18 @@ mod tests { #[test] fn sighashtype_fromstr_display() { let sighashtypes = vec![ - ("SIGHASH_DEFAULT", SchnorrSigHashType::Default), - ("SIGHASH_ALL", SchnorrSigHashType::All), - ("SIGHASH_NONE", SchnorrSigHashType::None), - ("SIGHASH_SINGLE", SchnorrSigHashType::Single), - ("SIGHASH_ALL|SIGHASH_ANYONECANPAY", SchnorrSigHashType::AllPlusAnyoneCanPay), - ("SIGHASH_NONE|SIGHASH_ANYONECANPAY", SchnorrSigHashType::NonePlusAnyoneCanPay), - ("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", SchnorrSigHashType::SinglePlusAnyoneCanPay), - ("SIGHASH_RESERVED", SchnorrSigHashType::Reserved), + ("SIGHASH_DEFAULT", SchnorrSighashType::Default), + ("SIGHASH_ALL", SchnorrSighashType::All), + ("SIGHASH_NONE", SchnorrSighashType::None), + ("SIGHASH_SINGLE", SchnorrSighashType::Single), + ("SIGHASH_ALL|SIGHASH_ANYONECANPAY", SchnorrSighashType::AllPlusAnyoneCanPay), + ("SIGHASH_NONE|SIGHASH_ANYONECANPAY", SchnorrSighashType::NonePlusAnyoneCanPay), + ("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", SchnorrSighashType::SinglePlusAnyoneCanPay), + ("SIGHASH_RESERVED", SchnorrSighashType::Reserved), ]; for (s, sht) in sighashtypes { assert_eq!(sht.to_string(), s); - assert_eq!(SchnorrSigHashType::from_str(s).unwrap(), sht); + assert_eq!(SchnorrSighashType::from_str(s).unwrap(), sht); } let sht_mistakes = vec![ "SIGHASH_ALL | SIGHASH_ANYONECANPAY", @@ -1176,7 +1176,7 @@ mod tests { "SigHash_NONE", ]; for s in sht_mistakes { - assert_eq!(SchnorrSigHashType::from_str(s).unwrap_err().to_string(), format!("Unrecognized SIGHASH string '{}'", s)); + assert_eq!(SchnorrSighashType::from_str(s).unwrap_err().to_string(), format!("Unrecognized SIGHASH string '{}'", s)); } } } From 130e27349edb79a535ea731b4f54f2efd221abe7 Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 29 Mar 2022 08:54:02 +1100 Subject: [PATCH 25/40] Rename SigHashTypeParseError -> SighashTypeParseError Our usage of `SigHash` implies that 'sighash' is _two_ words; 'sighash' is a well known word in the Bitcoin ecosystem it should appear in identifiers as `Sighash`. Rename `SigHashTypeParseError` to `SighashTypeParseError`. --- src/blockdata/transaction.rs | 10 +++++----- src/util/psbt/map/input.rs | 8 ++++---- src/util/sighash.rs | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 984e1ac88a..ee5bc4f9a2 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -778,7 +778,7 @@ impl fmt::Display for EcdsaSighashType { } impl str::FromStr for EcdsaSighashType { - type Err = SigHashTypeParseError; + type Err = SighashTypeParseError; fn from_str(s: &str) -> Result { match s { @@ -788,7 +788,7 @@ impl str::FromStr for EcdsaSighashType { "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() }), + _ => Err(SighashTypeParseError { unrecognized: s.to_owned() }), } } } @@ -875,12 +875,12 @@ impl EcdsaSighashType { /// /// 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) } @@ -888,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 { diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index 6362748d2b..f575a5c8e5 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -20,7 +20,7 @@ use core::str::FromStr; use secp256k1; use blockdata::script::Script; use blockdata::witness::Witness; -use blockdata::transaction::{Transaction, TxOut, NonStandardSigHashType, SigHashTypeParseError}; +use blockdata::transaction::{Transaction, TxOut, NonStandardSigHashType, SighashTypeParseError}; use consensus::encode; use hashes::{self, hash160, ripemd160, sha256, sha256d}; use secp256k1::XOnlyPublicKey; @@ -167,7 +167,7 @@ impl fmt::Display for PsbtSigHashType { } impl FromStr for PsbtSigHashType { - type Err = SigHashTypeParseError; + type Err = SighashTypeParseError; #[inline] fn from_str(s: &str) -> Result { @@ -177,7 +177,7 @@ impl FromStr for PsbtSigHashType { // inputs. We also do not support SIGHASH_RESERVED in verbatim form // ("0xFF" string should be used instead). match SchnorrSighashType::from_str(s) { - Ok(SchnorrSighashType::Reserved) => return Err(SigHashTypeParseError{ unrecognized: s.to_owned() }), + Ok(SchnorrSighashType::Reserved) => return Err(SighashTypeParseError{ unrecognized: s.to_owned() }), Ok(ty) => return Ok(ty.into()), Err(_) => {} } @@ -188,7 +188,7 @@ impl FromStr for PsbtSigHashType { return Ok(PsbtSigHashType { inner }); } - Err(SigHashTypeParseError{ unrecognized: s.to_owned() }) + Err(SighashTypeParseError{ unrecognized: s.to_owned() }) } } impl From for PsbtSigHashType { diff --git a/src/util/sighash.rs b/src/util/sighash.rs index 2eb62309b3..6babb5a0b0 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -22,7 +22,7 @@ use prelude::*; -pub use blockdata::transaction::{EcdsaSighashType, SigHashTypeParseError}; +pub use blockdata::transaction::{EcdsaSighashType, SighashTypeParseError}; use blockdata::witness::Witness; use consensus::{encode, Encodable}; use core::{str, fmt}; @@ -148,7 +148,7 @@ impl fmt::Display for SchnorrSighashType { } impl str::FromStr for SchnorrSighashType { - type Err = SigHashTypeParseError; + type Err = SighashTypeParseError; fn from_str(s: &str) -> Result { match s { @@ -160,7 +160,7 @@ impl str::FromStr for SchnorrSighashType { "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::NonePlusAnyoneCanPay), "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SchnorrSighashType::SinglePlusAnyoneCanPay), "SIGHASH_RESERVED" => Ok(SchnorrSighashType::Reserved), - _ => Err(SigHashTypeParseError{ unrecognized: s.to_owned() }), + _ => Err(SighashTypeParseError{ unrecognized: s.to_owned() }), } } } From c19ec339efec462464bb829742e6326d8121adbd Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 29 Mar 2022 08:56:36 +1100 Subject: [PATCH 26/40] Rename NonStandardSigHashType -> NonStandardSighashType Our usage of `SigHash` implies that 'sighash' is _two_ words; 'sighash' is a well known word in the Bitcoin ecosystem it should appear in identifiers as `Sighash`. Rename the `NonStandardSigHashType` type and error variant to `NonStandardSighashType`. --- src/blockdata/transaction.rs | 14 +++++++------- src/util/ecdsa.rs | 14 +++++++------- src/util/psbt/error.rs | 4 ++-- src/util/psbt/map/input.rs | 8 ++++---- src/util/psbt/serialize.rs | 6 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index ee5bc4f9a2..41b355e1e1 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -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,7 +733,7 @@ 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")] @@ -843,7 +843,7 @@ impl EcdsaSighashType { /// 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 { + pub fn from_u32_standard(n: u32) -> Result { EcdsaSighashType::from_standard(n) } @@ -852,7 +852,7 @@ impl EcdsaSighashType { /// # Errors /// /// If `n` is a non-standard sighash value. - pub fn from_standard(n: u32) -> Result { + 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), @@ -861,7 +861,7 @@ impl EcdsaSighashType { 0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), 0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), 0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), - non_standard => Err(NonStandardSigHashType(non_standard)) + non_standard => Err(NonStandardSighashType(non_standard)) } } @@ -1202,7 +1202,7 @@ mod tests { // This type is not well defined, by consensus it becomes 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] diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 75082dc48d..431b368af5 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -20,7 +20,7 @@ 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; @@ -48,7 +48,7 @@ impl EcdsaSig { let (hash_ty, sig) = sl.split_last() .ok_or(EcdsaSigError::EmptySignature)?; let hash_ty = EcdsaSighashType::from_standard(*hash_ty as u32) - .map_err(|_| EcdsaSigError::NonStandardSigHashType(*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 }) @@ -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..be5aeba2ca 100644 --- a/src/util/psbt/error.rs +++ b/src/util/psbt/error.rs @@ -62,7 +62,7 @@ pub enum Error { actual: Box, }, /// Unable to parse as a standard SigHash type. - NonStandardSigHashType(u32), + 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 f575a5c8e5..5733f71f18 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -20,7 +20,7 @@ use core::str::FromStr; use secp256k1; use blockdata::script::Script; use blockdata::witness::Witness; -use blockdata::transaction::{Transaction, TxOut, NonStandardSigHashType, SighashTypeParseError}; +use blockdata::transaction::{Transaction, TxOut, NonStandardSighashType, SighashTypeParseError}; use consensus::encode; use hashes::{self, hash160, ripemd160, sha256, sha256d}; use secp256k1::XOnlyPublicKey; @@ -206,7 +206,7 @@ impl From for PsbtSigHashType { impl PsbtSigHashType { /// Returns the [`EcdsaSighashType`] if the [`PsbtSigHashType`] can be /// converted to one. - pub fn ecdsa_hash_ty(self) -> Result { + pub fn ecdsa_hash_ty(self) -> Result { EcdsaSighashType::from_standard(self.inner) } @@ -244,7 +244,7 @@ impl Input { /// # Errors /// /// If the `sighash_type` field is set to a non-standard ECDSA sighash value. - pub fn ecdsa_hash_ty(&self) -> Result { + pub fn ecdsa_hash_ty(&self) -> Result { self.sighash_type .map(|sighash_type| sighash_type.ecdsa_hash_ty()) .unwrap_or(Ok(EcdsaSighashType::All)) @@ -600,7 +600,7 @@ mod test { let back = PsbtSigHashType::from_str(&s).unwrap(); assert_eq!(back, sighash); - assert_eq!(back.ecdsa_hash_ty(), Err(NonStandardSigHashType(nonstd))); + assert_eq!(back.ecdsa_hash_ty(), Err(NonStandardSighashType(nonstd))); assert_eq!(back.schnorr_hash_ty(), Err(sighash::Error::InvalidSigHashType(nonstd))); } } diff --git a/src/util/psbt/serialize.rs b/src/util/psbt/serialize.rs index e555d059ae..d825181129 100644 --- a/src/util/psbt/serialize.rs +++ b/src/util/psbt/serialize.rs @@ -130,8 +130,8 @@ impl Deserialize for EcdsaSig { EcdsaSigError::EmptySignature => { encode::Error::ParseFailed("Empty partial signature data") } - EcdsaSigError::NonStandardSigHashType(flag) => { - encode::Error::from(psbt::Error::NonStandardSigHashType(flag)) + EcdsaSigError::NonStandardSighashType(flag) => { + encode::Error::from(psbt::Error::NonStandardSighashType(flag)) } EcdsaSigError::Secp256k1(..) => { encode::Error::ParseFailed("Invalid Ecdsa signature") @@ -229,7 +229,7 @@ impl Deserialize for schnorr::SchnorrSig { schnorr::SchnorrSig::from_slice(&bytes) .map_err(|e| match e { schnorr::SchnorrSigError::InvalidSighashType(flag) => { - encode::Error::from(psbt::Error::NonStandardSigHashType(flag as u32)) + encode::Error::from(psbt::Error::NonStandardSighashType(flag as u32)) } schnorr::SchnorrSigError::InvalidSchnorrSigSize(_) => { encode::Error::ParseFailed("Invalid Schnorr signature length") From e37652578ba2aa1109275a92eae96992c9763abb Mon Sep 17 00:00:00 2001 From: Tobin Harding Date: Tue, 29 Mar 2022 08:58:07 +1100 Subject: [PATCH 27/40] Rename PsbtSigHashType -> PsbtSighashType Our usage of `SigHash` implies that 'sighash' is _two_ words; 'sighash' is a well known word in the Bitcoin ecosystem it should appear in identifiers as `Sighash`. Rename `PsbtSigHashType` to `PsbtSighashType`. --- src/util/psbt/map/input.rs | 52 +++++++++++++++++++------------------- src/util/psbt/map/mod.rs | 2 +- src/util/psbt/mod.rs | 2 +- src/util/psbt/serialize.rs | 10 ++++---- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index 5733f71f18..d0f22f3e01 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -95,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