use bs58; use hex; use sha256; // Mainnet enum Prefixes { P2PKH, P2SH, WIFPrivateKey, ExtendedPrivateKey, ExtendedPublicKey, } impl Prefixes { fn value(&self) -> Vec { match *self { Prefixes::P2PKH => vec![0], // 00 Prefixes::P2SH => vec![5], // 05 Prefixes::WIFPrivateKey => vec![128], // 80 Prefixes::ExtendedPrivateKey => vec![4, 136, 173, 228], // 04 88 AD E4 Prefixes::ExtendedPublicKey => vec![4, 136, 178, 30], // 04 88 B2 1E } } } fn my_checksum(data: &Vec) -> String { // There was a bug here because the first sha256 returns a String - didn't even think of // Kind of fucking dumb it returns that as the "default" data type IUAM sha256::digest(hex::decode(sha256::digest(data)).unwrap())[0..8].to_string() } fn pubkeyhash_to_address(prefix: &str, p2pkh: &str, checksum: Option<&str>) -> String { let mut address_unencoded: Vec = vec![]; address_unencoded.extend(hex::decode(prefix).unwrap()); address_unencoded.extend(hex::decode(p2pkh).unwrap()); let determined_checksum = my_checksum(&address_unencoded); if let Some(chk) = checksum { assert_eq!(chk, determined_checksum); }; address_unencoded.extend(hex::decode(determined_checksum).unwrap()); bs58::encode(address_unencoded).into_string() } fn main() { println!("Hello, world!"); } #[cfg(test)] mod tests { use super::*; #[test] fn satoshi2() { let prefix = hex::encode(Prefixes::P2PKH.value()); let pubkeyhash = "11b366edfc0a8b66feebae5c2e25a7b6a5d1cf31".to_string(); let satoshi2_address = pubkeyhash_to_address(&prefix, &pubkeyhash, None); assert_eq!( satoshi2_address, "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S".to_string() ); } }