diff --git a/examples/taproot.rs b/examples/taproot.rs index 996d82313..9d829d066 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -6,7 +6,7 @@ use bitcoin::util::address::WitnessVersion; use bitcoin::Network; use miniscript::descriptor::DescriptorType; use miniscript::policy::Concrete; -use miniscript::{Descriptor, Miniscript, Tap, TranslatePk, Translator}; +use miniscript::{hash256, Descriptor, Miniscript, Tap, TranslatePk, Translator}; use secp256k1::{rand, KeyPair}; // Refer to https://github.com/sanket1729/adv_btc_workshop/blob/master/workshop.md#creating-a-taproot-descriptor @@ -28,6 +28,10 @@ impl Translator for StrPkTranslator { fn sha256(&mut self, _sha256: &String) -> Result { unreachable!("Policy does not contain any sha256 fragment"); } + + fn hash256(&mut self, _sha256: &String) -> Result { + unreachable!("Policy does not contain any hash256 fragment"); + } } fn main() { diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 49abef16e..9d5dbcc85 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -167,7 +167,7 @@ impl ForEachKey for Bare { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { self.ms.for_each_key(pred) } @@ -329,7 +329,7 @@ impl ForEachKey for Pkh { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { pred(&self.pk) } diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index edcd43b6d..f62d39922 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -10,7 +10,7 @@ use bitcoin::util::bip32; use bitcoin::{self, XOnlyPublicKey, XpubIdentifier}; use crate::prelude::*; -use crate::{MiniscriptKey, ToPublicKey}; +use crate::{hash256, MiniscriptKey, ToPublicKey}; /// The descriptor pubkey, either a single pubkey or an xpub. #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)] @@ -736,8 +736,9 @@ impl DescriptorXKey { impl MiniscriptKey for DescriptorPublicKey { // This allows us to be able to derive public keys even for PkH s - type Hash = Self; - type Sha256 = bitcoin::hashes::sha256::Hash; + type RawPkHash = Self; + type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; fn is_uncompressed(&self) -> bool { match self { @@ -802,8 +803,9 @@ impl fmt::Display for DerivedDescriptorKey { impl MiniscriptKey for DerivedDescriptorKey { // This allows us to be able to derive public keys even for PkH s - type Hash = Self; - type Sha256 = bitcoin::hashes::sha256::Hash; + type RawPkHash = Self; + type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; fn is_uncompressed(&self) -> bool { self.key.is_uncompressed() @@ -831,6 +833,10 @@ impl ToPublicKey for DerivedDescriptorKey { fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } + + fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { + *hash + } } #[cfg(test)] diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 27487ff85..fbeb6cf4a 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -37,8 +37,8 @@ use self::checksum::verify_checksum; use crate::miniscript::{Legacy, Miniscript, Segwitv0}; use crate::prelude::*; use crate::{ - expression, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, PkTranslator, Satisfier, - ToPublicKey, TranslatePk, Translator, + expression, hash256, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, PkTranslator, + Satisfier, ToPublicKey, TranslatePk, Translator, }; mod bare; @@ -498,7 +498,7 @@ impl ForEachKey for Descriptor { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { match *self { Descriptor::Bare(ref bare) => bare.for_each_key(pred), @@ -646,6 +646,12 @@ impl Descriptor { sha256::Hash::from_str(sha256).map_err(|e| Error::Unexpected(e.to_string()))?; Ok(hash) } + + fn hash256(&mut self, hash256: &String) -> Result { + let hash = hash256::Hash::from_str(hash256) + .map_err(|e| Error::Unexpected(e.to_string()))?; + Ok(hash) + } } let descriptor = Descriptor::::from_str(s)?; @@ -672,6 +678,10 @@ impl Descriptor { fn sha256(&mut self, sha256: &sha256::Hash) -> Result { Ok(sha256.to_string()) } + + fn hash256(&mut self, hash256: &hash256::Hash) -> Result { + Ok(hash256.to_string()) + } } fn key_to_string(pk: &DescriptorPublicKey, key_map: &KeyMap) -> Result { diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index f1c0202dc..9f306ccbc 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -249,7 +249,7 @@ impl ForEachKey for Wsh { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { match self.inner { WshInner::SortedMulti(ref smv) => smv.for_each_key(pred), @@ -442,7 +442,7 @@ impl ForEachKey for Wpkh { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { pred(&self.pk) } diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 6d8aa0923..3b387fc85 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -380,7 +380,7 @@ impl ForEachKey for Sh { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { match self.inner { ShInner::Wsh(ref wsh) => wsh.for_each_key(pred), diff --git a/src/descriptor/sortedmulti.rs b/src/descriptor/sortedmulti.rs index 47f1ac627..a79e84507 100644 --- a/src/descriptor/sortedmulti.rs +++ b/src/descriptor/sortedmulti.rs @@ -115,7 +115,7 @@ impl ForEachKey for SortedMultiVec bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { self.pks.iter().all(|key| pred(key)) } diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index b2dc1ee20..7280893f7 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -581,7 +581,7 @@ impl ForEachKey for Tr { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { let script_keys_res = self .iter_scripts() diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 661270ae0..4a7bc14f3 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -23,14 +23,14 @@ use core::fmt; use core::str::FromStr; use bitcoin::blockdata::witness::Witness; -use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::util::{sighash, taproot}; use bitcoin::{self, secp256k1, TxOut}; use crate::miniscript::context::NoChecks; use crate::miniscript::ScriptContext; use crate::prelude::*; -use crate::{Descriptor, Miniscript, Terminal, ToPublicKey}; +use crate::{hash256, Descriptor, Miniscript, Terminal, ToPublicKey}; mod error; mod inner; @@ -148,10 +148,11 @@ impl TypedHash160 { } impl MiniscriptKey for BitcoinKey { - type Hash = TypedHash160; - type Sha256 = bitcoin::hashes::sha256::Hash; + type RawPkHash = TypedHash160; + type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; - fn to_pubkeyhash(&self) -> Self::Hash { + fn to_pubkeyhash(&self) -> Self::RawPkHash { match self { BitcoinKey::Fullkey(pk) => TypedHash160::FullKey(pk.to_pubkeyhash()), BitcoinKey::XOnlyPublicKey(pk) => TypedHash160::XonlyKey(pk.to_pubkeyhash()), @@ -454,7 +455,7 @@ pub enum HashLockType { ///SHA 256 hashlock Sha256(sha256::Hash), ///Hash 256 hashlock - Hash256(sha256d::Hash), + Hash256(hash256::Hash), ///Hash160 hashlock Hash160(hash160::Hash), ///Ripemd160 hashlock @@ -1040,7 +1041,7 @@ fn verify_sersig<'txin>( mod tests { use bitcoin; - use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; + use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; use bitcoin::secp256k1::{self, Secp256k1}; use super::inner::ToNoChecks; @@ -1156,11 +1157,8 @@ mod tests { let preimage = [0xab as u8; 32]; let sha256_hash = sha256::Hash::hash(&preimage); let sha256 = no_checks_ms(&format!("sha256({})", sha256_hash)); - let sha256d_hash_rev = sha256d::Hash::hash(&preimage); - let mut sha256d_hash_bytes = sha256d_hash_rev.clone().into_inner(); - sha256d_hash_bytes.reverse(); - let sha256d_hash = sha256d::Hash::from_inner(sha256d_hash_bytes); - let hash256 = no_checks_ms(&format!("hash256({})", sha256d_hash)); + let hash256_hash = hash256::Hash::hash(&preimage); + let hash256 = no_checks_ms(&format!("hash256({})", hash256_hash)); let hash160_hash = hash160::Hash::hash(&preimage); let hash160 = no_checks_ms(&format!("hash160({})", hash160_hash)); let ripemd160_hash = ripemd160::Hash::hash(&preimage); @@ -1242,7 +1240,7 @@ mod tests { assert_eq!( sha256d_satisfied.unwrap(), vec![SatisfiedConstraint::HashLock { - hash: HashLockType::Hash256(sha256d_hash_rev), + hash: HashLockType::Hash256(hash256_hash), preimage: preimage, }] ); diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index 1b793b979..6591a6afd 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -16,12 +16,13 @@ use bitcoin; use bitcoin::blockdata::{opcodes, script}; -use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; use super::error::PkEvalErrInner; use super::{ verify_sersig, BitcoinKey, Error, HashLockType, KeySigPair, SatisfiedConstraint, TypedHash160, }; +use crate::hash256; use crate::prelude::*; /// Definition of Stack Element of the Stack used for interpretation of Miniscript. @@ -288,13 +289,13 @@ impl<'txin> Stack<'txin> { /// `SIZE 32 EQUALVERIFY HASH256 h EQUAL` pub(super) fn evaluate_hash256( &mut self, - hash: &sha256d::Hash, + hash: &hash256::Hash, ) -> Option> { if let Some(Element::Push(preimage)) = self.pop() { if preimage.len() != 32 { return Some(Err(Error::HashPreimageLengthMismatch)); } - if sha256d::Hash::hash(preimage) == *hash { + if hash256::Hash::hash(preimage) == *hash { self.push(Element::Satisfied); Some(Ok(SatisfiedConstraint::HashLock { hash: HashLockType::Hash256(*hash), diff --git a/src/lib.rs b/src/lib.rs index 338488e1b..115429bc7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,7 +135,7 @@ pub use crate::interpreter::Interpreter; pub use crate::miniscript::context::{BareCtx, Legacy, ScriptContext, Segwitv0, Tap}; pub use crate::miniscript::decode::Terminal; pub use crate::miniscript::satisfy::{Preimage32, Satisfier}; -pub use crate::miniscript::Miniscript; +pub use crate::miniscript::{hash256, Miniscript}; use crate::prelude::*; ///Public key trait which can be converted to Hash type @@ -152,22 +152,30 @@ pub trait MiniscriptKey: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Ha false } - /// The associated [`Hash`] type for this pubkey. - type Hash: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; + /// The associated PublicKey Hash for this [`MiniscriptKey`], + /// used in the raw_pkh fragment + /// This fragment is only internally used for representing partial descriptors when parsing from script + /// The library does not support creating partial descriptors yet. + type RawPkHash: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; - /// The associated [`sha256::Hash`] type for this [`MiniscriptKey`] type. - /// Used in the sha256 fragment + /// The associated [`sha256::Hash`] for this [`MiniscriptKey`], + /// used in the hash256 fragment. type Sha256: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; + /// The associated [`hash256::Hash`] for this [`MiniscriptKey`], + /// used in the hash256 fragment. + type Hash256: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; + /// Converts this key to the associated pubkey hash. - fn to_pubkeyhash(&self) -> Self::Hash; + fn to_pubkeyhash(&self) -> Self::RawPkHash; } impl MiniscriptKey for bitcoin::secp256k1::PublicKey { - type Hash = hash160::Hash; + type RawPkHash = hash160::Hash; type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; - fn to_pubkeyhash(&self) -> Self::Hash { + fn to_pubkeyhash(&self) -> Self::RawPkHash { hash160::Hash::hash(&self.serialize()) } } @@ -178,19 +186,21 @@ impl MiniscriptKey for bitcoin::PublicKey { !self.compressed } - type Hash = hash160::Hash; + type RawPkHash = hash160::Hash; type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; - fn to_pubkeyhash(&self) -> Self::Hash { + fn to_pubkeyhash(&self) -> Self::RawPkHash { hash160::Hash::hash(&self.to_bytes()) } } impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey { - type Hash = hash160::Hash; + type RawPkHash = hash160::Hash; type Sha256 = sha256::Hash; + type Hash256 = hash256::Hash; - fn to_pubkeyhash(&self) -> Self::Hash { + fn to_pubkeyhash(&self) -> Self::RawPkHash { hash160::Hash::hash(&self.serialize()) } @@ -200,10 +210,11 @@ impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey { } impl MiniscriptKey for String { - type Hash = String; + type RawPkHash = String; type Sha256 = String; // specify hashes as string + type Hash256 = String; - fn to_pubkeyhash(&self) -> Self::Hash { + fn to_pubkeyhash(&self) -> Self::RawPkHash { (&self).to_string() } } @@ -225,10 +236,13 @@ pub trait ToPublicKey: MiniscriptKey { /// that calling `MiniscriptKey::to_pubkeyhash` followed by this function /// should give the same result as calling `to_public_key` and hashing /// the result directly. - fn hash_to_hash160(hash: &::Hash) -> hash160::Hash; + fn hash_to_hash160(hash: &::RawPkHash) -> hash160::Hash; /// Converts the generic associated [`MiniscriptKey::Sha256`] to [`sha256::Hash`] fn to_sha256(hash: &::Sha256) -> sha256::Hash; + + /// Converts the generic associated [`MiniscriptKey::Hash256`] to [`hash256::Hash`] + fn to_hash256(hash: &::Hash256) -> hash256::Hash; } impl ToPublicKey for bitcoin::PublicKey { @@ -243,6 +257,10 @@ impl ToPublicKey for bitcoin::PublicKey { fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } + + fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { + *hash + } } impl ToPublicKey for bitcoin::secp256k1::PublicKey { @@ -257,6 +275,10 @@ impl ToPublicKey for bitcoin::secp256k1::PublicKey { fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } + + fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { + *hash + } } impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { @@ -280,6 +302,10 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { fn to_sha256(hash: &sha256::Hash) -> sha256::Hash { *hash } + + fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { + *hash + } } /// Dummy key which de/serializes to the empty string; useful sometimes for testing @@ -298,10 +324,11 @@ impl str::FromStr for DummyKey { } impl MiniscriptKey for DummyKey { - type Hash = DummyKeyHash; + type RawPkHash = DummyKeyHash; type Sha256 = DummySha256Hash; + type Hash256 = DummyHash256; - fn to_pubkeyhash(&self) -> Self::Hash { + fn to_pubkeyhash(&self) -> Self::RawPkHash { DummyKeyHash } } @@ -334,6 +361,11 @@ impl ToPublicKey for DummyKey { sha256::Hash::from_str("50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352") .unwrap() } + + fn to_hash256(_hash: &DummyHash256) -> hash256::Hash { + hash256::Hash::from_str("50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352") + .unwrap() + } } /// Dummy keyhash which de/serializes to the empty string; useful sometimes for testing @@ -390,8 +422,34 @@ impl hash::Hash for DummySha256Hash { } } -/// Describes an object that can translate various keys and hashes from one key to the type -/// associated with the other key. Used by the [`TranslatePk`] trait to do the actual translations. +/// Dummy keyhash which de/serializes to the empty string; useful for testing +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub struct DummyHash256; + +impl str::FromStr for DummyHash256 { + type Err = &'static str; + fn from_str(x: &str) -> Result { + if x.is_empty() { + Ok(DummyHash256) + } else { + Err("non empty dummy hash") + } + } +} + +impl fmt::Display for DummyHash256 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("") + } +} + +impl hash::Hash for DummyHash256 { + fn hash(&self, state: &mut H) { + "DummySha256Hash".hash(state); + } +} + +/// Provides the conversion information required in [`TranslatePk`] pub trait Translator where P: MiniscriptKey, @@ -401,10 +459,13 @@ where fn pk(&mut self, pk: &P) -> Result; /// Translates public key hashes P::Hash -> Q::Hash. - fn pkh(&mut self, pkh: &P::Hash) -> Result; + fn pkh(&mut self, pkh: &P::RawPkHash) -> Result; - /// Translates sha256 hashes from P::Sha256 -> Q::Sha256 + /// Provides the translation from P::Sha256 -> Q::Sha256 fn sha256(&mut self, sha256: &P::Sha256) -> Result; + + /// Provides the translation from P::Hash256 -> Q::Hash256 + fn hash256(&mut self, hash256: &P::Hash256) -> Result; } /// Provides the conversion information required in [`TranslatePk`]. @@ -419,26 +480,33 @@ where fn pk(&mut self, pk: &P) -> Result; /// Provides the translation public keys hashes P::Hash -> Q::Hash - fn pkh(&mut self, pkh: &P::Hash) -> Result; + fn pkh(&mut self, pkh: &P::RawPkHash) -> Result; } impl Translator for T where T: PkTranslator, P: MiniscriptKey, - Q: MiniscriptKey, + Q: MiniscriptKey, { fn pk(&mut self, pk: &P) -> Result { >::pk(self, pk) } - fn pkh(&mut self, pkh: &

