Skip to content

Commit

Permalink
Adding taptree_of_horror example.
Browse files Browse the repository at this point in the history
Adding bitcoin_hashes as dev dependency.
  • Loading branch information
miketwenty1 committed Nov 9, 2024
1 parent acbd120 commit 85963fc
Show file tree
Hide file tree
Showing 6 changed files with 2,969 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ required-features = ["std", "base64"]
name = "big"
required-features = ["std", "base64", "compiler"]

[[example]]
name = "taptree_of_horror"
path = "examples/taptree_of_horror/taptree_of_horror.rs"
required-features = ["compiler"]

[workspace]
members = ["fuzz"]
exclude = ["embedded", "bitcoind-tests"]
20 changes: 20 additions & 0 deletions examples/taptree_of_horror/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Taptree of Horror Example

### Running this example:
- `cargo run --example taptree_of_horror --features "compiler"`

### Originally based on the TABConf 6, CTB.
The challenge can be found here:
- https://tabctb.com/six
- https://tabctb.com/six/thebeginning/thetree/grim/iacceptyourterms.html

### This example demonstrates:
- Providing multiple extended private key (xpriv) descriptors for sample personas.
- Creating a policy using logical 'and/or' conditions with preimages and signatures and timelocks.
- Structuring a Taproot tree (taptree) with an internal key into logical branches and leaves based on the policy.
- Implementing nine complex tapleaves within the taptree.
- Building a spending transaction that signs and satisfies one of the tapleaves using signatures, preimages and a timelock.

### Helpful Graphic to visualize using Excalidraw
![taptree_of_horror](./taptree_of_horror.png)

59 changes: 59 additions & 0 deletions examples/taptree_of_horror/helper_fns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::str::FromStr;

use bitcoin::bip32::{DerivationPath, Xpriv};
use bitcoin::hashes::{ripemd160, sha256, Hash};
use miniscript::descriptor::DescriptorSecretKey;
use miniscript::ToPublicKey;
use secp256k1::Secp256k1;

use crate::KEYS_PER_PERSONA;

pub fn produce_grim_hash(secret: &str) -> (sha256::Hash, ripemd160::Hash) {
let mut hash_holder = sha256::Hash::hash(secret.as_bytes());
for _i in 0..5 {
hash_holder = sha256::Hash::hash(hash_holder.as_byte_array());
//println!("{} hash: {}", i, hash_holder);
}

let ripemd_160_final = ripemd160::Hash::hash(hash_holder.as_byte_array());
(hash_holder, ripemd_160_final)
}

pub fn produce_kelly_hash(secret: &str) -> (sha256::Hash, sha256::Hash) {
let prepreimage = secret.as_bytes();
let preimage_256_hash = sha256::Hash::hash(&prepreimage);
let result256_final = sha256::Hash::hash(&preimage_256_hash.to_byte_array());
(preimage_256_hash, result256_final)
}

pub fn produce_key_pairs(
desc: DescriptorSecretKey,
secp: &Secp256k1<secp256k1::All>,
derivation_without_index: &str,
_alias: &str,
) -> (Vec<bitcoin::PublicKey>, Vec<Xpriv>) {
let mut pks = Vec::new();
let mut prvs = Vec::new();

let xprv = match &desc {
DescriptorSecretKey::XPrv(xpriv) => xpriv,
_ => panic!("not an xpriv"),
};

for i in 0..KEYS_PER_PERSONA {
let pk = desc
.to_public(secp)
.unwrap()
.at_derivation_index(i.try_into().unwrap())
.unwrap()
.to_public_key();

let derivation_with_index = format!("{}/{}", derivation_without_index, i);
let derivation_path = DerivationPath::from_str(&derivation_with_index).unwrap();
let derived_xpriv: Xpriv = xprv.xkey.derive_priv(secp, &derivation_path).unwrap();

pks.push(pk);
prvs.push(derived_xpriv);
}
(pks, prvs)
}
Loading

0 comments on commit 85963fc

Please sign in to comment.