Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding taptree_of_horror example. #766

Merged
merged 2 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading