rustywallet_taproot/
tagged_hash.rs1use sha2::{Digest, Sha256};
6
7pub const TAG_TAP_LEAF: &str = "TapLeaf";
9pub const TAG_TAP_BRANCH: &str = "TapBranch";
11pub const TAG_TAP_TWEAK: &str = "TapTweak";
13pub const TAG_TAP_SIGHASH: &str = "TapSighash";
15pub const TAG_BIP340_CHALLENGE: &str = "BIP0340/challenge";
17pub const TAG_BIP340_AUX: &str = "BIP0340/aux";
19pub const TAG_BIP340_NONCE: &str = "BIP0340/nonce";
21
22pub fn tagged_hash(tag: &str, data: &[u8]) -> [u8; 32] {
24 let tag_hash = Sha256::digest(tag.as_bytes());
25
26 let mut hasher = Sha256::new();
27 hasher.update(tag_hash);
28 hasher.update(tag_hash);
29 hasher.update(data);
30
31 let result = hasher.finalize();
32 let mut output = [0u8; 32];
33 output.copy_from_slice(&result);
34 output
35}
36
37#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
39pub struct TapLeafHash(pub [u8; 32]);
40
41impl TapLeafHash {
42 pub fn from_script(leaf_version: u8, script: &[u8]) -> Self {
44 let mut data = Vec::with_capacity(1 + script.len());
45 data.push(leaf_version);
46 data.extend_from_slice(script);
47 Self(tagged_hash(TAG_TAP_LEAF, &data))
48 }
49
50 pub fn as_bytes(&self) -> &[u8; 32] {
52 &self.0
53 }
54
55 pub fn to_bytes(self) -> [u8; 32] {
57 self.0
58 }
59}
60
61impl AsRef<[u8]> for TapLeafHash {
62 fn as_ref(&self) -> &[u8] {
63 &self.0
64 }
65}
66
67#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
69pub struct TapNodeHash(pub [u8; 32]);
70
71impl TapNodeHash {
72 pub fn from_bytes(bytes: [u8; 32]) -> Self {
74 Self(bytes)
75 }
76
77 pub fn from_children(left: &TapNodeHash, right: &TapNodeHash) -> Self {
80 let mut data = [0u8; 64];
81
82 if left.0 <= right.0 {
84 data[..32].copy_from_slice(&left.0);
85 data[32..].copy_from_slice(&right.0);
86 } else {
87 data[..32].copy_from_slice(&right.0);
88 data[32..].copy_from_slice(&left.0);
89 }
90
91 Self(tagged_hash(TAG_TAP_BRANCH, &data))
92 }
93
94 pub fn from_leaf(leaf: TapLeafHash) -> Self {
96 Self(leaf.0)
97 }
98
99 pub fn as_bytes(&self) -> &[u8; 32] {
101 &self.0
102 }
103
104 pub fn to_bytes(self) -> [u8; 32] {
106 self.0
107 }
108}
109
110impl AsRef<[u8]> for TapNodeHash {
111 fn as_ref(&self) -> &[u8] {
112 &self.0
113 }
114}
115
116impl From<TapLeafHash> for TapNodeHash {
117 fn from(leaf: TapLeafHash) -> Self {
118 Self(leaf.0)
119 }
120}
121
122#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
124pub struct TapTweakHash(pub [u8; 32]);
125
126impl TapTweakHash {
127 pub fn from_key_and_merkle_root(internal_key: &[u8; 32], merkle_root: Option<&TapNodeHash>) -> Self {
129 let mut data = Vec::with_capacity(64);
130 data.extend_from_slice(internal_key);
131 if let Some(root) = merkle_root {
132 data.extend_from_slice(&root.0);
133 }
134 Self(tagged_hash(TAG_TAP_TWEAK, &data))
135 }
136
137 pub fn as_bytes(&self) -> &[u8; 32] {
139 &self.0
140 }
141
142 pub fn to_bytes(self) -> [u8; 32] {
144 self.0
145 }
146}
147
148impl AsRef<[u8]> for TapTweakHash {
149 fn as_ref(&self) -> &[u8] {
150 &self.0
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn test_tagged_hash() {
160 let hash1 = tagged_hash("test", b"data");
162 let hash2 = tagged_hash("test", b"data");
163 assert_eq!(hash1, hash2);
164
165 let hash3 = tagged_hash("other", b"data");
167 assert_ne!(hash1, hash3);
168
169 let hash4 = tagged_hash("test", b"other");
171 assert_ne!(hash1, hash4);
172 }
173
174 #[test]
175 fn test_tap_leaf_hash() {
176 let script = vec![0x51]; let leaf_hash = TapLeafHash::from_script(0xc0, &script);
178
179 let leaf_hash2 = TapLeafHash::from_script(0xc0, &script);
181 assert_eq!(leaf_hash, leaf_hash2);
182 }
183
184 #[test]
185 fn test_tap_branch_hash_ordering() {
186 let left = TapNodeHash([0x01; 32]);
187 let right = TapNodeHash([0x02; 32]);
188
189 let hash1 = TapNodeHash::from_children(&left, &right);
191 let hash2 = TapNodeHash::from_children(&right, &left);
192 assert_eq!(hash1, hash2);
193 }
194
195 #[test]
196 fn test_tap_tweak_hash() {
197 let internal_key = [0x02; 32];
198
199 let tweak1 = TapTweakHash::from_key_and_merkle_root(&internal_key, None);
201
202 let merkle_root = TapNodeHash([0x03; 32]);
204 let tweak2 = TapTweakHash::from_key_and_merkle_root(&internal_key, Some(&merkle_root));
205
206 assert_ne!(tweak1.0, tweak2.0);
207 }
208}