rustywallet_taproot/
lib.rs

1//! # rustywallet-taproot
2//!
3//! Full Taproot support implementing BIP340 (Schnorr), BIP341 (Taproot), and BIP342 (Tapscript).
4//!
5//! ## Features
6//!
7//! - Schnorr signatures (BIP340)
8//! - X-only public keys
9//! - Key tweaking for Taproot
10//! - Tap tree (MAST) construction
11//! - Control block generation
12//! - P2TR address generation
13//! - BIP341 signature hash
14//!
15//! ## Example
16//!
17//! ```rust
18//! use rustywallet_taproot::{XOnlyPublicKey, TaprootOutput, Network};
19//! use secp256k1::{Secp256k1, SecretKey};
20//!
21//! // Generate a key pair
22//! let secp = Secp256k1::new();
23//! let secret = [1u8; 32];
24//! let sk = SecretKey::from_slice(&secret).unwrap();
25//! let pk = sk.public_key(&secp);
26//! let (xonly, _) = pk.x_only_public_key();
27//! let internal_key = XOnlyPublicKey::from_inner(xonly);
28//!
29//! // Create a key-path only Taproot output
30//! let output = TaprootOutput::key_path_only(internal_key).unwrap();
31//!
32//! // Get the P2TR address
33//! let address = output.address(Network::Mainnet).unwrap();
34//! assert!(address.starts_with("bc1p"));
35//! ```
36//!
37//! ## Script Path Example
38//!
39//! ```rust
40//! use rustywallet_taproot::{XOnlyPublicKey, TaprootOutput, TapTreeBuilder, Network};
41//! use secp256k1::{Secp256k1, SecretKey};
42//!
43//! let secp = Secp256k1::new();
44//! let secret = [1u8; 32];
45//! let sk = SecretKey::from_slice(&secret).unwrap();
46//! let pk = sk.public_key(&secp);
47//! let (xonly, _) = pk.x_only_public_key();
48//! let internal_key = XOnlyPublicKey::from_inner(xonly);
49//!
50//! // Build a tap tree with two scripts
51//! let tree = TapTreeBuilder::new()
52//!     .add_leaf(1, vec![0x51]) // OP_1
53//!     .add_leaf(1, vec![0x52]) // OP_2
54//!     .build()
55//!     .unwrap();
56//!
57//! // Create output with script tree
58//! let output = TaprootOutput::with_script_tree(internal_key, &tree).unwrap();
59//! let address = output.address(Network::Mainnet).unwrap();
60//! ```
61
62pub mod control_block;
63pub mod error;
64pub mod schnorr;
65pub mod sighash;
66pub mod tagged_hash;
67pub mod taproot;
68pub mod taptree;
69pub mod tweak;
70pub mod xonly;
71
72// Re-exports
73pub use control_block::ControlBlock;
74pub use error::TaprootError;
75pub use schnorr::SchnorrSignature;
76pub use sighash::{taproot_key_path_sighash, taproot_script_path_sighash, TaprootSighashType};
77pub use tagged_hash::{tagged_hash, TapLeafHash, TapNodeHash, TapTweakHash};
78pub use taproot::{create_address, is_p2tr_address, parse_address, Network, TaprootOutput};
79pub use taptree::{LeafVersion, TapLeaf, TapNode, TapTree, TapTreeBuilder};
80pub use tweak::{compute_output_key, compute_tweak, tweak_private_key, tweak_public_key};
81pub use xonly::{Parity, XOnlyPublicKey};
82
83/// Prelude module for convenient imports
84pub mod prelude {
85    pub use crate::control_block::ControlBlock;
86    pub use crate::error::TaprootError;
87    pub use crate::schnorr::SchnorrSignature;
88    pub use crate::sighash::TaprootSighashType;
89    pub use crate::tagged_hash::{TapLeafHash, TapNodeHash, TapTweakHash};
90    pub use crate::taproot::{Network, TaprootOutput};
91    pub use crate::taptree::{LeafVersion, TapLeaf, TapTree, TapTreeBuilder};
92    pub use crate::xonly::{Parity, XOnlyPublicKey};
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use secp256k1::{Secp256k1, SecretKey};
99
100    fn get_test_keypair() -> ([u8; 32], XOnlyPublicKey) {
101        let secp = Secp256k1::new();
102        let secret = [1u8; 32];
103        let sk = SecretKey::from_slice(&secret).unwrap();
104        let pk = sk.public_key(&secp);
105        let (xonly, _) = pk.x_only_public_key();
106        (secret, XOnlyPublicKey::from_inner(xonly))
107    }
108
109    #[test]
110    fn test_key_path_workflow() {
111        let (secret, internal_key) = get_test_keypair();
112
113        // Create output
114        let output = TaprootOutput::key_path_only(internal_key).unwrap();
115
116        // Get address
117        let address = output.address(Network::Mainnet).unwrap();
118        assert!(address.starts_with("bc1p"));
119
120        // Parse address back
121        let parsed = parse_address(&address).unwrap();
122        assert_eq!(output.output_key, parsed);
123    }
124
125    #[test]
126    fn test_script_path_workflow() {
127        let (_, internal_key) = get_test_keypair();
128
129        // Build tree
130        let tree = TapTreeBuilder::new()
131            .add_leaf(1, vec![0x51])
132            .add_leaf(1, vec![0x52])
133            .build()
134            .unwrap();
135
136        // Create output
137        let output = TaprootOutput::with_script_tree(internal_key, &tree).unwrap();
138        assert!(!output.is_key_path_only());
139
140        // Get control block for first leaf
141        let leaf = TapLeaf::new(vec![0x51]);
142        let cb = ControlBlock::for_leaf(&tree, &leaf, internal_key, output.parity).unwrap();
143
144        // Verify control block
145        assert!(cb.verify(&output.output_key, &leaf.script).unwrap());
146    }
147
148    #[test]
149    fn test_schnorr_signing() {
150        let (secret, pubkey) = get_test_keypair();
151        let message = [0x42u8; 32];
152
153        let sig = SchnorrSignature::sign(&message, &secret).unwrap();
154        assert!(sig.verify(&message, &pubkey));
155    }
156}