bcloop 0.1.0

A tool for processing Bitcoin-like blockchain data
Documentation
use std::io::{Cursor, Read, Result, Write};

use sha2::Digest;

// MARK: Hashing Functions

pub fn sha256(data: &[u8]) -> [u8; 32] {
  let mut hasher = sha2::Sha256::new();
  hasher.update(data);
  hasher.finalize().into()
}

pub fn sha256d(data: &[u8]) -> [u8; 32] {
  sha256(&sha256(data))
}

pub fn rmd160(data: &[u8]) -> [u8; 20] {
  let mut hasher = ripemd::Ripemd160::new();
  hasher.update(data);
  hasher.finalize().into()
}

pub fn hash160(data: &[u8]) -> [u8; 20] {
  rmd160(&sha256(data))
}

// MARK: Address

// https://bitcoin.stackexchange.com/a/91091
// https://learnmeabitcoin.com/technical/script/
pub enum AddrType {
  P2PKH([u8; 20]),  // DUP HASH160 0x14 <hash160> EQUALVERIFY CHECKSIG
  P2SH([u8; 20]),   // HASH160 0x14 <hash160> EQUAL
  P2PK([u8; 20]),   // 0x41 <pubkey> CHECKSIG
  P2WPKH([u8; 20]), // 0x00 0x14 <hash160>
  P2WSH([u8; 20]),  // 0x00 0x20 <hash256>
  Unknown,
}

impl AddrType {
  pub fn hex(&self) -> String {
    match self {
      AddrType::P2PKH(h) => hex::encode(h),
      AddrType::P2SH(h) => hex::encode(h),
      AddrType::P2PK(h) => hex::encode(h),
      AddrType::P2WPKH(h) => hex::encode(h),
      AddrType::P2WSH(h) => hex::encode(h),
      AddrType::Unknown => "".to_string(),
    }
  }

  pub fn load(s: &[u8]) -> AddrType {
    // https://bitcoin.stackexchange.com/a/91091
    // https://learnmeabitcoin.com/technical/script/
    match s {
      s if s.len() == 25 && s[0] == 0x76 && s[1] == 0xA9 && s[2] == 0x14 && s[24] == 0xAC => {
        AddrType::P2PKH(s[3..23].try_into().unwrap())
      }

      s if s.len() == 23 && s[0] == 0xA9 && s[1] == 0x14 && s[22] == 0x87 => {
        AddrType::P2SH(s[2..22].try_into().unwrap())
      }

      s if s.len() == 67 && s[0] == 0x41 && s[66] == 0xAC => {
        AddrType::P2PK(hash160(s[1..66].as_ref()))
      }

      s if s.len() == 22 && s[0] == 0x00 && s[1] == 0x14 => {
        AddrType::P2WPKH(s[2..22].try_into().unwrap())
      }

      s if s.len() == 34 && s[0] == 0x00 && s[1] == 0x20 => AddrType::P2WSH(rmd160(&s[2..34])),

      _ => AddrType::Unknown,
    }
  }
}