Skip to content

Commit f7d3681

Browse files
committed
Adding taptree_of_horror example.
Adding bitcoin_hashes as dev dependency.
1 parent a998160 commit f7d3681

File tree

6 files changed

+2969
-0
lines changed

6 files changed

+2969
-0
lines changed

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ required-features = ["std", "base64"]
6666
name = "big"
6767
required-features = ["std", "base64", "compiler"]
6868

69+
[[example]]
70+
name = "taptree_of_horror"
71+
path = "examples/taptree_of_horror/taptree_of_horror.rs"
72+
required-features = ["compiler"]
73+
6974
[workspace]
7075
members = ["fuzz"]
7176
exclude = ["embedded", "bitcoind-tests"]

examples/taptree_of_horror/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Taptree of Horror Example
2+
3+
### Running this example:
4+
- `cargo run --example taptree_of_horror --features "compiler"`
5+
6+
### Originally based on the TABConf 6, CTB.
7+
The challenge can be found here:
8+
- https://tabctb.com/six
9+
- https://tabctb.com/six/thebeginning/thetree/grim/iacceptyourterms.html
10+
11+
### This example demonstrates:
12+
- Providing multiple extended private key (xpriv) descriptors for sample personas.
13+
- Creating a policy using logical 'and/or' conditions with preimages and signatures and timelocks.
14+
- Structuring a Taproot tree (taptree) with an internal key into logical branches and leaves based on the policy.
15+
- Implementing nine complex tapleaves within the taptree.
16+
- Building a spending transaction that signs and satisfies one of the tapleaves using signatures, preimages and a timelock.
17+
18+
### Helpful Graphic to visualize using Excalidraw
19+
![taptree_of_horror](./taptree_of_horror.png)
20+
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use std::str::FromStr;
2+
3+
use bitcoin::bip32::{DerivationPath, Xpriv};
4+
use bitcoin::hashes::{ripemd160, sha256, Hash};
5+
use miniscript::descriptor::DescriptorSecretKey;
6+
use miniscript::ToPublicKey;
7+
use secp256k1::Secp256k1;
8+
9+
use crate::KEYS_PER_PERSONA;
10+
11+
pub fn produce_grim_hash(secret: &str) -> (sha256::Hash, ripemd160::Hash) {
12+
let mut hash_holder = sha256::Hash::hash(secret.as_bytes());
13+
for _i in 0..5 {
14+
hash_holder = sha256::Hash::hash(hash_holder.as_byte_array());
15+
//println!("{} hash: {}", i, hash_holder);
16+
}
17+
18+
let ripemd_160_final = ripemd160::Hash::hash(hash_holder.as_byte_array());
19+
(hash_holder, ripemd_160_final)
20+
}
21+
22+
pub fn produce_kelly_hash(secret: &str) -> (sha256::Hash, sha256::Hash) {
23+
let prepreimage = secret.as_bytes();
24+
let preimage_256_hash = sha256::Hash::hash(prepreimage);
25+
let result256_final = sha256::Hash::hash(&preimage_256_hash.to_byte_array());
26+
(preimage_256_hash, result256_final)
27+
}
28+
29+
pub fn produce_key_pairs(
30+
desc: DescriptorSecretKey,
31+
secp: &Secp256k1<secp256k1::All>,
32+
derivation_without_index: &str,
33+
_alias: &str,
34+
) -> (Vec<bitcoin::PublicKey>, Vec<Xpriv>) {
35+
let mut pks = Vec::new();
36+
let mut prvs = Vec::new();
37+
38+
let xprv = match &desc {
39+
DescriptorSecretKey::XPrv(xpriv) => xpriv,
40+
_ => panic!("not an xpriv"),
41+
};
42+
43+
for i in 0..KEYS_PER_PERSONA {
44+
let pk = desc
45+
.to_public(secp)
46+
.unwrap()
47+
.at_derivation_index(i.try_into().unwrap())
48+
.unwrap()
49+
.to_public_key();
50+
51+
let derivation_with_index = format!("{}/{}", derivation_without_index, i);
52+
let derivation_path = DerivationPath::from_str(&derivation_with_index).unwrap();
53+
let derived_xpriv: Xpriv = xprv.xkey.derive_priv(secp, &derivation_path).unwrap();
54+
55+
pks.push(pk);
56+
prvs.push(derived_xpriv);
57+
}
58+
(pks, prvs)
59+
}

0 commit comments

Comments
 (0)