1use std::str::FromStr;
2
3use bitcoin::hashes::{ripemd160, Hash};
4use bitcoin::util::base58::check_encode_slice;
5use bitcoin::util::base58::from_check;
6use bitcoin::util::taproot::TapTweakHash;
7use bitcoin_bech32::{u5, WitnessProgram};
8use hex_utilities::{decode_hex, encode_hex};
9use secp256k1::{Scalar, Secp256k1, SecretKey};
10use sha2::{Digest, Sha256};
11
12#[derive(Debug, Clone, Copy)]
13pub enum Network {
14 Mainnet,
15 Testnet,
16}
17
18#[derive(Copy, Clone)]
19pub enum AddressType {
20 P2PKH,
22 P2SH,
24 P2WPKH,
29 P2TR,
30}
31pub fn concat_u8(first: &[u8], second: &[u8]) -> Vec<u8> {
33 [first, second].concat()
34}
35
36pub fn sha256_non_hex(non_hex_string_to_hash: &str) -> String {
37 let byte_array = non_hex_string_to_hash.as_bytes();
38 let mut hasher = Sha256::new();
39 hasher.update(&byte_array);
41 let sha256_result = hasher.finalize();
43 let sha256_result_array = sha256_result.to_vec();
44 let hex_result = encode_hex(&sha256_result_array);
45 hex_result
46}
47pub fn sha256_hex(hex_to_hash: &String) -> String {
48 let hex_byte_array = decode_hex(&hex_to_hash).unwrap();
49 let mut hasher = Sha256::new();
50 hasher.update(&hex_byte_array);
52 let sha256_result = hasher.finalize();
54 let sha256_result_array = sha256_result.to_vec();
55 let hex_result = encode_hex(&sha256_result_array);
56 hex_result
57}
58pub fn double_sha256_hex(hex_to_hash: &String) -> String {
59 let hex_byte_array = decode_hex(&hex_to_hash).unwrap();
60 let mut hasher = Sha256::new();
61 hasher.update(&hex_byte_array);
63 let sha256_result = hasher.finalize();
65 let sha256_result_array = sha256_result.to_vec();
66
67 let hex_byte_array_2 = sha256_result_array;
68 let mut hasher_2 = Sha256::new();
69 hasher_2.update(&hex_byte_array_2);
71 let sha256_result_2 = hasher_2.finalize();
73 let sha256_result_array_2 = sha256_result_2.to_vec();
74 encode_hex(&sha256_result_array_2)
75}
76pub fn get_compressed_public_key_from_private_key(private_key: &str) -> String {
77 let secp = Secp256k1::new();
79 let secret_key = SecretKey::from_str(private_key).unwrap();
80 let public_key_uncompressed = secret_key.public_key(&secp).serialize();
83 encode_hex(&public_key_uncompressed)
84}
85pub fn get_wif_from_private_key(
86 private_key: &String,
87 network: Network,
88 should_compress: bool,
89) -> String {
90 let version_application_byte_for_mainnet = "80";
93 let version_application_byte_for_testnet = "ef";
94
95 let version_application_byte = match network {
96 Network::Mainnet => version_application_byte_for_mainnet,
97 Network::Testnet => version_application_byte_for_testnet,
98 };
99
100 let private_key_hex = decode_hex(&private_key).unwrap();
101 let version_array = decode_hex(version_application_byte).unwrap();
102 let end = "01";
107 let end_array = decode_hex(end).unwrap();
108 let combined_version_and_private_key_hex = concat_u8(&version_array, &private_key_hex);
109 let combined_version_and_private_key_hex_with_end_array = if should_compress {
110 concat_u8(&combined_version_and_private_key_hex, &end_array)
111 } else {
112 combined_version_and_private_key_hex
113 };
114 let wif_private_key = check_encode_slice(&combined_version_and_private_key_hex_with_end_array);
116 wif_private_key
117}
118pub fn get_p2sh_address_from_script_hash(script_hash: &String, network: Network) -> String {
119 let p2sh_version_application_byte = "05";
121 let p2sh_testnet_version_application_byte = "c4";
122 let version_byte = match network {
123 Network::Mainnet => decode_hex(p2sh_version_application_byte).unwrap(),
124 Network::Testnet => decode_hex(p2sh_testnet_version_application_byte).unwrap(),
125 };
126 let script_hash_bytes = decode_hex(&script_hash).unwrap();
127 let script_hash_with_version_byte = concat_u8(&version_byte, &script_hash_bytes);
128 let address = check_encode_slice(&script_hash_with_version_byte);
129 address
130}
131pub fn get_p2sh_address_from_pubkey_hash(public_key_hash: &String, network: Network) -> String {
132 let prefix_bytes = decode_hex("0014").unwrap();
134 let public_key_hash_bytes = decode_hex(public_key_hash).unwrap();
135 let redeem_script = concat_u8(&prefix_bytes, &public_key_hash_bytes);
136 let redeem_script_sha256 = sha256::digest_bytes(&redeem_script);
137 let redeem_script_sha256_as_hex_array = decode_hex(&redeem_script_sha256).unwrap();
138 let redeem_script_ripemd160 = ripemd160::Hash::hash(&redeem_script_sha256_as_hex_array);
139 let hash160 = redeem_script_ripemd160.to_string();
140 return get_p2sh_address_from_script_hash(&hash160, network);
141 }
154pub fn get_p2pkh_address_from_pubkey_hash(public_key_hash: &String, network: Network) -> String {
155 let p2pkh_version_application_byte = "00";
158 let p2pkh_testnet_version_application_byte = "6f";
159
160 let version_application_byte = match network {
161 Network::Mainnet => p2pkh_version_application_byte,
162 Network::Testnet => p2pkh_testnet_version_application_byte,
163 };
164 let hex_array = decode_hex(&public_key_hash).unwrap();
171 let version_array = decode_hex(version_application_byte).unwrap();
172 let a = concat_u8(&version_array, &hex_array);
173 let address = check_encode_slice(&a);
178 address
179}
180pub fn get_address_from_pub_key_hash(
181 public_key_hash: &String,
182 network: Network,
183 address_type: AddressType,
184) -> String {
185 match address_type {
186 AddressType::P2PKH => get_p2pkh_address_from_pubkey_hash(public_key_hash, network),
187 AddressType::P2SH => get_p2sh_address_from_pubkey_hash(public_key_hash, network),
188 AddressType::P2WPKH => get_p2wpkh_address_from_pubkey_hash(public_key_hash, network),
189 AddressType::P2TR => {
190 todo!("Not sure if you can get pub key hash from a taproot address. Instead, use get address from public key, not hash")
191 }
192 }
193}
194
195pub fn get_bech32_address_from_witness_program(
196 witness_version: u8,
197 program_hex: &String,
198 network: Network,
199) -> String {
200 let network_for_bech32_library = match network {
201 Network::Mainnet => bitcoin_bech32::constants::Network::Bitcoin,
202 Network::Testnet => bitcoin_bech32::constants::Network::Testnet,
203 };
204 let byte_array = decode_hex(&program_hex).unwrap();
205 let witness_program = WitnessProgram::new(
206 u5::try_from_u8(witness_version).unwrap(),
207 byte_array,
208 network_for_bech32_library,
209 )
210 .unwrap();
211 let address = witness_program.to_address();
212 address
213}
214
215pub fn get_p2tr_address_from_pubkey(public_key_hex: &String, network: Network) -> String {
216 let witness_version = 1;
222 let secp = Secp256k1::new();
223 let tweaked_x_only_public_key = get_tweaked_x_only_public_key_from_public_key(public_key_hex);
224 let address = get_bech32_address_from_witness_program(
234 witness_version,
235 &tweaked_x_only_public_key.to_string(),
236 network,
237 );
238 address
239}
240
241pub fn get_p2wpkh_address_from_pubkey_hash(pub_key_hash: &String, network: Network) -> String {
242 let witness_version = 0;
246 let address = get_bech32_address_from_witness_program(
249 witness_version,
250 &pub_key_hash.to_string(),
251 network,
252 );
253 address
254}
255pub fn get_tweaked_x_only_public_key_from_p2tr_address(address: &String) -> String {
256 let witness = WitnessProgram::from_address(address).unwrap();
257 encode_hex(&witness.program())
258}
259pub fn get_pubkey_hash_from_p2wpkh_address(address: &String) -> String {
260 let witness = WitnessProgram::from_address(address).unwrap();
261 encode_hex(&witness.program())
262}
263
264pub fn get_address_from_pub_key(
265 pub_key: &String,
266 network: Network,
267 address_type: AddressType,
268) -> String {
269 match address_type {
270 AddressType::P2PKH | AddressType::P2SH | AddressType::P2WPKH => {
271 let pub_key_hash = get_public_key_hash_from_public_key(&pub_key);
272
273 let address = get_address_from_pub_key_hash(&pub_key_hash, network, address_type);
274 address
275 }
276 AddressType::P2TR => get_p2tr_address_from_pubkey(pub_key, network),
277 }
278}
279
280pub fn get_public_key_from_wif(wif: &String) -> String {
281 let private_key = convert_wif_to_private_key(&wif);
283 let public_key = get_public_key_from_private_key(&private_key, is_wif_compressed(&wif));
284 public_key
285}
286pub fn is_wif_compressed(wif: &String) -> bool {
287 let first_char_of_wif = wif.chars().nth(0).unwrap();
289 let is_compressed_wif = first_char_of_wif == 'K'
290 || first_char_of_wif == 'L'
291 || first_char_of_wif == 'M'
292 || first_char_of_wif == 'c';
293 is_compressed_wif
294}
295pub fn get_public_key_from_private_key(private_key: &String, is_compressed: bool) -> String {
296 let secp = Secp256k1::new();
298 let secret_key = SecretKey::from_str(private_key).unwrap();
299 let public_key = if is_compressed {
302 secret_key.public_key(&secp).serialize().to_vec()
303 } else {
304 secret_key
305 .public_key(&secp)
306 .serialize_uncompressed()
307 .to_vec()
308 };
309 encode_hex(&public_key)
310}
311
312pub fn hash160_for_non_hex(non_hex_string_to_hash: &String) -> String {
313 let string_as_array = non_hex_string_to_hash.as_bytes();
314 let sha256 = sha256::digest_bytes(&string_as_array);
315 let sha256_as_hex_array = sha256.as_bytes();
316 let ripemd160 = ripemd160::Hash::hash(&sha256_as_hex_array);
317 ripemd160.to_string()
318}
319pub fn hash160_for_hex(hex_to_hash: &String) -> String {
320 let hex_array = decode_hex(hex_to_hash).unwrap();
321 let sha256 = sha256_hex(hex_to_hash);
322 let sha256_as_hex_array = decode_hex(&sha256).unwrap();
323 let public_key_ripemd160 = ripemd160::Hash::hash(&sha256_as_hex_array);
324 public_key_ripemd160.to_string()
325}
326
327pub fn get_tweaked_x_only_public_key_from_public_key(public_key_hex: &String) -> String {
328 let secp = Secp256k1::new();
329 let public_key =
330 secp256k1::PublicKey::from_str(&public_key_hex).expect("statistically impossible to hit");
331 let (untweaked_x_only_public_key, _parity) = public_key.x_only_public_key();
332 let merkle_root = None;
333 let tweak =
334 TapTweakHash::from_key_and_tweak(untweaked_x_only_public_key, merkle_root).to_scalar();
335 let (tweaked_x_only_public_key, _parity) = untweaked_x_only_public_key
336 .add_tweak(&secp, &tweak)
337 .expect("Tap tweak failed");
338 tweaked_x_only_public_key.to_string()
339}
340
341pub fn get_public_key_hash_from_public_key(public_key: &String) -> String {
342 hash160_for_hex(public_key)
343}
344
345pub fn get_script_hash_from_p2sh_address(address: &str) -> String {
346 if bitcoin_address::is_p2sh(&address.to_string()) {
347 let address_base58check_decoded = from_check(&address).unwrap();
348 let address_base58check_decoded_without_first_byte =
349 address_base58check_decoded.get(1..).unwrap();
350 let script_hash = encode_hex(&address_base58check_decoded_without_first_byte);
351 script_hash
352 } else {
353 panic!("Address is not p2sh: {}", address);
354 }
355}
356
357pub fn get_public_key_hash_from_non_bech_32_address(address: &String) -> String {
358 if bitcoin_address::is_legacy(&address.to_string()) {
359 let address_base58check_decoded = from_check(&address).unwrap();
360 let address_base58check_decoded_without_first_byte =
361 address_base58check_decoded.get(1..).unwrap();
362 let pub_key_hash = encode_hex(&address_base58check_decoded_without_first_byte);
363 pub_key_hash
364 } else {
365 panic!("Address must be legacy: {}", address);
366 }
367}
368pub fn get_public_key_hash_from_address(address: &String) -> String {
369 if bitcoin_address::is_legacy(address) {
372 get_public_key_hash_from_non_bech_32_address(address)
373 } else if bitcoin_address::is_segwit_native(address) {
374 get_pubkey_hash_from_p2wpkh_address(address)
375 } else if bitcoin_address::is_nested_segwit(address) {
376 panic!(
377 "Couldn't get public key hash from address ({}). Nested segwit addresses not supported. Instead, you should use get_script_hash_from_p2sh_address() function",
378 address
379 );
380 } else {
381 panic!("Couldn't get public key hash from address: {}", address);
382 }
383}
384pub fn convert_wif_to_private_key(wif: &String) -> String {
385 let is_compressed_wif = is_wif_compressed(wif);
390 let wif_base58check_decoded_result = from_check(&wif);
391 let wif_base58check_decoded = from_check(&wif).unwrap();
392 let wif_base58check_decoded_without_first_byte = wif_base58check_decoded.get(1..).unwrap();
401 let wif_base58check_decoded_without_first_byte_and_adjusted_for_compression =
402 if is_compressed_wif {
403 wif_base58check_decoded_without_first_byte
404 .get(..=(wif_base58check_decoded_without_first_byte.len() - 2))
405 .unwrap()
406 } else {
407 wif_base58check_decoded_without_first_byte
408 };
409 let wif_base58check_decoded_without_first_byte_and_adjusted_for_compression_hex =
410 encode_hex(wif_base58check_decoded_without_first_byte_and_adjusted_for_compression);
411 wif_base58check_decoded_without_first_byte_and_adjusted_for_compression_hex
412}
413
414#[cfg(test)]
415mod tests {
416 use super::*;
417
418 #[test]
419 fn it_works() {
420 }
423}