use clap::{Parser, Subcommand};
use bitcoin_hash_toolkit::{
sha256, ripemd160, hash160, generate_private_key, derive_public_key, derive_address
};
use hex;
use secp256k1::SecretKey;
#[derive(Parser, Debug)]
#[command(author, version, about = "Bitcoin Cryptography Toolkit", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
Sha256 {
data: String,
#[arg(short = 'x', long)]
hex_input: bool,
},
Ripemd160 {
data: String,
#[arg(short = 'x', long)]
hex_input: bool,
},
Hash160 {
data: String,
#[arg(short = 'x', long)]
hex_input: bool,
},
GenerateKey,
DeriveAddress {
private_key_hex: String,
},
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
match &cli.command {
Commands::Sha256 { data, hex_input } => handle_hash_command(data, *hex_input, sha256, "SHA256"),
Commands::Ripemd160 { data, hex_input } => handle_hash_command(data, *hex_input, ripemd160, "RIPEMD160"),
Commands::Hash160 { data, hex_input } => handle_hash_command(data, *hex_input, hash160, "HASH160"),
Commands::GenerateKey => handle_generate_key(),
Commands::DeriveAddress { private_key_hex } => handle_derive_address(private_key_hex),
}
}
fn handle_hash_command(data: &str, hex_input: bool, hash_func: fn(&[u8]) -> Vec<u8>, name: &str) -> Result<(), Box<dyn std::error::Error>> {
let input_bytes = if hex_input {
hex::decode(data)?
} else {
data.as_bytes().to_vec()
};
let hash_result = hash_func(&input_bytes);
println!("{}: {}", name, hex::encode(hash_result));
Ok(())
}
fn handle_generate_key() -> Result<(), Box<dyn std::error::Error>> {
let private_key = generate_private_key();
let public_key = derive_public_key(&private_key);
let address = derive_address(&public_key);
println!("\n--- Generated Key Pair ---");
println!("**Private Key (WIF format not implemented yet):** {}", hex::encode(private_key.secret_bytes()));
println!("**Public Key (Compressed):** {}", hex::encode(public_key.serialize()));
println!("**P2PKH Bitcoin Address (Mainnet):** {}", address);
Ok(())
}
fn handle_derive_address(private_key_hex: &str) -> Result<(), Box<dyn std::error::Error>> {
let pk_bytes = hex::decode(private_key_hex)?;
let private_key = SecretKey::from_slice(&pk_bytes)?;
let public_key = derive_public_key(&private_key);
let address = derive_address(&public_key);
println!("\n--- Address Derivation Result ---");
println!("**Input Private Key:** {}", private_key_hex);
println!("**Public Key (Compressed):** {}", hex::encode(public_key.serialize()));
println!("**P2PKH Bitcoin Address:** {}", address);
Ok(())
}