1use crate::error::TaprootError;
6use crate::tagged_hash::{TapNodeHash, TapTweakHash};
7use crate::xonly::{Parity, XOnlyPublicKey};
8use secp256k1::{Secp256k1, SecretKey};
9
10pub fn tweak_public_key(
14 internal_key: &XOnlyPublicKey,
15 merkle_root: Option<&TapNodeHash>,
16) -> Result<(XOnlyPublicKey, Parity), TaprootError> {
17 let secp = Secp256k1::new();
18
19 let tweak_hash = TapTweakHash::from_key_and_merkle_root(
21 &internal_key.serialize(),
22 merkle_root,
23 );
24
25 internal_key.tweak_add(&secp, tweak_hash.as_bytes())
27}
28
29pub fn tweak_private_key(
33 secret_key: &[u8; 32],
34 internal_pubkey: &XOnlyPublicKey,
35 merkle_root: Option<&TapNodeHash>,
36) -> Result<[u8; 32], TaprootError> {
37 let secp = Secp256k1::new();
38
39 let mut sk = SecretKey::from_slice(secret_key)
41 .map_err(|e| TaprootError::Secp256k1Error(e.to_string()))?;
42
43 let pubkey = sk.public_key(&secp);
45 let (_, parity) = pubkey.x_only_public_key();
46
47 if parity == secp256k1::Parity::Odd {
48 sk = sk.negate();
49 }
50
51 let tweak_hash = TapTweakHash::from_key_and_merkle_root(
53 &internal_pubkey.serialize(),
54 merkle_root,
55 );
56
57 let scalar = secp256k1::Scalar::from_be_bytes(*tweak_hash.as_bytes())
59 .map_err(|e| TaprootError::InvalidTweak(e.to_string()))?;
60
61 let tweaked = sk.add_tweak(&scalar)
62 .map_err(|e| TaprootError::InvalidTweak(e.to_string()))?;
63
64 Ok(tweaked.secret_bytes())
65}
66
67pub fn compute_output_key(
69 internal_key: &XOnlyPublicKey,
70 merkle_root: Option<&TapNodeHash>,
71) -> Result<(XOnlyPublicKey, Parity), TaprootError> {
72 tweak_public_key(internal_key, merkle_root)
73}
74
75pub fn compute_tweak(
77 internal_key: &XOnlyPublicKey,
78 merkle_root: Option<&TapNodeHash>,
79) -> [u8; 32] {
80 TapTweakHash::from_key_and_merkle_root(
81 &internal_key.serialize(),
82 merkle_root,
83 ).to_bytes()
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 fn get_test_keypair() -> ([u8; 32], XOnlyPublicKey) {
91 let secp = Secp256k1::new();
92 let secret = [
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
97 ];
98 let sk = SecretKey::from_slice(&secret).unwrap();
99 let pk = sk.public_key(&secp);
100 let (xonly, _) = pk.x_only_public_key();
101 (secret, XOnlyPublicKey::from_inner(xonly))
102 }
103
104 #[test]
105 fn test_tweak_public_key_no_merkle() {
106 let (_, internal_key) = get_test_keypair();
107
108 let (output_key, parity) = tweak_public_key(&internal_key, None).unwrap();
109
110 assert_ne!(output_key.serialize(), internal_key.serialize());
112
113 let (output_key2, parity2) = tweak_public_key(&internal_key, None).unwrap();
115 assert_eq!(output_key, output_key2);
116 assert_eq!(parity, parity2);
117 }
118
119 #[test]
120 fn test_tweak_public_key_with_merkle() {
121 let (_, internal_key) = get_test_keypair();
122 let merkle_root = TapNodeHash::from_bytes([0x42; 32]);
123
124 let (output_key1, _) = tweak_public_key(&internal_key, None).unwrap();
125 let (output_key2, _) = tweak_public_key(&internal_key, Some(&merkle_root)).unwrap();
126
127 assert_ne!(output_key1, output_key2);
129 }
130
131 #[test]
132 fn test_tweak_private_key() {
133 let secp = Secp256k1::new();
134 let (secret, internal_key) = get_test_keypair();
135
136 let tweaked_secret = tweak_private_key(&secret, &internal_key, None).unwrap();
138
139 let tweaked_sk = SecretKey::from_slice(&tweaked_secret).unwrap();
141 let tweaked_pk = tweaked_sk.public_key(&secp);
142 let (tweaked_xonly, _) = tweaked_pk.x_only_public_key();
143
144 let (output_key, _) = tweak_public_key(&internal_key, None).unwrap();
146
147 assert_eq!(tweaked_xonly.serialize(), output_key.serialize());
149 }
150
151 #[test]
152 fn test_compute_tweak() {
153 let (_, internal_key) = get_test_keypair();
154
155 let tweak1 = compute_tweak(&internal_key, None);
156 let tweak2 = compute_tweak(&internal_key, None);
157
158 assert_eq!(tweak1, tweak2);
160
161 let merkle_root = TapNodeHash::from_bytes([0x42; 32]);
163 let tweak3 = compute_tweak(&internal_key, Some(&merkle_root));
164 assert_ne!(tweak1, tweak3);
165 }
166}