::Hash) -> Result<::Hash, E> { + fn pkh( + &mut self, + pkh: &

::RawPkHash, + ) -> Result<::RawPkHash, E> { >::pkh(self, pkh) } fn sha256(&mut self, sha256: &

::Sha256) -> Result<::Sha256, E> { Ok(sha256.clone()) } + + fn hash256(&mut self, hash256: &

::Hash256) -> Result<::Hash256, E> { + Ok(hash256.clone()) + } } /// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do @@ -475,14 +543,14 @@ pub trait ForEachKey { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a; + Pk::RawPkHash: 'a; /// Run a predicate on every key in the descriptor, returning whether /// the predicate returned true for any key fn for_any_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { !self.for_each_key(|key| !pred(key)) } diff --git a/src/macros.rs b/src/macros.rs index 7f59aa9a2..954bf96d1 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -27,11 +27,13 @@ macro_rules! impl_from_tree { impl $crate::expression::FromTree for $name where Pk: MiniscriptKey + core::str::FromStr, - Pk::Hash: core::str::FromStr, + Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, + Pk::Hash256: core::str::FromStr, ::Err: $crate::prelude::ToString, - <::Hash as core::str::FromStr>::Err: $crate::prelude::ToString, + <::RawPkHash as core::str::FromStr>::Err: $crate::prelude::ToString, <::Sha256 as core::str::FromStr>::Err: $crate::prelude::ToString, + <::Hash256 as core::str::FromStr>::Err: $crate::prelude::ToString, $($gen : $gen_con,)* { @@ -55,11 +57,13 @@ macro_rules! impl_from_str { impl core::str::FromStr for $name where Pk: MiniscriptKey + core::str::FromStr, - Pk::Hash: core::str::FromStr, + Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, + Pk::Hash256: core::str::FromStr, ::Err: $crate::prelude::ToString, - <::Hash as core::str::FromStr>::Err: $crate::prelude::ToString, + <::RawPkHash as core::str::FromStr>::Err: $crate::prelude::ToString, <::Sha256 as core::str::FromStr>::Err: $crate::prelude::ToString, + <::Hash256 as core::str::FromStr>::Err: $crate::prelude::ToString, $($gen : $gen_con,)* { type Err = $err_ty; @@ -83,11 +87,13 @@ macro_rules! impl_block_str { impl $name where Pk: MiniscriptKey + core::str::FromStr, - Pk::Hash: core::str::FromStr, + Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, + Pk::Hash256: core::str::FromStr, ::Err: $crate::prelude::ToString, - <::Hash as core::str::FromStr>::Err: $crate::prelude::ToString, + <::RawPkHash as core::str::FromStr>::Err: $crate::prelude::ToString, <::Sha256 as core::str::FromStr>::Err: $crate::prelude::ToString, + <::Hash256 as core::str::FromStr>::Err: $crate::prelude::ToString, $($gen : $gen_con,)* { $(#[$meta])* @@ -106,13 +112,16 @@ macro_rules! serde_string_impl_pk { impl<'de, Pk $(, $gen)*> $crate::serde::Deserialize<'de> for $name where Pk: $crate::MiniscriptKey + core::str::FromStr, - Pk::Hash: core::str::FromStr, + Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, + Pk::Hash256: core::str::FromStr, ::Err: core::fmt::Display, - <::Hash as core::str::FromStr>::Err: + <::RawPkHash as core::str::FromStr>::Err: core::fmt::Display, <::Sha256 as core::str::FromStr>::Err: core::fmt::Display, + <::Hash256 as core::str::FromStr>::Err: + core::fmt::Display, $($gen : $gen_con,)* { fn deserialize(deserializer: D) -> Result<$name, D::Error> @@ -128,13 +137,16 @@ macro_rules! serde_string_impl_pk { impl<'de, Pk $(, $gen)*> $crate::serde::de::Visitor<'de> for Visitor where Pk: $crate::MiniscriptKey + core::str::FromStr, - Pk::Hash: core::str::FromStr, + Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, + Pk::Hash256: core::str::FromStr, ::Err: core::fmt::Display, - <::Hash as core::str::FromStr>::Err: + <::RawPkHash as core::str::FromStr>::Err: core::fmt::Display, <::Sha256 as core::str::FromStr>::Err: core::fmt::Display, + <::Hash256 as core::str::FromStr>::Err: + core::fmt::Display, $($gen: $gen_con,)* { type Value = $name; diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index 4a4c34459..566bde7a6 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -24,7 +24,7 @@ use core::str::FromStr; use bitcoin::blockdata::{opcodes, script}; use bitcoin::hashes::hex::FromHex; -use bitcoin::hashes::{hash160, ripemd160, sha256d, Hash}; +use bitcoin::hashes::{hash160, ripemd160}; use sync::Arc; use crate::miniscript::context::SigType; @@ -79,7 +79,7 @@ impl Terminal { pub(super) fn real_for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: &mut F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { match *self { Terminal::PkK(ref p) => pred(p), @@ -133,7 +133,7 @@ impl Terminal { Terminal::After(n) => Terminal::After(n), Terminal::Older(n) => Terminal::Older(n), Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(&x)?), - Terminal::Hash256(x) => Terminal::Hash256(x), + Terminal::Hash256(ref x) => Terminal::Hash256(t.hash256(&x)?), Terminal::Ripemd160(x) => Terminal::Ripemd160(x), Terminal::Hash160(x) => Terminal::Hash160(x), Terminal::True => Terminal::True, @@ -200,7 +200,7 @@ impl ForEachKey for Terminal fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { self.real_for_each_key(&mut pred) } @@ -259,11 +259,7 @@ impl fmt::Debug for Terminal { Terminal::After(t) => write!(f, "after({})", t), Terminal::Older(t) => write!(f, "older({})", t), Terminal::Sha256(ref h) => write!(f, "sha256({})", h), - Terminal::Hash256(h) => { - let mut x = h.into_inner(); - x.reverse(); - write!(f, "hash256({})", sha256d::Hash::from_inner(x)) - } + Terminal::Hash256(ref h) => write!(f, "hash256({})", h), Terminal::Ripemd160(h) => write!(f, "ripemd160({})", h), Terminal::Hash160(h) => write!(f, "hash160({})", h), Terminal::True => f.write_str("1"), @@ -317,11 +313,7 @@ impl fmt::Display for Terminal { Terminal::After(t) => write!(f, "after({})", t), Terminal::Older(t) => write!(f, "older({})", t), Terminal::Sha256(ref h) => write!(f, "sha256({})", h), - Terminal::Hash256(h) => { - let mut x = h.into_inner(); - x.reverse(); - write!(f, "hash256({})", sha256d::Hash::from_inner(x)) - } + Terminal::Hash256(ref h) => write!(f, "hash256({})", h), Terminal::Ripemd160(h) => write!(f, "ripemd160({})", h), Terminal::Hash160(h) => write!(f, "hash160({})", h), Terminal::True => f.write_str("1"), @@ -478,13 +470,7 @@ impl_from_tree!( Pk::Sha256::from_str(x).map(Terminal::Sha256) }), ("hash256", 1) => expression::terminal(&top.args[0], |x| { - sha256d::Hash::from_hex(x) - .map(|x| x.into_inner()) - .map(|mut x| { - x.reverse(); - x - }) - .map(|x| Terminal::Hash256(sha256d::Hash::from_inner(x))) + Pk::Hash256::from_str(x).map(Terminal::Hash256) }), ("ripemd160", 1) => expression::terminal(&top.args[0], |x| { ripemd160::Hash::from_hex(x).map(Terminal::Ripemd160) @@ -646,12 +632,12 @@ impl Terminal { .push_opcode(opcodes::all::OP_SHA256) .push_slice(&Pk::to_sha256(&h)) .push_opcode(opcodes::all::OP_EQUAL), - Terminal::Hash256(h) => builder + Terminal::Hash256(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) .push_int(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH256) - .push_slice(&h[..]) + .push_slice(&Pk::to_hash256(&h)) .push_opcode(opcodes::all::OP_EQUAL), Terminal::Ripemd160(h) => builder .push_opcode(opcodes::all::OP_SIZE) diff --git a/src/miniscript/context.rs b/src/miniscript/context.rs index 645eef235..b63bc5ba9 100644 --- a/src/miniscript/context.rs +++ b/src/miniscript/context.rs @@ -18,6 +18,7 @@ use std::error; use bitcoin; use bitcoin::blockdata::constants::MAX_BLOCK_WEIGHT; +use bitcoin::hashes::{hash160, sha256}; use super::decode::ParseableKey; use crate::miniscript::limits::{ @@ -28,7 +29,7 @@ use crate::miniscript::limits::{ use crate::miniscript::types; use crate::prelude::*; use crate::util::witness_to_scriptsig; -use crate::{Error, Miniscript, MiniscriptKey, Terminal}; +use crate::{hash256, Error, Miniscript, MiniscriptKey, Terminal}; /// Error for Script Context #[derive(Clone, PartialEq, Eq, Debug)] @@ -190,8 +191,9 @@ impl fmt::Display for ScriptContextError { pub trait ScriptContext: fmt::Debug + Clone + Ord + PartialOrd + Eq + PartialEq + hash::Hash + private::Sealed where - Self::Key: MiniscriptKey, - Self::Key: MiniscriptKey, + Self::Key: MiniscriptKey, + Self::Key: MiniscriptKey, + Self::Key: MiniscriptKey, { /// The consensus key associated with the type. Must be a parseable key type Key: ParseableKey; diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index e6a0f9fa8..e7dc9404b 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -23,7 +23,7 @@ use core::marker::PhantomData; use std::error; use bitcoin::blockdata::constants::MAX_BLOCK_WEIGHT; -use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; use sync::Arc; use crate::miniscript::lex::{Token as Tk, TokenIter}; @@ -32,7 +32,7 @@ use crate::miniscript::types::extra_props::ExtData; use crate::miniscript::types::{Property, Type}; use crate::miniscript::ScriptContext; use crate::prelude::*; -use crate::{bitcoin, Error, Miniscript, MiniscriptKey, ToPublicKey}; +use crate::{bitcoin, hash256, Error, Miniscript, MiniscriptKey, ToPublicKey}; fn return_none(_: usize) -> Option { None @@ -136,7 +136,7 @@ pub enum Terminal { /// `DUP HASH160 EQUALVERIFY` PkH(Pk), /// Only for parsing PkH for Script - RawPkH(Pk::Hash), + RawPkH(Pk::RawPkHash), // timelocks /// `n CHECKLOCKTIMEVERIFY` After(u32), @@ -146,7 +146,7 @@ pub enum Terminal { /// `SIZE 32 EQUALVERIFY SHA256 EQUAL` Sha256(Pk::Sha256), /// `SIZE 32 EQUALVERIFY HASH256 EQUAL` - Hash256(sha256d::Hash), + Hash256(Pk::Hash256), /// `SIZE 32 EQUALVERIFY RIPEMD160 EQUAL` Ripemd160(ripemd160::Hash), /// `SIZE 32 EQUALVERIFY HASH160 EQUAL` @@ -368,7 +368,7 @@ pub fn parse( Tk::Hash256, Tk::Verify, Tk::Equal, Tk::Num(32), Tk::Size => { non_term.push(NonTerm::Verify); term.reduce0(Terminal::Hash256( - sha256d::Hash::from_slice(hash).expect("valid size") + hash256::Hash::from_slice(hash).expect("valid size") ))? }, ), @@ -412,7 +412,7 @@ pub fn parse( Tk::Equal, Tk::Num(32), Tk::Size => term.reduce0(Terminal::Hash256( - sha256d::Hash::from_slice(hash).expect("valid size") + hash256::Hash::from_slice(hash).expect("valid size") ))?, ), Tk::Hash20(hash) => match_token!( diff --git a/src/miniscript/hash256.rs b/src/miniscript/hash256.rs new file mode 100644 index 000000000..013b2ebe2 --- /dev/null +++ b/src/miniscript/hash256.rs @@ -0,0 +1,88 @@ +// Miniscript +// Written in 2022 by +// Sanket Kanjalkar +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! Hash256 type +//! +//! This module is _identical_ in functionality to the `bitcoin_hashes::sha256d` hash type +//! but the `FromHex/FromStr` and `ToHex/Display` implementations use `DISPLAY_BACKWARDS = false`. +//! +use core::str; + +use bitcoin::hashes::{ + self, borrow_slice_impl, hex, hex_fmt_impl, index_impl, serde_impl, sha256, Hash as HashTrait, +}; + +/// Output of the SHA256d hash function +#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct Hash([u8; 32]); + +hex_fmt_impl!(Debug, Hash); +hex_fmt_impl!(Display, Hash); +hex_fmt_impl!(LowerHex, Hash); +index_impl!(Hash); +serde_impl!(Hash, 32); +borrow_slice_impl!(Hash); + +impl str::FromStr for Hash { + type Err = hex::Error; + fn from_str(s: &str) -> Result { + hex::FromHex::from_hex(s) + } +} + +impl HashTrait for Hash { + type Engine = sha256::HashEngine; + type Inner = [u8; 32]; + + fn engine() -> sha256::HashEngine { + sha256::Hash::engine() + } + + fn from_engine(e: sha256::HashEngine) -> Hash { + let sha2 = sha256::Hash::from_engine(e); + let sha2d = sha256::Hash::hash(&sha2[..]); + + let mut ret = [0; 32]; + ret.copy_from_slice(&sha2d[..]); + Hash(ret) + } + + const LEN: usize = 32; + + fn from_slice(sl: &[u8]) -> Result { + if sl.len() != 32 { + Err(hashes::Error::InvalidLength(Self::LEN, sl.len())) + } else { + let mut ret = [0; 32]; + ret.copy_from_slice(sl); + Ok(Hash(ret)) + } + } + + /// sha256d has DISPLAY_BACKWARD as true + const DISPLAY_BACKWARD: bool = false; + + fn into_inner(self) -> Self::Inner { + self.0 + } + + fn as_inner(&self) -> &Self::Inner { + &self.0 + } + + fn from_inner(inner: Self::Inner) -> Self { + Hash(inner) + } +} diff --git a/src/miniscript/iter.rs b/src/miniscript/iter.rs index a3dff1b8b..1df400902 100644 --- a/src/miniscript/iter.rs +++ b/src/miniscript/iter.rs @@ -140,7 +140,7 @@ impl Miniscript { /// NB: The function analyzes only single miniscript item and not any of its descendants in AST. /// To obtain a list of all public key hashes within AST use [Miniscript::iter_pkh()] function, /// for example `miniscript.iter_pubkey_hashes().collect()`. - pub fn get_leapkh(&self) -> Vec { + pub fn get_leapkh(&self) -> Vec { match self.node { Terminal::RawPkH(ref hash) => vec![hash.clone()], Terminal::PkK(ref key) | Terminal::PkH(ref key) => vec![key.to_pubkeyhash()], @@ -193,7 +193,7 @@ impl Miniscript { /// returns it cloned copy. /// /// NB: The function analyzes only single miniscript item and not any of its descendants in AST. - pub fn get_nth_pkh(&self, n: usize) -> Option { + pub fn get_nth_pkh(&self, n: usize) -> Option { match (&self.node, n) { (&Terminal::RawPkH(ref hash), 0) => Some(hash.clone()), (&Terminal::PkK(ref key), 0) | (&Terminal::PkH(ref key), 0) => { @@ -348,7 +348,7 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> PkhIter<'a, Pk, Ctx> { } impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> Iterator for PkhIter<'a, Pk, Ctx> { - type Item = Pk::Hash; + type Item = Pk::RawPkHash; fn next(&mut self) -> Option { loop { @@ -376,10 +376,10 @@ pub enum PkPkh { /// Plain public key PlainPubkey(Pk), /// Hashed public key - HashedPubkey(Pk::Hash), + HashedPubkey(Pk::RawPkHash), } -impl> PkPkh { +impl> PkPkh { /// Convenience method to avoid distinguishing between keys and hashes when these are the same type pub fn as_key(self) -> Pk { match self { diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index fd81d9d78..9d50d63d1 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -37,6 +37,7 @@ pub mod analyzable; pub mod astelem; pub(crate) mod context; pub mod decode; +pub mod hash256; pub mod iter; pub mod lex; pub mod limits; @@ -272,7 +273,7 @@ impl ForEachKey for Miniscript bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { self.real_for_each_key(&mut pred) } @@ -300,7 +301,7 @@ impl Miniscript { fn real_for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: &mut F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { self.node.real_for_each_key(pred) } diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 6f3be9bbd..0ed6f285b 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -21,7 +21,7 @@ use core::{cmp, i64, mem}; use bitcoin; -use bitcoin::hashes::{hash160, ripemd160, sha256d}; +use bitcoin::hashes::{hash160, ripemd160}; use bitcoin::secp256k1::XOnlyPublicKey; use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapLeafHash}; use sync::Arc; @@ -63,7 +63,7 @@ pub trait Satisfier { } /// Given a `Pkh`, lookup corresponding `Pk` - fn lookup_pkh_pk(&self, _: &Pk::Hash) -> Option { + fn lookup_pkh_pk(&self, _: &Pk::RawPkHash) -> Option { None } @@ -73,7 +73,7 @@ pub trait Satisfier { /// for dissatisfying pkh. fn lookup_pkh_ecdsa_sig( &self, - _: &Pk::Hash, + _: &Pk::RawPkHash, ) -> Option<(bitcoin::PublicKey, bitcoin::EcdsaSig)> { None } @@ -84,7 +84,7 @@ pub trait Satisfier { /// for dissatisfying pkh. fn lookup_pkh_tap_leaf_script_sig( &self, - _: &(Pk::Hash, TapLeafHash), + _: &(Pk::RawPkHash, TapLeafHash), ) -> Option<(XOnlyPublicKey, bitcoin::SchnorrSig)> { None } @@ -95,7 +95,7 @@ pub trait Satisfier { } /// Given a HASH256 hash, look up its preimage - fn lookup_hash256(&self, _: sha256d::Hash) -> Option { + fn lookup_hash256(&self, _: &Pk::Hash256) -> Option { None } @@ -181,7 +181,8 @@ impl Satisfier } } -impl Satisfier for HashMap +impl Satisfier + for HashMap where Pk: MiniscriptKey + ToPublicKey, { @@ -189,13 +190,13 @@ where self.get(&key.to_pubkeyhash()).map(|x| x.1) } - fn lookup_pkh_pk(&self, pk_hash: &Pk::Hash) -> Option { + fn lookup_pkh_pk(&self, pk_hash: &Pk::RawPkHash) -> Option { self.get(pk_hash).map(|x| x.0.clone()) } fn lookup_pkh_ecdsa_sig( &self, - pk_hash: &Pk::Hash, + pk_hash: &Pk::RawPkHash, ) -> Option<(bitcoin::PublicKey, bitcoin::EcdsaSig)> { self.get(pk_hash) .map(|&(ref pk, sig)| (pk.to_public_key(), sig)) @@ -203,7 +204,7 @@ where } impl Satisfier - for HashMap<(Pk::Hash, TapLeafHash), (Pk, bitcoin::SchnorrSig)> + for HashMap<(Pk::RawPkHash, TapLeafHash), (Pk, bitcoin::SchnorrSig)> where Pk: MiniscriptKey + ToPublicKey, { @@ -213,7 +214,7 @@ where fn lookup_pkh_tap_leaf_script_sig( &self, - pk_hash: &(Pk::Hash, TapLeafHash), + pk_hash: &(Pk::RawPkHash, TapLeafHash), ) -> Option<(XOnlyPublicKey, bitcoin::SchnorrSig)> { self.get(pk_hash) .map(|&(ref pk, sig)| (pk.to_x_only_pubkey(), sig)) @@ -229,13 +230,13 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).lookup_tap_leaf_script_sig(p, h) } - fn lookup_pkh_pk(&self, pkh: &Pk::Hash) -> Option { + fn lookup_pkh_pk(&self, pkh: &Pk::RawPkHash) -> Option { (**self).lookup_pkh_pk(pkh) } fn lookup_pkh_ecdsa_sig( &self, - pkh: &Pk::Hash, + pkh: &Pk::RawPkHash, ) -> Option<(bitcoin::PublicKey, bitcoin::EcdsaSig)> { (**self).lookup_pkh_ecdsa_sig(pkh) } @@ -246,7 +247,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' fn lookup_pkh_tap_leaf_script_sig( &self, - pkh: &(Pk::Hash, TapLeafHash), + pkh: &(Pk::RawPkHash, TapLeafHash), ) -> Option<(XOnlyPublicKey, bitcoin::SchnorrSig)> { (**self).lookup_pkh_tap_leaf_script_sig(pkh) } @@ -261,7 +262,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).lookup_sha256(h) } - fn lookup_hash256(&self, h: sha256d::Hash) -> Option { + fn lookup_hash256(&self, h: &Pk::Hash256) -> Option { (**self).lookup_hash256(h) } @@ -295,20 +296,20 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).lookup_tap_key_spend_sig() } - fn lookup_pkh_pk(&self, pkh: &Pk::Hash) -> Option { + fn lookup_pkh_pk(&self, pkh: &Pk::RawPkHash) -> Option { (**self).lookup_pkh_pk(pkh) } fn lookup_pkh_ecdsa_sig( &self, - pkh: &Pk::Hash, + pkh: &Pk::RawPkHash, ) -> Option<(bitcoin::PublicKey, bitcoin::EcdsaSig)> { (**self).lookup_pkh_ecdsa_sig(pkh) } fn lookup_pkh_tap_leaf_script_sig( &self, - pkh: &(Pk::Hash, TapLeafHash), + pkh: &(Pk::RawPkHash, TapLeafHash), ) -> Option<(XOnlyPublicKey, bitcoin::SchnorrSig)> { (**self).lookup_pkh_tap_leaf_script_sig(pkh) } @@ -323,7 +324,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).lookup_sha256(h) } - fn lookup_hash256(&self, h: sha256d::Hash) -> Option { + fn lookup_hash256(&self, h: &Pk::Hash256) -> Option { (**self).lookup_hash256(h) } @@ -384,7 +385,7 @@ macro_rules! impl_tuple_satisfier { fn lookup_pkh_ecdsa_sig( &self, - key_hash: &Pk::Hash, + key_hash: &Pk::RawPkHash, ) -> Option<(bitcoin::PublicKey, bitcoin::EcdsaSig)> { let &($(ref $ty,)*) = self; $( @@ -397,7 +398,7 @@ macro_rules! impl_tuple_satisfier { fn lookup_pkh_tap_leaf_script_sig( &self, - key_hash: &(Pk::Hash, TapLeafHash), + key_hash: &(Pk::RawPkHash, TapLeafHash), ) -> Option<(XOnlyPublicKey, bitcoin::SchnorrSig)> { let &($(ref $ty,)*) = self; $( @@ -410,7 +411,7 @@ macro_rules! impl_tuple_satisfier { fn lookup_pkh_pk( &self, - key_hash: &Pk::Hash, + key_hash: &Pk::RawPkHash, ) -> Option { let &($(ref $ty,)*) = self; $( @@ -443,7 +444,7 @@ macro_rules! impl_tuple_satisfier { None } - fn lookup_hash256(&self, h: sha256d::Hash) -> Option { + fn lookup_hash256(&self, h: &Pk::Hash256) -> Option { let &($(ref $ty,)*) = self; $( if let Some(result) = $ty.lookup_hash256(h) { @@ -565,7 +566,7 @@ impl Witness { } /// Turn a public key related to a pkh into (part of) a satisfaction - fn pkh_public_key>(sat: S, pkh: &Pk::Hash) -> Self { + fn pkh_public_key>(sat: S, pkh: &Pk::RawPkHash) -> Self { match sat.lookup_pkh_pk(pkh) { Some(pk) => Witness::Stack(vec![pk.to_public_key().to_bytes()]), // public key hashes are assumed to be unavailable @@ -575,7 +576,7 @@ impl Witness { } /// Turn a key/signature pair related to a pkh into (part of) a satisfaction - fn pkh_signature>(sat: S, pkh: &Pk::Hash) -> Self { + fn pkh_signature>(sat: S, pkh: &Pk::RawPkHash) -> Self { match sat.lookup_pkh_ecdsa_sig(pkh) { Some((pk, sig)) => Witness::Stack(vec![sig.to_vec(), pk.to_public_key().to_bytes()]), None => Witness::Impossible, @@ -610,7 +611,7 @@ impl Witness { } /// Turn a hash preimage into (part of) a satisfaction - fn hash256_preimage>(sat: S, h: sha256d::Hash) -> Self { + fn hash256_preimage>(sat: S, h: &Pk::Hash256) -> Self { match sat.lookup_hash256(h) { Some(pre) => Witness::Stack(vec![pre.to_vec()]), // Note hash preimages are unavailable instead of impossible @@ -989,7 +990,7 @@ impl Satisfaction { stack: Witness::sha256_preimage(stfr, h), has_sig: false, }, - Terminal::Hash256(h) => Satisfaction { + Terminal::Hash256(ref h) => Satisfaction { stack: Witness::hash256_preimage(stfr, h), has_sig: false, }, diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index ec562acd3..d6d8e5c1a 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -849,7 +849,9 @@ where insert_wrap!(AstElemExt::terminal(Terminal::Sha256(hash.clone()))) } // Satisfaction-cost + script-cost - Concrete::Hash256(hash) => insert_wrap!(AstElemExt::terminal(Terminal::Hash256(hash))), + Concrete::Hash256(ref hash) => { + insert_wrap!(AstElemExt::terminal(Terminal::Hash256(hash.clone()))) + } Concrete::Ripemd160(hash) => insert_wrap!(AstElemExt::terminal(Terminal::Ripemd160(hash))), Concrete::Hash160(hash) => insert_wrap!(AstElemExt::terminal(Terminal::Hash160(hash))), Concrete::And(ref subs) => { diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index f2e4853e3..787891ae8 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -20,7 +20,7 @@ use core::{fmt, str}; use std::error; use bitcoin::hashes::hex::FromHex; -use bitcoin::hashes::{hash160, ripemd160, sha256d}; +use bitcoin::hashes::{hash160, ripemd160}; #[cfg(feature = "compiler")] use { crate::descriptor::TapTree, @@ -60,7 +60,7 @@ pub enum Policy { /// A SHA256 whose preimage must be provided to satisfy the descriptor Sha256(Pk::Sha256), /// A SHA256d whose preimage must be provided to satisfy the descriptor - Hash256(sha256d::Hash), + Hash256(Pk::Hash256), /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor Ripemd160(ripemd160::Hash), /// A HASH160 whose preimage must be provided to satisfy the descriptor @@ -345,7 +345,7 @@ impl ForEachKey for Policy { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { match *self { Policy::Unsatisfiable | Policy::Trivial => true, @@ -371,7 +371,7 @@ impl Policy { /// # Example /// /// ``` - /// use miniscript::{bitcoin::PublicKey, policy::concrete::Policy, Translator}; + /// use miniscript::{bitcoin::PublicKey, policy::concrete::Policy, Translator, hash256}; /// use std::str::FromStr; /// use std::collections::HashMap; /// use miniscript::bitcoin::hashes::{sha256, hash160}; @@ -402,6 +402,11 @@ impl Policy { /// fn sha256(&mut self, sha256: &String) -> Result { /// unreachable!("Policy does not contain any sha256 fragment"); /// } + /// + /// // If our policy also contained other fragments, we could provide the translation here. + /// fn hash256(&mut self, sha256: &String) -> Result { + /// unreachable!("Policy does not contain any sha256 fragment"); + /// } /// } /// /// let mut pk_map = HashMap::new(); @@ -432,7 +437,7 @@ impl Policy { Policy::Trivial => Ok(Policy::Trivial), Policy::Key(ref pk) => t.pk(pk).map(Policy::Key), Policy::Sha256(ref h) => t.sha256(h).map(Policy::Sha256), - Policy::Hash256(ref h) => Ok(Policy::Hash256(*h)), + Policy::Hash256(ref h) => t.hash256(h).map(Policy::Hash256), Policy::Ripemd160(ref h) => Ok(Policy::Ripemd160(*h)), Policy::Hash160(ref h) => Ok(Policy::Hash160(*h)), Policy::After(n) => Ok(Policy::After(n)), @@ -675,7 +680,7 @@ impl fmt::Debug for Policy { Policy::After(n) => write!(f, "after({})", n), Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), - Policy::Hash256(h) => write!(f, "hash256({})", h), + Policy::Hash256(ref h) => write!(f, "hash256({})", h), Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), Policy::Hash160(h) => write!(f, "hash160({})", h), Policy::And(ref subs) => { @@ -718,7 +723,7 @@ impl fmt::Display for Policy { Policy::After(n) => write!(f, "after({})", n), Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), - Policy::Hash256(h) => write!(f, "hash256({})", h), + Policy::Hash256(ref h) => write!(f, "hash256({})", h), Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), Policy::Hash160(h) => write!(f, "hash160({})", h), Policy::And(ref subs) => { @@ -828,7 +833,7 @@ impl_block_str!( ::from_str(x).map(Policy::Sha256) }), ("hash256", 1) => expression::terminal(&top.args[0], |x| { - sha256d::Hash::from_hex(x).map(Policy::Hash256) + ::from_str(x).map(Policy::Hash256) }), ("ripemd160", 1) => expression::terminal(&top.args[0], |x| { ripemd160::Hash::from_hex(x).map(Policy::Ripemd160) diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 3582b9cd4..07a6972a2 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -129,7 +129,7 @@ impl Liftable for Terminal { Terminal::After(t) => Semantic::After(t), Terminal::Older(t) => Semantic::Older(t), Terminal::Sha256(ref h) => Semantic::Sha256(h.clone()), - Terminal::Hash256(h) => Semantic::Hash256(h), + Terminal::Hash256(ref h) => Semantic::Hash256(h.clone()), Terminal::Ripemd160(h) => Semantic::Ripemd160(h), Terminal::Hash160(h) => Semantic::Hash160(h), Terminal::True => Semantic::Trivial, @@ -204,7 +204,7 @@ impl Liftable for Concrete { Concrete::After(t) => Semantic::After(t), Concrete::Older(t) => Semantic::Older(t), Concrete::Sha256(ref h) => Semantic::Sha256(h.clone()), - Concrete::Hash256(h) => Semantic::Hash256(h), + Concrete::Hash256(ref h) => Semantic::Hash256(h.clone()), Concrete::Ripemd160(h) => Semantic::Ripemd160(h), Concrete::Hash160(h) => Semantic::Hash160(h), Concrete::And(ref subs) => { diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 2d463573e..f7a126608 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -18,7 +18,7 @@ use core::str::FromStr; use core::{fmt, str}; use bitcoin::hashes::hex::FromHex; -use bitcoin::hashes::{hash160, ripemd160, sha256d}; +use bitcoin::hashes::{hash160, ripemd160}; use super::concrete::PolicyError; use super::ENTAILMENT_MAX_TERMINALS; @@ -38,7 +38,7 @@ pub enum Policy { /// Trivially satisfiable Trivial, /// Signature and public key matching a given hash is required - KeyHash(Pk::Hash), + KeyHash(Pk::RawPkHash), /// An absolute locktime restriction After(u32), /// A relative locktime restriction @@ -46,7 +46,7 @@ pub enum Policy { /// A SHA256 whose preimage must be provided to satisfy the descriptor Sha256(Pk::Sha256), /// A SHA256d whose preimage must be provided to satisfy the descriptor - Hash256(sha256d::Hash), + Hash256(Pk::Hash256), /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor Ripemd160(ripemd160::Hash), /// A HASH160 whose preimage must be provided to satisfy the descriptor @@ -59,7 +59,7 @@ impl ForEachKey for Policy { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool where Pk: 'a, - Pk::Hash: 'a, + Pk::RawPkHash: 'a, { match *self { Policy::Unsatisfiable | Policy::Trivial => true, @@ -82,7 +82,7 @@ impl Policy { /// # Example /// /// ``` - /// use miniscript::{bitcoin::{hashes::hash160, PublicKey}, policy::semantic::Policy, Translator}; + /// use miniscript::{bitcoin::{hashes::hash160, PublicKey}, policy::semantic::Policy, Translator, hash256}; /// use std::str::FromStr; /// use std::collections::HashMap; /// use miniscript::bitcoin::hashes::sha256; @@ -113,6 +113,11 @@ impl Policy { /// fn sha256(&mut self, sha256: &String) -> Result { /// unreachable!("Policy does not contain any sha256 fragment"); /// } + /// + /// // If our policy also contained other fragments, we could provide the translation here. + /// fn hash256(&mut self, sha256: &String) -> Result { + /// unreachable!("Policy does not contain any sha256 fragment"); + /// } /// } /// /// let mut pk_map = HashMap::new(); @@ -143,7 +148,7 @@ impl Policy { Policy::Trivial => Ok(Policy::Trivial), Policy::KeyHash(ref pkh) => t.pkh(pkh).map(Policy::KeyHash), Policy::Sha256(ref h) => t.sha256(h).map(Policy::Sha256), - Policy::Hash256(ref h) => Ok(Policy::Hash256(*h)), + Policy::Hash256(ref h) => t.hash256(h).map(Policy::Hash256), Policy::Ripemd160(ref h) => Ok(Policy::Ripemd160(*h)), Policy::Hash160(ref h) => Ok(Policy::Hash160(*h)), Policy::After(n) => Ok(Policy::After(n)), @@ -250,7 +255,7 @@ impl fmt::Debug for Policy { Policy::After(n) => write!(f, "after({})", n), Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), - Policy::Hash256(h) => write!(f, "hash256({})", h), + Policy::Hash256(ref h) => write!(f, "hash256({})", h), Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), Policy::Hash160(h) => write!(f, "hash160({})", h), Policy::Threshold(k, ref subs) => { @@ -283,7 +288,7 @@ impl fmt::Display for Policy { Policy::After(n) => write!(f, "after({})", n), Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), - Policy::Hash256(h) => write!(f, "hash256({})", h), + Policy::Hash256(ref h) => write!(f, "hash256({})", h), Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), Policy::Hash160(h) => write!(f, "hash160({})", h), Policy::Threshold(k, ref subs) => { @@ -331,7 +336,8 @@ impl_from_tree!( ("UNSATISFIABLE", 0) => Ok(Policy::Unsatisfiable), ("TRIVIAL", 0) => Ok(Policy::Trivial), ("pkh", 1) => expression::terminal(&top.args[0], |pk| { - Pk::Hash::from_str(pk).map(Policy::KeyHash) + // TODO: This will be fixed up in a later commit that changes semantic policy to Pk from Pk::Hash + Pk::RawPkHash::from_str(pk).map(Policy::KeyHash) }), ("after", 1) => expression::terminal(&top.args[0], |x| { expression::parse_num(x).map(Policy::After) @@ -343,7 +349,7 @@ impl_from_tree!( Pk::Sha256::from_str(x).map(Policy::Sha256) }), ("hash256", 1) => expression::terminal(&top.args[0], |x| { - sha256d::Hash::from_hex(x).map(Policy::Hash256) + Pk::Hash256::from_str(x).map(Policy::Hash256) }), ("ripemd160", 1) => expression::terminal(&top.args[0], |x| { ripemd160::Hash::from_hex(x).map(Policy::Ripemd160) diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index c77717f87..0798fee9c 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -24,7 +24,7 @@ use core::ops::Deref; #[cfg(feature = "std")] use std::error; -use bitcoin::hashes::{hash160, ripemd160, sha256d}; +use bitcoin::hashes::{hash160, ripemd160, sha256d, Hash}; use bitcoin::secp256k1::{self, Secp256k1, VerifyOnly}; use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt}; use bitcoin::util::sighash::SighashCache; @@ -305,7 +305,7 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier for PsbtInputSatisfie fn lookup_pkh_tap_leaf_script_sig( &self, - pkh: &(Pk::Hash, TapLeafHash), + pkh: &(Pk::RawPkHash, TapLeafHash), ) -> Option<(bitcoin::secp256k1::XOnlyPublicKey, bitcoin::SchnorrSig)> { self.psbt.inputs[self.index] .tap_script_sigs @@ -325,7 +325,7 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier for PsbtInputSatisfie fn lookup_pkh_ecdsa_sig( &self, - pkh: &Pk::Hash, + pkh: &Pk::RawPkHash, ) -> Option<(bitcoin::PublicKey, bitcoin::EcdsaSig)> { self.psbt.inputs[self.index] .partial_sigs @@ -375,10 +375,10 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier for PsbtInputSatisfie .and_then(try_vec_as_preimage32) } - fn lookup_hash256(&self, h: sha256d::Hash) -> Option { + fn lookup_hash256(&self, h: &Pk::Hash256) -> Option { self.psbt.inputs[self.index] .hash256_preimages - .get(&h) + .get(&sha256d::Hash::from_inner(Pk::to_hash256(h).into_inner())) // upstream psbt operates on hash256 .and_then(try_vec_as_preimage32) } diff --git a/src/test_utils.rs b/src/test_utils.rs index 8098482b4..3367576b1 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -6,7 +6,7 @@ use std::str::FromStr; use bitcoin::hashes::{hash160, sha256}; use bitcoin::secp256k1; -use crate::{MiniscriptKey, Translator}; +use crate::{hash256, MiniscriptKey, Translator}; /// Translate from a String MiniscriptKey type to bitcoin::PublicKey /// If the hashmap is populated, this will lookup for keys in HashMap @@ -43,6 +43,15 @@ impl Translator for StrKeyTranslator { .unwrap(); Ok(hash) } + + fn hash256(&mut self, _hash256: &String) -> Result { + // hard coded value + let hash = hash256::Hash::from_str( + "4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", + ) + .unwrap(); + Ok(hash) + } } /// Same as [`StrKeyTranslator`], but for [`bitcoin::XOnlyPublicKey`] @@ -78,6 +87,14 @@ impl Translator for StrXOnlyKeyTranslator { .unwrap(); Ok(hash) } + + fn hash256(&mut self, _hash256: &String) -> Result { + let hash = hash256::Hash::from_str( + "4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", + ) + .unwrap(); + Ok(hash) + } } // Deterministically sample keys to allow reproducible tests diff --git a/tests/setup/test_util.rs b/tests/setup/test_util.rs index 18851b5cc..dcffbde99 100644 --- a/tests/setup/test_util.rs +++ b/tests/setup/test_util.rs @@ -21,11 +21,12 @@ use std::str::FromStr; use actual_rand as rand; use bitcoin::hashes::hex::ToHex; -use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; use bitcoin::secp256k1; use miniscript::descriptor::{SinglePub, SinglePubKey}; use miniscript::{ - Descriptor, DescriptorPublicKey, Error, Miniscript, ScriptContext, TranslatePk, Translator, + hash256, Descriptor, DescriptorPublicKey, Error, Miniscript, ScriptContext, TranslatePk, + Translator, }; use rand::RngCore; #[derive(Clone, Debug)] @@ -33,7 +34,7 @@ pub struct PubData { pub pks: Vec, pub x_only_pks: Vec, pub sha256: sha256::Hash, - pub hash256: sha256d::Hash, + pub hash256: hash256::Hash, pub ripemd160: ripemd160::Hash, pub hash160: hash160::Hash, } @@ -99,7 +100,7 @@ impl TestData { let sha256_pre = [0x12 as u8; 32]; let sha256 = sha256::Hash::hash(&sha256_pre); let hash256_pre = [0x34 as u8; 32]; - let hash256 = sha256d::Hash::hash(&hash256_pre); + let hash256 = hash256::Hash::hash(&hash256_pre); let hash160_pre = [0x56 as u8; 32]; let hash160 = hash160::Hash::hash(&hash160_pre); let ripemd160_pre = [0x78 as u8; 32]; @@ -197,6 +198,11 @@ impl<'a> Translator for StrDescPubKeyTranslator let sha = sha256::Hash::from_str(sha256).unwrap(); Ok(sha) } + + fn hash256(&mut self, hash256: &String) -> Result { + let hash256 = hash256::Hash::from_str(hash256).unwrap(); + Ok(hash256) + } } // Translate Str to DescriptorPublicKey @@ -243,6 +249,11 @@ impl<'a> Translator for StrTranslatorLoose<'a> let sha = sha256::Hash::from_str(sha256).unwrap(); Ok(sha) } + + fn hash256(&mut self, hash256: &String) -> Result { + let hash256 = hash256::Hash::from_str(hash256).unwrap(); + Ok(hash256) + } } #[allow(dead_code)] diff --git a/tests/test_cpp.rs b/tests/test_cpp.rs index 90d120a0d..a6e7fd1a3 100644 --- a/tests/test_cpp.rs +++ b/tests/test_cpp.rs @@ -9,6 +9,7 @@ use std::fs::File; use std::io::{self, BufRead}; use std::path::Path; +use bitcoin::hashes::{sha256d, Hash}; use bitcoin::secp256k1::{self, Secp256k1}; use bitcoin::util::psbt; use bitcoin::util::psbt::PartiallySignedTransaction as Psbt; @@ -197,7 +198,7 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) { testdata.secretdata.sha256_pre.to_vec(), ); psbts[i].inputs[0].hash256_preimages.insert( - testdata.pubdata.hash256, + sha256d::Hash::from_inner(testdata.pubdata.hash256.into_inner()), testdata.secretdata.hash256_pre.to_vec(), ); println!("{}", ms); diff --git a/tests/test_desc.rs b/tests/test_desc.rs index 6aca87b87..425b1da6d 100644 --- a/tests/test_desc.rs +++ b/tests/test_desc.rs @@ -9,6 +9,7 @@ use std::{error, fmt}; use actual_rand as rand; use bitcoin::blockdata::witness::Witness; +use bitcoin::hashes::{sha256d, Hash}; use bitcoin::util::psbt::PartiallySignedTransaction as Psbt; use bitcoin::util::sighash::SighashCache; use bitcoin::util::taproot::{LeafVersion, TapLeafHash}; @@ -282,7 +283,7 @@ pub fn test_desc_satisfy( testdata.secretdata.sha256_pre.to_vec(), ); psbt.inputs[0].hash256_preimages.insert( - testdata.pubdata.hash256, + sha256d::Hash::from_inner(testdata.pubdata.hash256.into_inner()), testdata.secretdata.hash256_pre.to_vec(), ); psbt.inputs[0].hash160_preimages.insert(