From 4ccd4f7abb266acef8c1d5bec8629fd7335db3db Mon Sep 17 00:00:00 2001 From: kanishk779 Date: Mon, 27 Jun 2022 00:16:04 +0530 Subject: [PATCH] Add support for string images in ripemd160 and hash160 --- examples/taproot.rs | 11 ++- src/descriptor/key.rs | 14 +++- src/descriptor/mod.rs | 22 +++++- src/interpreter/mod.rs | 2 + src/lib.rs | 136 +++++++++++++++++++++++++++++++++++++- src/macros.rs | 24 +++++++ src/miniscript/astelem.rs | 26 ++++---- src/miniscript/context.rs | 4 +- src/miniscript/decode.rs | 4 +- src/miniscript/satisfy.rs | 25 ++++--- src/policy/compiler.rs | 8 ++- src/policy/concrete.rs | 34 ++++++---- src/policy/mod.rs | 12 ++-- src/policy/semantic.rs | 33 +++++---- src/psbt/mod.rs | 10 +-- src/test_utils.rs | 30 ++++++++- tests/setup/test_util.rs | 20 ++++++ 17 files changed, 337 insertions(+), 78 deletions(-) diff --git a/examples/taproot.rs b/examples/taproot.rs index 9d829d066..fcabc5e54 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::str::FromStr; -use bitcoin::hashes::{hash160, sha256}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::util::address::WitnessVersion; use bitcoin::Network; use miniscript::descriptor::DescriptorType; @@ -32,6 +32,14 @@ impl Translator for StrPkTranslator { fn hash256(&mut self, _sha256: &String) -> Result { unreachable!("Policy does not contain any hash256 fragment"); } + + fn ripemd160(&mut self, _ripemd160: &String) -> Result { + unreachable!("Policy does not contain any ripemd160 fragment"); + } + + fn hash160(&mut self, _hash160: &String) -> Result { + unreachable!("Policy does not contain any hash160 fragment"); + } } fn main() { @@ -45,6 +53,7 @@ fn main() { )" .replace(&[' ', '\n', '\t'][..], ""); + let _ms = Miniscript::::from_str("and_v(v:ripemd160(H),pk(A))").unwrap(); let pol: Concrete = Concrete::from_str(&pol_str).unwrap(); // In case we can't find an internal key for the given policy, we set the internal key to // a random pubkey as specified by BIP341 (which are *unspendable* by any party :p) diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index f62d39922..c00114321 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -4,7 +4,7 @@ use core::str::FromStr; use std::error; use bitcoin::hashes::hex::FromHex; -use bitcoin::hashes::{hash160, sha256, Hash, HashEngine}; +use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine}; use bitcoin::secp256k1::{Secp256k1, Signing, Verification}; use bitcoin::util::bip32; use bitcoin::{self, XOnlyPublicKey, XpubIdentifier}; @@ -739,6 +739,8 @@ impl MiniscriptKey for DescriptorPublicKey { type RawPkHash = Self; type Sha256 = sha256::Hash; type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; fn is_uncompressed(&self) -> bool { match self { @@ -806,6 +808,8 @@ impl MiniscriptKey for DerivedDescriptorKey { type RawPkHash = Self; type Sha256 = sha256::Hash; type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; fn is_uncompressed(&self) -> bool { self.key.is_uncompressed() @@ -837,6 +841,14 @@ impl ToPublicKey for DerivedDescriptorKey { fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } + + fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { + *hash + } + + fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { + *hash + } } #[cfg(test)] diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index fbeb6cf4a..845fd1d2f 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -28,7 +28,7 @@ use core::ops::Range; use core::str::{self, FromStr}; use bitcoin::blockdata::witness::Witness; -use bitcoin::hashes::sha256; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::util::address::WitnessVersion; use bitcoin::{self, secp256k1, Address, Network, Script, TxIn}; use sync::Arc; @@ -652,6 +652,18 @@ impl Descriptor { .map_err(|e| Error::Unexpected(e.to_string()))?; Ok(hash) } + + fn ripemd160(&mut self, ripemd160: &String) -> Result { + let hash = ripemd160::Hash::from_str(ripemd160) + .map_err(|e| Error::Unexpected(e.to_string()))?; + Ok(hash) + } + + fn hash160(&mut self, hash160: &String) -> Result { + let hash = hash160::Hash::from_str(hash160) + .map_err(|e| Error::Unexpected(e.to_string()))?; + Ok(hash) + } } let descriptor = Descriptor::::from_str(s)?; @@ -682,6 +694,14 @@ impl Descriptor { fn hash256(&mut self, hash256: &hash256::Hash) -> Result { Ok(hash256.to_string()) } + + fn ripemd160(&mut self, ripemd160: &ripemd160::Hash) -> Result { + Ok(ripemd160.to_string()) + } + + fn hash160(&mut self, hash160: &hash160::Hash) -> Result { + Ok(hash160.to_string()) + } } fn key_to_string(pk: &DescriptorPublicKey, key_map: &KeyMap) -> Result { diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 4a7bc14f3..2c2c4b917 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -151,6 +151,8 @@ impl MiniscriptKey for BitcoinKey { type RawPkHash = TypedHash160; type Sha256 = sha256::Hash; type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; fn to_pubkeyhash(&self) -> Self::RawPkHash { match self { diff --git a/src/lib.rs b/src/lib.rs index 115429bc7..dd0888624 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,7 +128,7 @@ use core::{fmt, hash, str}; use std::error; use bitcoin::blockdata::{opcodes, script}; -use bitcoin::hashes::{hash160, sha256, Hash}; +use bitcoin::hashes::{hash160, ripemd160, sha256, Hash}; pub use crate::descriptor::{Descriptor, DescriptorPublicKey}; pub use crate::interpreter::Interpreter; @@ -165,6 +165,13 @@ pub trait MiniscriptKey: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Ha /// The associated [`hash256::Hash`] for this [`MiniscriptKey`], /// used in the hash256 fragment. type Hash256: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; + /// The associated [`ripedmd160::Hash`] for this [`MiniscriptKey`] type. + /// used in the ripemd160 fragment + type Ripemd160: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; + + /// The associated [`hash160::Hash`] for this [`MiniscriptKey`] type. + /// used in the hash160 fragment + type Hash160: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash; /// Converts this key to the associated pubkey hash. fn to_pubkeyhash(&self) -> Self::RawPkHash; @@ -174,6 +181,8 @@ impl MiniscriptKey for bitcoin::secp256k1::PublicKey { type RawPkHash = hash160::Hash; type Sha256 = sha256::Hash; type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; fn to_pubkeyhash(&self) -> Self::RawPkHash { hash160::Hash::hash(&self.serialize()) @@ -189,6 +198,8 @@ impl MiniscriptKey for bitcoin::PublicKey { type RawPkHash = hash160::Hash; type Sha256 = sha256::Hash; type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; fn to_pubkeyhash(&self) -> Self::RawPkHash { hash160::Hash::hash(&self.to_bytes()) @@ -199,6 +210,8 @@ impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey { type RawPkHash = hash160::Hash; type Sha256 = sha256::Hash; type Hash256 = hash256::Hash; + type Ripemd160 = ripemd160::Hash; + type Hash160 = hash160::Hash; fn to_pubkeyhash(&self) -> Self::RawPkHash { hash160::Hash::hash(&self.serialize()) @@ -213,6 +226,8 @@ impl MiniscriptKey for String { type RawPkHash = String; type Sha256 = String; // specify hashes as string type Hash256 = String; + type Ripemd160 = String; + type Hash160 = String; fn to_pubkeyhash(&self) -> Self::RawPkHash { (&self).to_string() @@ -243,6 +258,12 @@ pub trait ToPublicKey: MiniscriptKey { /// Converts the generic associated [`MiniscriptKey::Hash256`] to [`hash256::Hash`] fn to_hash256(hash: &::Hash256) -> hash256::Hash; + + /// Converts the generic associated [`MiniscriptKey::Ripemd160`] to [`ripemd160::Hash`] + fn to_ripemd160(hash: &::Ripemd160) -> ripemd160::Hash; + + /// Converts the generic associated [`MiniscriptKey::Hash160`] to [`hash160::Hash`] + fn to_hash160(hash: &::Hash160) -> hash160::Hash; } impl ToPublicKey for bitcoin::PublicKey { @@ -261,6 +282,14 @@ impl ToPublicKey for bitcoin::PublicKey { fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } + + fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { + *hash + } + + fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { + *hash + } } impl ToPublicKey for bitcoin::secp256k1::PublicKey { @@ -279,6 +308,14 @@ impl ToPublicKey for bitcoin::secp256k1::PublicKey { fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } + + fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { + *hash + } + + fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { + *hash + } } impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { @@ -306,6 +343,14 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { fn to_hash256(hash: &hash256::Hash) -> hash256::Hash { *hash } + + fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash { + *hash + } + + fn to_hash160(hash: &hash160::Hash) -> hash160::Hash { + *hash + } } /// Dummy key which de/serializes to the empty string; useful sometimes for testing @@ -327,6 +372,8 @@ impl MiniscriptKey for DummyKey { type RawPkHash = DummyKeyHash; type Sha256 = DummySha256Hash; type Hash256 = DummyHash256; + type Ripemd160 = DummyRipemd160Hash; + type Hash160 = DummyHash160Hash; fn to_pubkeyhash(&self) -> Self::RawPkHash { DummyKeyHash @@ -366,6 +413,14 @@ impl ToPublicKey for DummyKey { hash256::Hash::from_str("50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352") .unwrap() } + + fn to_ripemd160(_: &DummyRipemd160Hash) -> ripemd160::Hash { + ripemd160::Hash::from_str("f54a5851e9372b87810a8e60cdd2e7cfd80b6e31").unwrap() + } + + fn to_hash160(_: &DummyHash160Hash) -> hash160::Hash { + hash160::Hash::from_str("f54a5851e9372b87810a8e60cdd2e7cfd80b6e31").unwrap() + } } /// Dummy keyhash which de/serializes to the empty string; useful sometimes for testing @@ -437,11 +492,31 @@ impl str::FromStr for DummyHash256 { } } +/// Dummy keyhash which de/serializes to the empty string; useful for testing +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub struct DummyRipemd160Hash; + +impl str::FromStr for DummyRipemd160Hash { + type Err = &'static str; + fn from_str(x: &str) -> Result { + if x.is_empty() { + Ok(DummyRipemd160Hash) + } else { + Err("non empty dummy hash") + } + } +} + impl fmt::Display for DummyHash256 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } } +impl fmt::Display for DummyRipemd160Hash { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("") + } +} impl hash::Hash for DummyHash256 { fn hash(&self, state: &mut H) { @@ -449,7 +524,40 @@ impl hash::Hash for DummyHash256 { } } -/// Provides the conversion information required in [`TranslatePk`] +impl hash::Hash for DummyRipemd160Hash { + fn hash(&self, state: &mut H) { + "DummyRipemd160Hash".hash(state); + } +} + +/// Dummy keyhash which de/serializes to the empty string; useful for testing +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub struct DummyHash160Hash; + +impl str::FromStr for DummyHash160Hash { + type Err = &'static str; + fn from_str(x: &str) -> Result { + if x.is_empty() { + Ok(DummyHash160Hash) + } else { + Err("non empty dummy hash") + } + } +} + +impl fmt::Display for DummyHash160Hash { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("") + } +} + +impl hash::Hash for DummyHash160Hash { + fn hash(&self, state: &mut H) { + "DummyHash160Hash".hash(state); + } +} +/// 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. pub trait Translator where P: MiniscriptKey, @@ -466,6 +574,12 @@ where /// Provides the translation from P::Hash256 -> Q::Hash256 fn hash256(&mut self, hash256: &P::Hash256) -> Result; + + /// Translates ripemd160 hashes from P::Ripemd160 -> Q::Ripemd160 + fn ripemd160(&mut self, ripemd160: &P::Ripemd160) -> Result; + + /// Translates hash160 hashes from P::Hash160 -> Q::Hash160 + fn hash160(&mut self, hash160: &P::Hash160) -> Result; } /// Provides the conversion information required in [`TranslatePk`]. @@ -487,7 +601,12 @@ impl Translator for T where T: PkTranslator, P: MiniscriptKey, - Q: MiniscriptKey, + Q: MiniscriptKey< + Sha256 = P::Sha256, + Hash256 = P::Hash256, + Ripemd160 = P::Ripemd160, + Hash160 = P::Hash160, + >, { fn pk(&mut self, pk: &P) -> Result { >::pk(self, pk) @@ -507,6 +626,17 @@ where fn hash256(&mut self, hash256: &

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

::Ripemd160, + ) -> Result<::Ripemd160, E> { + Ok(ripemd160.clone()) + } + + fn hash160(&mut self, hash160: &

::Hash160) -> Result<::Hash160, E> { + Ok(hash160.clone()) + } } /// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do diff --git a/src/macros.rs b/src/macros.rs index 954bf96d1..cdad906ec 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -30,10 +30,14 @@ macro_rules! impl_from_tree { Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, Pk::Hash256: core::str::FromStr, + Pk::Ripemd160: core::str::FromStr, + Pk::Hash160: 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, + <::Ripemd160 as core::str::FromStr>::Err: $crate::prelude::ToString, + <::Hash160 as core::str::FromStr>::Err: $crate::prelude::ToString, $($gen : $gen_con,)* { @@ -60,10 +64,14 @@ macro_rules! impl_from_str { Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, Pk::Hash256: core::str::FromStr, + Pk::Ripemd160: core::str::FromStr, + Pk::Hash160: 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, + <::Ripemd160 as core::str::FromStr>::Err: $crate::prelude::ToString, + <::Hash160 as core::str::FromStr>::Err: $crate::prelude::ToString, $($gen : $gen_con,)* { type Err = $err_ty; @@ -90,10 +98,14 @@ macro_rules! impl_block_str { Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, Pk::Hash256: core::str::FromStr, + Pk::Ripemd160: core::str::FromStr, + Pk::Hash160: 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, + <::Ripemd160 as core::str::FromStr>::Err: $crate::prelude::ToString, + <::Hash160 as core::str::FromStr>::Err: $crate::prelude::ToString, $($gen : $gen_con,)* { $(#[$meta])* @@ -115,6 +127,8 @@ macro_rules! serde_string_impl_pk { Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, Pk::Hash256: core::str::FromStr, + Pk::Ripemd160: core::str::FromStr, + Pk::Hash160: core::str::FromStr, ::Err: core::fmt::Display, <::RawPkHash as core::str::FromStr>::Err: core::fmt::Display, @@ -122,6 +136,10 @@ macro_rules! serde_string_impl_pk { core::fmt::Display, <::Hash256 as core::str::FromStr>::Err: core::fmt::Display, + <::Ripemd160 as core::str::FromStr>::Err: + core::fmt::Display, + <::Hash160 as core::str::FromStr>::Err: + core::fmt::Display, $($gen : $gen_con,)* { fn deserialize(deserializer: D) -> Result<$name, D::Error> @@ -140,6 +158,8 @@ macro_rules! serde_string_impl_pk { Pk::RawPkHash: core::str::FromStr, Pk::Sha256: core::str::FromStr, Pk::Hash256: core::str::FromStr, + Pk::Ripemd160: core::str::FromStr, + Pk::Hash160: core::str::FromStr, ::Err: core::fmt::Display, <::RawPkHash as core::str::FromStr>::Err: core::fmt::Display, @@ -147,6 +167,10 @@ macro_rules! serde_string_impl_pk { core::fmt::Display, <::Hash256 as core::str::FromStr>::Err: core::fmt::Display, + <::Ripemd160 as core::str::FromStr>::Err: + core::fmt::Display, + <::Hash160 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 566bde7a6..b21756430 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -23,8 +23,6 @@ use core::fmt; use core::str::FromStr; use bitcoin::blockdata::{opcodes, script}; -use bitcoin::hashes::hex::FromHex; -use bitcoin::hashes::{hash160, ripemd160}; use sync::Arc; use crate::miniscript::context::SigType; @@ -134,8 +132,8 @@ impl Terminal { Terminal::Older(n) => Terminal::Older(n), Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(&x)?), Terminal::Hash256(ref x) => Terminal::Hash256(t.hash256(&x)?), - Terminal::Ripemd160(x) => Terminal::Ripemd160(x), - Terminal::Hash160(x) => Terminal::Hash160(x), + Terminal::Ripemd160(ref x) => Terminal::Ripemd160(t.ripemd160(&x)?), + Terminal::Hash160(ref x) => Terminal::Hash160(t.hash160(&x)?), Terminal::True => Terminal::True, Terminal::False => Terminal::False, Terminal::Alt(ref sub) => Terminal::Alt(Arc::new(sub.real_translate_pk(t)?)), @@ -260,8 +258,8 @@ impl fmt::Debug for Terminal { Terminal::Older(t) => write!(f, "older({})", t), Terminal::Sha256(ref h) => write!(f, "sha256({})", h), Terminal::Hash256(ref h) => write!(f, "hash256({})", h), - Terminal::Ripemd160(h) => write!(f, "ripemd160({})", h), - Terminal::Hash160(h) => write!(f, "hash160({})", h), + Terminal::Ripemd160(ref h) => write!(f, "ripemd160({})", h), + Terminal::Hash160(ref h) => write!(f, "hash160({})", h), Terminal::True => f.write_str("1"), Terminal::False => f.write_str("0"), Terminal::AndV(ref l, ref r) => write!(f, "and_v({:?},{:?})", l, r), @@ -314,8 +312,8 @@ impl fmt::Display for Terminal { Terminal::Older(t) => write!(f, "older({})", t), Terminal::Sha256(ref h) => write!(f, "sha256({})", h), Terminal::Hash256(ref h) => write!(f, "hash256({})", h), - Terminal::Ripemd160(h) => write!(f, "ripemd160({})", h), - Terminal::Hash160(h) => write!(f, "hash160({})", h), + Terminal::Ripemd160(ref h) => write!(f, "ripemd160({})", h), + Terminal::Hash160(ref h) => write!(f, "hash160({})", h), Terminal::True => f.write_str("1"), Terminal::False => f.write_str("0"), Terminal::AndV(ref l, ref r) if r.node != Terminal::True => { @@ -473,10 +471,10 @@ impl_from_tree!( Pk::Hash256::from_str(x).map(Terminal::Hash256) }), ("ripemd160", 1) => expression::terminal(&top.args[0], |x| { - ripemd160::Hash::from_hex(x).map(Terminal::Ripemd160) + Pk::Ripemd160::from_str(x).map(Terminal::Ripemd160) }), ("hash160", 1) => expression::terminal(&top.args[0], |x| { - hash160::Hash::from_hex(x).map(Terminal::Hash160) + Pk::Hash160::from_str(x).map(Terminal::Hash160) }), ("1", 0) => Ok(Terminal::True), ("0", 0) => Ok(Terminal::False), @@ -639,19 +637,19 @@ impl Terminal { .push_opcode(opcodes::all::OP_HASH256) .push_slice(&Pk::to_hash256(&h)) .push_opcode(opcodes::all::OP_EQUAL), - Terminal::Ripemd160(h) => builder + Terminal::Ripemd160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) .push_int(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_RIPEMD160) - .push_slice(&h[..]) + .push_slice(&Pk::to_ripemd160(&h)) .push_opcode(opcodes::all::OP_EQUAL), - Terminal::Hash160(h) => builder + Terminal::Hash160(ref h) => builder .push_opcode(opcodes::all::OP_SIZE) .push_int(32) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&h[..]) + .push_slice(&Pk::to_hash160(&h)) .push_opcode(opcodes::all::OP_EQUAL), Terminal::True => builder.push_opcode(opcodes::OP_TRUE), Terminal::False => builder.push_opcode(opcodes::OP_FALSE), diff --git a/src/miniscript/context.rs b/src/miniscript/context.rs index b63bc5ba9..d838ee4ba 100644 --- a/src/miniscript/context.rs +++ b/src/miniscript/context.rs @@ -18,7 +18,7 @@ use std::error; use bitcoin; use bitcoin::blockdata::constants::MAX_BLOCK_WEIGHT; -use bitcoin::hashes::{hash160, sha256}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use super::decode::ParseableKey; use crate::miniscript::limits::{ @@ -194,6 +194,8 @@ 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 e7dc9404b..d7f72c1d8 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -148,9 +148,9 @@ pub enum Terminal { /// `SIZE 32 EQUALVERIFY HASH256 EQUAL` Hash256(Pk::Hash256), /// `SIZE 32 EQUALVERIFY RIPEMD160 EQUAL` - Ripemd160(ripemd160::Hash), + Ripemd160(Pk::Ripemd160), /// `SIZE 32 EQUALVERIFY HASH160 EQUAL` - Hash160(hash160::Hash), + Hash160(Pk::Hash160), // Wrappers /// `TOALTSTACK [E] FROMALTSTACK` Alt(Arc>), diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index 0ed6f285b..37723117c 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -21,7 +21,6 @@ use core::{cmp, i64, mem}; use bitcoin; -use bitcoin::hashes::{hash160, ripemd160}; use bitcoin::secp256k1::XOnlyPublicKey; use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapLeafHash}; use sync::Arc; @@ -100,12 +99,12 @@ pub trait Satisfier { } /// Given a RIPEMD160 hash, look up its preimage - fn lookup_ripemd160(&self, _: ripemd160::Hash) -> Option { + fn lookup_ripemd160(&self, _: &Pk::Ripemd160) -> Option { None } /// Given a HASH160 hash, look up its preimage - fn lookup_hash160(&self, _: hash160::Hash) -> Option { + fn lookup_hash160(&self, _: &Pk::Hash160) -> Option { None } @@ -266,11 +265,11 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).lookup_hash256(h) } - fn lookup_ripemd160(&self, h: ripemd160::Hash) -> Option { + fn lookup_ripemd160(&self, h: &Pk::Ripemd160) -> Option { (**self).lookup_ripemd160(h) } - fn lookup_hash160(&self, h: hash160::Hash) -> Option { + fn lookup_hash160(&self, h: &Pk::Hash160) -> Option { (**self).lookup_hash160(h) } @@ -328,11 +327,11 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).lookup_hash256(h) } - fn lookup_ripemd160(&self, h: ripemd160::Hash) -> Option { + fn lookup_ripemd160(&self, h: &Pk::Ripemd160) -> Option { (**self).lookup_ripemd160(h) } - fn lookup_hash160(&self, h: hash160::Hash) -> Option { + fn lookup_hash160(&self, h: &Pk::Hash160) -> Option { (**self).lookup_hash160(h) } @@ -454,7 +453,7 @@ macro_rules! impl_tuple_satisfier { None } - fn lookup_ripemd160(&self, h: ripemd160::Hash) -> Option { + fn lookup_ripemd160(&self, h: &Pk::Ripemd160) -> Option { let &($(ref $ty,)*) = self; $( if let Some(result) = $ty.lookup_ripemd160(h) { @@ -464,7 +463,7 @@ macro_rules! impl_tuple_satisfier { None } - fn lookup_hash160(&self, h: hash160::Hash) -> Option { + fn lookup_hash160(&self, h: &Pk::Hash160) -> Option { let &($(ref $ty,)*) = self; $( if let Some(result) = $ty.lookup_hash160(h) { @@ -584,7 +583,7 @@ impl Witness { } /// Turn a hash preimage into (part of) a satisfaction - fn ripemd160_preimage>(sat: S, h: ripemd160::Hash) -> Self { + fn ripemd160_preimage>(sat: S, h: &Pk::Ripemd160) -> Self { match sat.lookup_ripemd160(h) { Some(pre) => Witness::Stack(vec![pre.to_vec()]), // Note hash preimages are unavailable instead of impossible @@ -593,7 +592,7 @@ impl Witness { } /// Turn a hash preimage into (part of) a satisfaction - fn hash160_preimage>(sat: S, h: hash160::Hash) -> Self { + fn hash160_preimage>(sat: S, h: &Pk::Hash160) -> Self { match sat.lookup_hash160(h) { Some(pre) => Witness::Stack(vec![pre.to_vec()]), // Note hash preimages are unavailable instead of impossible @@ -978,11 +977,11 @@ impl Satisfaction { has_sig: false, }, - Terminal::Ripemd160(h) => Satisfaction { + Terminal::Ripemd160(ref h) => Satisfaction { stack: Witness::ripemd160_preimage(stfr, h), has_sig: false, }, - Terminal::Hash160(h) => Satisfaction { + Terminal::Hash160(ref h) => Satisfaction { stack: Witness::hash160_preimage(stfr, h), has_sig: false, }, diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index d6d8e5c1a..c5cb7cdea 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -852,8 +852,12 @@ where 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::Ripemd160(ref hash) => { + insert_wrap!(AstElemExt::terminal(Terminal::Ripemd160(hash.clone()))) + } + Concrete::Hash160(ref hash) => { + insert_wrap!(AstElemExt::terminal(Terminal::Hash160(hash.clone()))) + } Concrete::And(ref subs) => { assert_eq!(subs.len(), 2, "and takes 2 args"); let mut left = best_compilations(policy_cache, &subs[0], sat_prob, dissat_prob)?; diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index 787891ae8..6e28f3d11 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -19,8 +19,6 @@ use core::{fmt, str}; #[cfg(feature = "std")] use std::error; -use bitcoin::hashes::hex::FromHex; -use bitcoin::hashes::{hash160, ripemd160}; #[cfg(feature = "compiler")] use { crate::descriptor::TapTree, @@ -62,9 +60,9 @@ pub enum Policy { /// A SHA256d whose preimage must be provided to satisfy the descriptor Hash256(Pk::Hash256), /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor - Ripemd160(ripemd160::Hash), + Ripemd160(Pk::Ripemd160), /// A HASH160 whose preimage must be provided to satisfy the descriptor - Hash160(hash160::Hash), + Hash160(Pk::Hash160), /// A list of sub-policies, all of which must be satisfied And(Vec>), /// A list of sub-policies, one of which must be satisfied, along with @@ -374,7 +372,7 @@ impl Policy { /// use miniscript::{bitcoin::PublicKey, policy::concrete::Policy, Translator, hash256}; /// use std::str::FromStr; /// use std::collections::HashMap; - /// use miniscript::bitcoin::hashes::{sha256, hash160}; + /// use miniscript::bitcoin::hashes::{sha256, hash160, ripemd160}; /// let alice_key = "0270cf3c71f65a3d93d285d9149fddeeb638f87a2d4d8cf16c525f71c417439777"; /// let bob_key = "02f43b15c50a436f5335dbea8a64dd3b4e63e34c3b50c42598acb5f4f336b5d2fb"; /// let placeholder_policy = Policy::::from_str("and(pk(alice_key),pk(bob_key))").unwrap(); @@ -407,6 +405,14 @@ impl Policy { /// fn hash256(&mut self, sha256: &String) -> Result { /// unreachable!("Policy does not contain any sha256 fragment"); /// } + /// + /// fn ripemd160(&mut self, ripemd160: &String) -> Result { + /// unreachable!("Policy does not contain any ripemd160 fragment"); + /// } + /// + /// fn hash160(&mut self, hash160: &String) -> Result { + /// unreachable!("Policy does not contain any hash160 fragment"); + /// } /// } /// /// let mut pk_map = HashMap::new(); @@ -438,10 +444,10 @@ impl Policy { Policy::Key(ref pk) => t.pk(pk).map(Policy::Key), Policy::Sha256(ref h) => t.sha256(h).map(Policy::Sha256), 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)), + Policy::Ripemd160(ref h) => t.ripemd160(h).map(Policy::Ripemd160), + Policy::Hash160(ref h) => t.hash160(h).map(Policy::Hash160), Policy::Older(n) => Ok(Policy::Older(n)), + Policy::After(n) => Ok(Policy::After(n)), Policy::Threshold(k, ref subs) => { let new_subs: Result>, _> = subs.iter().map(|sub| sub._translate_pk(t)).collect(); @@ -681,8 +687,8 @@ impl fmt::Debug for Policy { Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), Policy::Hash256(ref h) => write!(f, "hash256({})", h), - Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), - Policy::Hash160(h) => write!(f, "hash160({})", h), + Policy::Ripemd160(ref h) => write!(f, "ripemd160({})", h), + Policy::Hash160(ref h) => write!(f, "hash160({})", h), Policy::And(ref subs) => { f.write_str("and(")?; if !subs.is_empty() { @@ -724,8 +730,8 @@ impl fmt::Display for Policy { Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), Policy::Hash256(ref h) => write!(f, "hash256({})", h), - Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), - Policy::Hash160(h) => write!(f, "hash160({})", h), + Policy::Ripemd160(ref h) => write!(f, "ripemd160({})", h), + Policy::Hash160(ref h) => write!(f, "hash160({})", h), Policy::And(ref subs) => { f.write_str("and(")?; if !subs.is_empty() { @@ -836,10 +842,10 @@ impl_block_str!( ::from_str(x).map(Policy::Hash256) }), ("ripemd160", 1) => expression::terminal(&top.args[0], |x| { - ripemd160::Hash::from_hex(x).map(Policy::Ripemd160) + ::from_str(x).map(Policy::Ripemd160) }), ("hash160", 1) => expression::terminal(&top.args[0], |x| { - hash160::Hash::from_hex(x).map(Policy::Hash160) + ::from_str(x).map(Policy::Hash160) }), ("and", _) => { if top.args.len() != 2 { diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 07a6972a2..9e91dc7fe 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -130,10 +130,10 @@ impl Liftable for Terminal { Terminal::Older(t) => Semantic::Older(t), Terminal::Sha256(ref h) => Semantic::Sha256(h.clone()), Terminal::Hash256(ref h) => Semantic::Hash256(h.clone()), - Terminal::Ripemd160(h) => Semantic::Ripemd160(h), - Terminal::Hash160(h) => Semantic::Hash160(h), - Terminal::True => Semantic::Trivial, + Terminal::Ripemd160(ref h) => Semantic::Ripemd160(h.clone()), + Terminal::Hash160(ref h) => Semantic::Hash160(h.clone()), Terminal::False => Semantic::Unsatisfiable, + Terminal::True => Semantic::Trivial, Terminal::Alt(ref sub) | Terminal::Swap(ref sub) | Terminal::Check(ref sub) @@ -205,8 +205,8 @@ impl Liftable for Concrete { Concrete::Older(t) => Semantic::Older(t), Concrete::Sha256(ref h) => Semantic::Sha256(h.clone()), Concrete::Hash256(ref h) => Semantic::Hash256(h.clone()), - Concrete::Ripemd160(h) => Semantic::Ripemd160(h), - Concrete::Hash160(h) => Semantic::Hash160(h), + Concrete::Ripemd160(ref h) => Semantic::Ripemd160(h.clone()), + Concrete::Hash160(ref h) => Semantic::Hash160(h.clone()), Concrete::And(ref subs) => { let semantic_subs: Result<_, Error> = subs.iter().map(Liftable::lift).collect(); Semantic::Threshold(2, semantic_subs?) @@ -287,7 +287,7 @@ mod tests { assert!(ConcretePol::from_str("thresh()").is_err()); assert!(SemanticPol::from_str("thresh(0)").is_err()); assert!(SemanticPol::from_str("thresh()").is_err()); - concrete_policy_rtt("ripemd160(aaaaaaaaaaaaaaaaaaaaaa0Daaaaaaaaaabaaaaa)"); + concrete_policy_rtt("ripemd160()"); } #[test] diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index f7a126608..1bf430cb9 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -17,9 +17,6 @@ use core::str::FromStr; use core::{fmt, str}; -use bitcoin::hashes::hex::FromHex; -use bitcoin::hashes::{hash160, ripemd160}; - use super::concrete::PolicyError; use super::ENTAILMENT_MAX_TERMINALS; use crate::prelude::*; @@ -48,9 +45,9 @@ pub enum Policy { /// A SHA256d whose preimage must be provided to satisfy the descriptor Hash256(Pk::Hash256), /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor - Ripemd160(ripemd160::Hash), + Ripemd160(Pk::Ripemd160), /// A HASH160 whose preimage must be provided to satisfy the descriptor - Hash160(hash160::Hash), + Hash160(Pk::Hash160), /// A set of descriptors, satisfactions must be provided for `k` of them Threshold(usize, Vec>), } @@ -82,7 +79,7 @@ impl Policy { /// # Example /// /// ``` - /// use miniscript::{bitcoin::{hashes::hash160, PublicKey}, policy::semantic::Policy, Translator, hash256}; + /// use miniscript::{bitcoin::{hashes::{hash160, ripemd160}, PublicKey}, policy::semantic::Policy, Translator, hash256}; /// use std::str::FromStr; /// use std::collections::HashMap; /// use miniscript::bitcoin::hashes::sha256; @@ -118,6 +115,14 @@ impl Policy { /// fn hash256(&mut self, sha256: &String) -> Result { /// unreachable!("Policy does not contain any sha256 fragment"); /// } + /// + /// fn ripemd160(&mut self, ripemd160: &String) -> Result { + /// unreachable!("Policy does not contain any ripemd160 fragment"); + /// } + /// + /// fn hash160(&mut self, hash160: &String) -> Result { + /// unreachable!("Policy does not contain any hash160 fragment"); + /// } /// } /// /// let mut pk_map = HashMap::new(); @@ -149,8 +154,8 @@ impl Policy { Policy::KeyHash(ref pkh) => t.pkh(pkh).map(Policy::KeyHash), Policy::Sha256(ref h) => t.sha256(h).map(Policy::Sha256), 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::Ripemd160(ref h) => t.ripemd160(h).map(Policy::Ripemd160), + Policy::Hash160(ref h) => t.hash160(h).map(Policy::Hash160), Policy::After(n) => Ok(Policy::After(n)), Policy::Older(n) => Ok(Policy::Older(n)), Policy::Threshold(k, ref subs) => { @@ -256,8 +261,8 @@ impl fmt::Debug for Policy { Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), Policy::Hash256(ref h) => write!(f, "hash256({})", h), - Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), - Policy::Hash160(h) => write!(f, "hash160({})", h), + Policy::Ripemd160(ref h) => write!(f, "ripemd160({})", h), + Policy::Hash160(ref h) => write!(f, "hash160({})", h), Policy::Threshold(k, ref subs) => { if k == subs.len() { write!(f, "and(")?; @@ -289,8 +294,8 @@ impl fmt::Display for Policy { Policy::Older(n) => write!(f, "older({})", n), Policy::Sha256(ref h) => write!(f, "sha256({})", h), Policy::Hash256(ref h) => write!(f, "hash256({})", h), - Policy::Ripemd160(h) => write!(f, "ripemd160({})", h), - Policy::Hash160(h) => write!(f, "hash160({})", h), + Policy::Ripemd160(ref h) => write!(f, "ripemd160({})", h), + Policy::Hash160(ref h) => write!(f, "hash160({})", h), Policy::Threshold(k, ref subs) => { if k == subs.len() { write!(f, "and(")?; @@ -352,10 +357,10 @@ impl_from_tree!( Pk::Hash256::from_str(x).map(Policy::Hash256) }), ("ripemd160", 1) => expression::terminal(&top.args[0], |x| { - ripemd160::Hash::from_hex(x).map(Policy::Ripemd160) + Pk::Ripemd160::from_str(x).map(Policy::Ripemd160) }), ("hash160", 1) => expression::terminal(&top.args[0], |x| { - hash160::Hash::from_hex(x).map(Policy::Hash160) + Pk::Hash160::from_str(x).map(Policy::Hash160) }), ("and", nsubs) => { if nsubs < 2 { diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 0798fee9c..50a7144f7 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, Hash}; +use bitcoin::hashes::{hash160, sha256d, Hash}; use bitcoin::secp256k1::{self, Secp256k1, VerifyOnly}; use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt}; use bitcoin::util::sighash::SighashCache; @@ -361,10 +361,10 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier for PsbtInputSatisfie } } - fn lookup_hash160(&self, h: hash160::Hash) -> Option { + fn lookup_hash160(&self, h: &Pk::Hash160) -> Option { self.psbt.inputs[self.index] .hash160_preimages - .get(&h) + .get(&Pk::to_hash160(h)) .and_then(try_vec_as_preimage32) } @@ -382,10 +382,10 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier for PsbtInputSatisfie .and_then(try_vec_as_preimage32) } - fn lookup_ripemd160(&self, h: ripemd160::Hash) -> Option { + fn lookup_ripemd160(&self, h: &Pk::Ripemd160) -> Option { self.psbt.inputs[self.index] .ripemd160_preimages - .get(&h) + .get(&Pk::to_ripemd160(h)) .and_then(try_vec_as_preimage32) } } diff --git a/src/test_utils.rs b/src/test_utils.rs index 3367576b1..64a3202f4 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::str::FromStr; -use bitcoin::hashes::{hash160, sha256}; +use bitcoin::hashes::{hash160, ripemd160, sha256}; use bitcoin::secp256k1; use crate::{hash256, MiniscriptKey, Translator}; @@ -16,6 +16,8 @@ pub struct StrKeyTranslator { pub pk_map: HashMap, pub pkh_map: HashMap, pub sha256_map: HashMap, + pub ripemd160_map: HashMap, + pub hash160_map: HashMap, } impl Translator for StrKeyTranslator { @@ -52,6 +54,16 @@ impl Translator for StrKeyTranslator { .unwrap(); Ok(hash) } + + fn ripemd160(&mut self, _ripemd160: &String) -> Result { + let hash = ripemd160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); + Ok(hash) + } + + fn hash160(&mut self, _hash160: &String) -> Result { + let hash = hash160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); + Ok(hash) + } } /// Same as [`StrKeyTranslator`], but for [`bitcoin::XOnlyPublicKey`] @@ -60,6 +72,8 @@ pub struct StrXOnlyKeyTranslator { pub pk_map: HashMap, pub pkh_map: HashMap, pub sha256_map: HashMap, + pub ripemd160_map: HashMap, + pub hash160_map: HashMap, } impl Translator for StrXOnlyKeyTranslator { @@ -95,6 +109,16 @@ impl Translator for StrXOnlyKeyTranslator { .unwrap(); Ok(hash) } + + fn ripemd160(&mut self, _ripemd160: &String) -> Result { + let hash = ripemd160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); + Ok(hash) + } + + fn hash160(&mut self, _hash160: &String) -> Result { + let hash = hash160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); + Ok(hash) + } } // Deterministically sample keys to allow reproducible tests @@ -134,6 +158,8 @@ impl StrKeyTranslator { pk_map, pkh_map, sha256_map: HashMap::new(), + ripemd160_map: HashMap::new(), + hash160_map: HashMap::new(), } } } @@ -162,6 +188,8 @@ impl StrXOnlyKeyTranslator { pk_map, pkh_map, sha256_map: HashMap::new(), + ripemd160_map: HashMap::new(), + hash160_map: HashMap::new(), } } } diff --git a/tests/setup/test_util.rs b/tests/setup/test_util.rs index dcffbde99..18bf2ddb5 100644 --- a/tests/setup/test_util.rs +++ b/tests/setup/test_util.rs @@ -203,6 +203,16 @@ impl<'a> Translator for StrDescPubKeyTranslator let hash256 = hash256::Hash::from_str(hash256).unwrap(); Ok(hash256) } + + fn ripemd160(&mut self, ripemd160: &String) -> Result { + let ripemd160 = ripemd160::Hash::from_str(ripemd160).unwrap(); + Ok(ripemd160) + } + + fn hash160(&mut self, hash160: &String) -> Result { + let hash160 = hash160::Hash::from_str(hash160).unwrap(); + Ok(hash160) + } } // Translate Str to DescriptorPublicKey @@ -254,6 +264,16 @@ impl<'a> Translator for StrTranslatorLoose<'a> let hash256 = hash256::Hash::from_str(hash256).unwrap(); Ok(hash256) } + + fn ripemd160(&mut self, ripemd160: &String) -> Result { + let ripemd160 = ripemd160::Hash::from_str(ripemd160).unwrap(); + Ok(ripemd160) + } + + fn hash160(&mut self, hash160: &String) -> Result { + let hash160 = hash160::Hash::from_str(hash160).unwrap(); + Ok(hash160) + } } #[allow(dead_code)]