Skip to content

Commit f6dc945

Browse files
committed
Merge #439: Add support for string images in ripemd160 and hash160
4ccd4f7 Add support for string images in ripemd160 and hash160 (kanishk779) Pull request description: ACKs for top commit: apoelstra: code review ACK 4ccd4f7 sanket1729: ACK 4ccd4f7 . @apoelstra , this is exactly what I had in mind Tree-SHA512: 857804baf21687c2aa003b196dec0185b773ad9feee4c5f37c3089d8d9f0bea34a448e6754620170fe7007c46229d704ae6462cefbca9d3558e16b4ba920b822
2 parents e2e8e77 + 4ccd4f7 commit f6dc945

File tree

17 files changed

+337
-78
lines changed

17 files changed

+337
-78
lines changed

examples/taproot.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22
use std::str::FromStr;
33

4-
use bitcoin::hashes::{hash160, sha256};
4+
use bitcoin::hashes::{hash160, ripemd160, sha256};
55
use bitcoin::util::address::WitnessVersion;
66
use bitcoin::Network;
77
use miniscript::descriptor::DescriptorType;
@@ -32,6 +32,14 @@ impl Translator<String, bitcoin::XOnlyPublicKey, ()> for StrPkTranslator {
3232
fn hash256(&mut self, _sha256: &String) -> Result<hash256::Hash, ()> {
3333
unreachable!("Policy does not contain any hash256 fragment");
3434
}
35+
36+
fn ripemd160(&mut self, _ripemd160: &String) -> Result<ripemd160::Hash, ()> {
37+
unreachable!("Policy does not contain any ripemd160 fragment");
38+
}
39+
40+
fn hash160(&mut self, _hash160: &String) -> Result<hash160::Hash, ()> {
41+
unreachable!("Policy does not contain any hash160 fragment");
42+
}
3543
}
3644

3745
fn main() {
@@ -45,6 +53,7 @@ fn main() {
4553
)"
4654
.replace(&[' ', '\n', '\t'][..], "");
4755

56+
let _ms = Miniscript::<String, Tap>::from_str("and_v(v:ripemd160(H),pk(A))").unwrap();
4857
let pol: Concrete<String> = Concrete::from_str(&pol_str).unwrap();
4958
// In case we can't find an internal key for the given policy, we set the internal key to
5059
// a random pubkey as specified by BIP341 (which are *unspendable* by any party :p)

src/descriptor/key.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::str::FromStr;
44
use std::error;
55

66
use bitcoin::hashes::hex::FromHex;
7-
use bitcoin::hashes::{hash160, sha256, Hash, HashEngine};
7+
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash, HashEngine};
88
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
99
use bitcoin::util::bip32;
1010
use bitcoin::{self, XOnlyPublicKey, XpubIdentifier};
@@ -739,6 +739,8 @@ impl MiniscriptKey for DescriptorPublicKey {
739739
type RawPkHash = Self;
740740
type Sha256 = sha256::Hash;
741741
type Hash256 = hash256::Hash;
742+
type Ripemd160 = ripemd160::Hash;
743+
type Hash160 = hash160::Hash;
742744

743745
fn is_uncompressed(&self) -> bool {
744746
match self {
@@ -806,6 +808,8 @@ impl MiniscriptKey for DerivedDescriptorKey {
806808
type RawPkHash = Self;
807809
type Sha256 = sha256::Hash;
808810
type Hash256 = hash256::Hash;
811+
type Ripemd160 = ripemd160::Hash;
812+
type Hash160 = hash160::Hash;
809813

810814
fn is_uncompressed(&self) -> bool {
811815
self.key.is_uncompressed()
@@ -837,6 +841,14 @@ impl ToPublicKey for DerivedDescriptorKey {
837841
fn to_hash256(hash: &hash256::Hash) -> hash256::Hash {
838842
*hash
839843
}
844+
845+
fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash {
846+
*hash
847+
}
848+
849+
fn to_hash160(hash: &hash160::Hash) -> hash160::Hash {
850+
*hash
851+
}
840852
}
841853

842854
#[cfg(test)]

src/descriptor/mod.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use core::ops::Range;
2828
use core::str::{self, FromStr};
2929

3030
use bitcoin::blockdata::witness::Witness;
31-
use bitcoin::hashes::sha256;
31+
use bitcoin::hashes::{hash160, ripemd160, sha256};
3232
use bitcoin::util::address::WitnessVersion;
3333
use bitcoin::{self, secp256k1, Address, Network, Script, TxIn};
3434
use sync::Arc;
@@ -652,6 +652,18 @@ impl Descriptor<DescriptorPublicKey> {
652652
.map_err(|e| Error::Unexpected(e.to_string()))?;
653653
Ok(hash)
654654
}
655+
656+
fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, Error> {
657+
let hash = ripemd160::Hash::from_str(ripemd160)
658+
.map_err(|e| Error::Unexpected(e.to_string()))?;
659+
Ok(hash)
660+
}
661+
662+
fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, Error> {
663+
let hash = hash160::Hash::from_str(hash160)
664+
.map_err(|e| Error::Unexpected(e.to_string()))?;
665+
Ok(hash)
666+
}
655667
}
656668

657669
let descriptor = Descriptor::<String>::from_str(s)?;
@@ -682,6 +694,14 @@ impl Descriptor<DescriptorPublicKey> {
682694
fn hash256(&mut self, hash256: &hash256::Hash) -> Result<String, ()> {
683695
Ok(hash256.to_string())
684696
}
697+
698+
fn ripemd160(&mut self, ripemd160: &ripemd160::Hash) -> Result<String, ()> {
699+
Ok(ripemd160.to_string())
700+
}
701+
702+
fn hash160(&mut self, hash160: &hash160::Hash) -> Result<String, ()> {
703+
Ok(hash160.to_string())
704+
}
685705
}
686706

687707
fn key_to_string(pk: &DescriptorPublicKey, key_map: &KeyMap) -> Result<String, ()> {

src/interpreter/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ impl MiniscriptKey for BitcoinKey {
151151
type RawPkHash = TypedHash160;
152152
type Sha256 = sha256::Hash;
153153
type Hash256 = hash256::Hash;
154+
type Ripemd160 = ripemd160::Hash;
155+
type Hash160 = hash160::Hash;
154156

155157
fn to_pubkeyhash(&self) -> Self::RawPkHash {
156158
match self {

src/lib.rs

+133-3
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ use core::{fmt, hash, str};
128128
use std::error;
129129

130130
use bitcoin::blockdata::{opcodes, script};
131-
use bitcoin::hashes::{hash160, sha256, Hash};
131+
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
132132

133133
pub use crate::descriptor::{Descriptor, DescriptorPublicKey};
134134
pub use crate::interpreter::Interpreter;
@@ -165,6 +165,13 @@ pub trait MiniscriptKey: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Ha
165165
/// The associated [`hash256::Hash`] for this [`MiniscriptKey`],
166166
/// used in the hash256 fragment.
167167
type Hash256: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
168+
/// The associated [`ripedmd160::Hash`] for this [`MiniscriptKey`] type.
169+
/// used in the ripemd160 fragment
170+
type Ripemd160: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
171+
172+
/// The associated [`hash160::Hash`] for this [`MiniscriptKey`] type.
173+
/// used in the hash160 fragment
174+
type Hash160: Clone + Eq + Ord + fmt::Display + fmt::Debug + hash::Hash;
168175

169176
/// Converts this key to the associated pubkey hash.
170177
fn to_pubkeyhash(&self) -> Self::RawPkHash;
@@ -174,6 +181,8 @@ impl MiniscriptKey for bitcoin::secp256k1::PublicKey {
174181
type RawPkHash = hash160::Hash;
175182
type Sha256 = sha256::Hash;
176183
type Hash256 = hash256::Hash;
184+
type Ripemd160 = ripemd160::Hash;
185+
type Hash160 = hash160::Hash;
177186

178187
fn to_pubkeyhash(&self) -> Self::RawPkHash {
179188
hash160::Hash::hash(&self.serialize())
@@ -189,6 +198,8 @@ impl MiniscriptKey for bitcoin::PublicKey {
189198
type RawPkHash = hash160::Hash;
190199
type Sha256 = sha256::Hash;
191200
type Hash256 = hash256::Hash;
201+
type Ripemd160 = ripemd160::Hash;
202+
type Hash160 = hash160::Hash;
192203

193204
fn to_pubkeyhash(&self) -> Self::RawPkHash {
194205
hash160::Hash::hash(&self.to_bytes())
@@ -199,6 +210,8 @@ impl MiniscriptKey for bitcoin::secp256k1::XOnlyPublicKey {
199210
type RawPkHash = hash160::Hash;
200211
type Sha256 = sha256::Hash;
201212
type Hash256 = hash256::Hash;
213+
type Ripemd160 = ripemd160::Hash;
214+
type Hash160 = hash160::Hash;
202215

203216
fn to_pubkeyhash(&self) -> Self::RawPkHash {
204217
hash160::Hash::hash(&self.serialize())
@@ -213,6 +226,8 @@ impl MiniscriptKey for String {
213226
type RawPkHash = String;
214227
type Sha256 = String; // specify hashes as string
215228
type Hash256 = String;
229+
type Ripemd160 = String;
230+
type Hash160 = String;
216231

217232
fn to_pubkeyhash(&self) -> Self::RawPkHash {
218233
(&self).to_string()
@@ -243,6 +258,12 @@ pub trait ToPublicKey: MiniscriptKey {
243258

244259
/// Converts the generic associated [`MiniscriptKey::Hash256`] to [`hash256::Hash`]
245260
fn to_hash256(hash: &<Self as MiniscriptKey>::Hash256) -> hash256::Hash;
261+
262+
/// Converts the generic associated [`MiniscriptKey::Ripemd160`] to [`ripemd160::Hash`]
263+
fn to_ripemd160(hash: &<Self as MiniscriptKey>::Ripemd160) -> ripemd160::Hash;
264+
265+
/// Converts the generic associated [`MiniscriptKey::Hash160`] to [`hash160::Hash`]
266+
fn to_hash160(hash: &<Self as MiniscriptKey>::Hash160) -> hash160::Hash;
246267
}
247268

248269
impl ToPublicKey for bitcoin::PublicKey {
@@ -261,6 +282,14 @@ impl ToPublicKey for bitcoin::PublicKey {
261282
fn to_hash256(hash: &hash256::Hash) -> hash256::Hash {
262283
*hash
263284
}
285+
286+
fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash {
287+
*hash
288+
}
289+
290+
fn to_hash160(hash: &hash160::Hash) -> hash160::Hash {
291+
*hash
292+
}
264293
}
265294

266295
impl ToPublicKey for bitcoin::secp256k1::PublicKey {
@@ -279,6 +308,14 @@ impl ToPublicKey for bitcoin::secp256k1::PublicKey {
279308
fn to_hash256(hash: &hash256::Hash) -> hash256::Hash {
280309
*hash
281310
}
311+
312+
fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash {
313+
*hash
314+
}
315+
316+
fn to_hash160(hash: &hash160::Hash) -> hash160::Hash {
317+
*hash
318+
}
282319
}
283320

284321
impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey {
@@ -306,6 +343,14 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey {
306343
fn to_hash256(hash: &hash256::Hash) -> hash256::Hash {
307344
*hash
308345
}
346+
347+
fn to_ripemd160(hash: &ripemd160::Hash) -> ripemd160::Hash {
348+
*hash
349+
}
350+
351+
fn to_hash160(hash: &hash160::Hash) -> hash160::Hash {
352+
*hash
353+
}
309354
}
310355

311356
/// Dummy key which de/serializes to the empty string; useful sometimes for testing
@@ -327,6 +372,8 @@ impl MiniscriptKey for DummyKey {
327372
type RawPkHash = DummyKeyHash;
328373
type Sha256 = DummySha256Hash;
329374
type Hash256 = DummyHash256;
375+
type Ripemd160 = DummyRipemd160Hash;
376+
type Hash160 = DummyHash160Hash;
330377

331378
fn to_pubkeyhash(&self) -> Self::RawPkHash {
332379
DummyKeyHash
@@ -366,6 +413,14 @@ impl ToPublicKey for DummyKey {
366413
hash256::Hash::from_str("50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352")
367414
.unwrap()
368415
}
416+
417+
fn to_ripemd160(_: &DummyRipemd160Hash) -> ripemd160::Hash {
418+
ripemd160::Hash::from_str("f54a5851e9372b87810a8e60cdd2e7cfd80b6e31").unwrap()
419+
}
420+
421+
fn to_hash160(_: &DummyHash160Hash) -> hash160::Hash {
422+
hash160::Hash::from_str("f54a5851e9372b87810a8e60cdd2e7cfd80b6e31").unwrap()
423+
}
369424
}
370425

371426
/// Dummy keyhash which de/serializes to the empty string; useful sometimes for testing
@@ -437,19 +492,72 @@ impl str::FromStr for DummyHash256 {
437492
}
438493
}
439494

495+
/// Dummy keyhash which de/serializes to the empty string; useful for testing
496+
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
497+
pub struct DummyRipemd160Hash;
498+
499+
impl str::FromStr for DummyRipemd160Hash {
500+
type Err = &'static str;
501+
fn from_str(x: &str) -> Result<DummyRipemd160Hash, &'static str> {
502+
if x.is_empty() {
503+
Ok(DummyRipemd160Hash)
504+
} else {
505+
Err("non empty dummy hash")
506+
}
507+
}
508+
}
509+
440510
impl fmt::Display for DummyHash256 {
441511
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
442512
f.write_str("")
443513
}
444514
}
515+
impl fmt::Display for DummyRipemd160Hash {
516+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
517+
f.write_str("")
518+
}
519+
}
445520

446521
impl hash::Hash for DummyHash256 {
447522
fn hash<H: hash::Hasher>(&self, state: &mut H) {
448523
"DummySha256Hash".hash(state);
449524
}
450525
}
451526

452-
/// Provides the conversion information required in [`TranslatePk`]
527+
impl hash::Hash for DummyRipemd160Hash {
528+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
529+
"DummyRipemd160Hash".hash(state);
530+
}
531+
}
532+
533+
/// Dummy keyhash which de/serializes to the empty string; useful for testing
534+
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
535+
pub struct DummyHash160Hash;
536+
537+
impl str::FromStr for DummyHash160Hash {
538+
type Err = &'static str;
539+
fn from_str(x: &str) -> Result<DummyHash160Hash, &'static str> {
540+
if x.is_empty() {
541+
Ok(DummyHash160Hash)
542+
} else {
543+
Err("non empty dummy hash")
544+
}
545+
}
546+
}
547+
548+
impl fmt::Display for DummyHash160Hash {
549+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550+
f.write_str("")
551+
}
552+
}
553+
554+
impl hash::Hash for DummyHash160Hash {
555+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
556+
"DummyHash160Hash".hash(state);
557+
}
558+
}
559+
/// Describes an object that can translate various keys and hashes from one key to the type
560+
/// associated with the other key. Used by the [`TranslatePk`] trait to do the actual translations.
453561
pub trait Translator<P, Q, E>
454562
where
455563
P: MiniscriptKey,
@@ -466,6 +574,12 @@ where
466574

467575
/// Provides the translation from P::Hash256 -> Q::Hash256
468576
fn hash256(&mut self, hash256: &P::Hash256) -> Result<Q::Hash256, E>;
577+
578+
/// Translates ripemd160 hashes from P::Ripemd160 -> Q::Ripemd160
579+
fn ripemd160(&mut self, ripemd160: &P::Ripemd160) -> Result<Q::Ripemd160, E>;
580+
581+
/// Translates hash160 hashes from P::Hash160 -> Q::Hash160
582+
fn hash160(&mut self, hash160: &P::Hash160) -> Result<Q::Hash160, E>;
469583
}
470584

471585
/// Provides the conversion information required in [`TranslatePk`].
@@ -487,7 +601,12 @@ impl<P, Q, E, T> Translator<P, Q, E> for T
487601
where
488602
T: PkTranslator<P, Q, E>,
489603
P: MiniscriptKey,
490-
Q: MiniscriptKey<Sha256 = P::Sha256, Hash256 = P::Hash256>,
604+
Q: MiniscriptKey<
605+
Sha256 = P::Sha256,
606+
Hash256 = P::Hash256,
607+
Ripemd160 = P::Ripemd160,
608+
Hash160 = P::Hash160,
609+
>,
491610
{
492611
fn pk(&mut self, pk: &P) -> Result<Q, E> {
493612
<Self as PkTranslator<P, Q, E>>::pk(self, pk)
@@ -507,6 +626,17 @@ where
507626
fn hash256(&mut self, hash256: &<P as MiniscriptKey>::Hash256) -> Result<<Q>::Hash256, E> {
508627
Ok(hash256.clone())
509628
}
629+
630+
fn ripemd160(
631+
&mut self,
632+
ripemd160: &<P as MiniscriptKey>::Ripemd160,
633+
) -> Result<<Q>::Ripemd160, E> {
634+
Ok(ripemd160.clone())
635+
}
636+
637+
fn hash160(&mut self, hash160: &<P as MiniscriptKey>::Hash160) -> Result<<Q>::Hash160, E> {
638+
Ok(hash160.clone())
639+
}
510640
}
511641

512642
/// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do

0 commit comments

Comments
 (0)