Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
419 changes: 419 additions & 0 deletions bitcoin-hashing-toolkit-project/Cargo.lock

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions bitcoin-hashing-toolkit-project/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "bitcoin-do"
version = "0.1.1"
edition = "2021"
description = "A CLI tool and Rust library for Bitcoin cryptography operations including SHA256, RIPEMD160, HASH160, secp256k1 key generation, and address derivation"
license = "MIT"
keywords = ["bitcoin", "cryptography", "crypto", "blockchain", "secp256k1"]
categories = ["cryptography", "development-tools"]

[dependencies]
clap = { version = "4.5.39", features = ["derive"]}
owo-colors = "4.2.1"
sha2 = "0.10"
ripemd = "0.1"
secp256k1 = { version = "0.29", features = ["rand-std"]}
base58 = "0.2"
hex = "0.4"
62 changes: 62 additions & 0 deletions bitcoin-hashing-toolkit-project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Bitcoin-do

A CLI tool and Rust library for Bitcoin-related cryptography operations.

## Features

- **SHA256**: Compute SHA256 hash of input data
- **RIPEMD160**: Compute RIPEMD160 hash of input data
- **HASH160**: Compute HASH160 (RIPEMD160 of SHA256) of input data
- **Key Generation**: Generate secp256k1 keypairs
- **Address Derivation**: Derive P2PKH Bitcoin addresses from public keys

## Installation

### As a CLI Tool

```bash
cargo install bitcoin-do
```

### As a Library

Add to your `Cargo.toml`:

```toml
[dependencies]
bitcoin-do = "0.1.2"
```

## Usage

### CLI Examples

Generate a new keypair:

```bash
bitcoin-do generate-key
```

Derive address from public key:

```bash
bitcoin-do derive-address 02...
```

Hash some data (hex input):

```bash
bitcoin-do sha256 68656c6c6f
```

```bash
bitcoin-do Hash160 68656c6c6f
```

```bash
bitcoin-do Ripemd160 68656c6c6f
```

## License

MIT
62 changes: 62 additions & 0 deletions bitcoin-hashing-toolkit-project/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use secp256k1::{Secp256k1, SecretKey, PublicKey};
use sha2::{Sha256, Digest};
use ripemd::Ripemd160;
use base58::ToBase58;
use hex;

// Compute SHA256 hash of input data and return as hex string
pub fn sha256(data: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(data);
let result = hasher.finalize();
hex::encode(result)
}

// Compute RIPEMD160 hash of input data and return as hex string
pub fn ripemd160(data: &[u8]) -> String {
let mut hasher = Ripemd160::new();
hasher.update(data);
let result = hasher.finalize();
hex::encode(result)
}

// Compute HASH160 (RIPEMD160 of SHA256) of input data and return as hex string
pub fn hash160(data: &[u8]) -> String {
let sha = sha2::Sha256::digest(data);
let mut ripemd = Ripemd160::new();
ripemd.update(sha);
let result = ripemd.finalize();
hex::encode(result)
}

// Generate a new secp256k1 keypair
pub fn generate_keypair() -> (SecretKey, PublicKey) {
let secp = Secp256k1::new();
let (secret_key, public_key) = secp.generate_keypair(&mut secp256k1::rand::thread_rng());
(secret_key, public_key)
}

// Derive Bitcoin P2PKH address from public key (compressed)
pub fn derive_address(public_key: &PublicKey) -> String {
let compressed_pubkey = public_key.serialize();
let hash160 = hash160(&compressed_pubkey);
let hash160_bytes = hex::decode(&hash160).unwrap();

// Version byte for mainnet P2PKH
let mut address_bytes = vec![0x00];
address_bytes.extend(&hash160_bytes);

// Checksum: first 4 bytes of sha256(sha256(address_bytes))
let checksum = {
let mut hasher = Sha256::new();
hasher.update(&address_bytes);
let hash1 = hasher.finalize();
let mut hasher2 = Sha256::new();
hasher2.update(&hash1);
let hash2 = hasher2.finalize();
hash2[..4].to_vec()
};

address_bytes.extend(&checksum);
address_bytes.to_base58()
}
94 changes: 94 additions & 0 deletions bitcoin-hashing-toolkit-project/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use clap::{Parser, Subcommand};
use owo_colors::OwoColorize;
use bitcoin_do::{sha256, ripemd160, hash160, generate_keypair, derive_address};
use secp256k1::PublicKey;
use hex;

#[derive(Parser)]
#[command(name = "bitcoin-do")]
#[command(about = "This tool provides essential cryptograpic functions for Bitcoin development:
- Hashing functions: SHA256, RIPEMD160, HASH160
- Key generation: secp256k1 keypairs
- Address derivation: P2PKH Bitcoin addresses

Examples:
Generate a new keypair:
bitcoin-do generate-key

Derive address from public key:
bitcoin-do derive-address 02...

Hash some data:
bitcoin-do sha256 68656c6c6f")]

struct Cli {
#[command(subcommand)]
command: Commands,
}

#[derive(Subcommand)]
enum Commands {
// Compute SHA256 hash of hex data
Sha256 { data: String },
// Compute RIPEMD160 hash of hex data
Ripemd160 { data: String },
// Compute HASH160 (RIPEMD160 of SHA256) of hex dat
Hash160 { data: String },
// Generate a new secp256k1 keypair
GenerateKey,
// Derive Bitcoin address from public key (hex)
DeriveAddress { pubkey: String },
}

fn main() {
let cli = Cli::parse();

match cli.command {
Commands::Sha256 { data } => {
match hex::decode(&data) {
Ok(bytes) => {
let hash = sha256(&bytes);
println!("Your SHA256: {}", hash.green());
}
Err(_) => eprintln!("{}", "Invalid hex data".red()),
}
}
Commands::Ripemd160 { data } => {
match hex::decode(&data) {
Ok(bytes) => {
let hash = ripemd160(&bytes);
println!("Your RIPEMD160: {}", hash.green());
}
Err(_) => eprintln!("{}", "Invalid hex data".red()),
}
}
Commands::Hash160 { data } => {
match hex::decode(&data) {
Ok(bytes) => {
let hash = hash160(&bytes);
println!("Your HASH160: {}", hash.green());
}
Err(_) => eprintln!("{}", "Invalid hex data".red()),
}
}
Commands::GenerateKey => {
let (priv_key, pub_key) = generate_keypair();
println!("Your Bitcoin Private Key: {}", hex::encode(priv_key.secret_bytes()).yellow());
println!("Your Bitcoin Public Key: {}", hex::encode(pub_key.serialize()).cyan());
}
Commands::DeriveAddress { pubkey } => {
match hex::decode(&pubkey) {
Ok(bytes) => {
match PublicKey::from_slice(&bytes){
Ok(pk) => {
let address = derive_address(&pk);
println!("Your Bitcoin Address: {}", address.magenta());
}
Err(_) => eprintln!("{}", "Invalid public key".red()),
}
}
Err(_) => eprintln!("{}", "Invalid hex public key".red()),
}
}
}
}
2 changes: 1 addition & 1 deletion code/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion code/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "rust_for_bitcoin"
name = "Tosin_week2_assignment"
version = "0.1.0"
edition = "2024"

Expand Down
31 changes: 31 additions & 0 deletions code/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
mod task1;
mod task2;
mod task3;

use task1::btc_value_in_usd;
use task2::mine_blocks;
use task3::{get_rpc_url, Network };


fn main() {
println!("Hello, world!");

println!("Task 1");
let btc_val = 0.5;
let rate = 115_194.75;
let btc_usd = btc_value_in_usd(btc_val, rate);
println!("The price of {btc_val} in usd is {btc_usd}");

println!("Task 2");
mine_blocks(15);

println!("Task 3");
let network = Network::Mainnet;
let rpc = get_rpc_url(&network);
println!("The rpc of mainnet is {rpc}");

let network = Network::Testnet;
let rpc = get_rpc_url(&network);
println!("The rpc of testnet is {rpc}");


// import week_2 module
mod week_2;
// entry point to run all topics covered
Expand Down
1 change: 1 addition & 0 deletions code/src/week_2/task_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pub fn btc_value_in_usd(btc: f64, rate: f64) -> f64 {
btc * rate
}

//main run main
pub fn main() {
let btc = 0.25; //a dream amount
Expand Down
21 changes: 11 additions & 10 deletions code/src/week_2/task_2.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
fn mine_blocks(limit: u8) {
pub fn mine_blocks(limit: u8) {
let mut difficulty = 1;

for height in 1..=limit {
println!("Mining block #{}", height);
for height in 0..limit {
let block_no = height + 1;
println!("Mining block #{block_no}");

// Simulate difficulty
while difficulty < 3 {
println!("Simulating difficulty level {}", difficulty);
difficulty += 1; // the number of starting zero's
while difficulty < height {
difficulty += 1;
println!("Simluating difficulty {difficulty}");
println!(" ");
}

if height % 5 == 0 {
println!("Checkpoint reached");
println!("Checkpoint reached ✅");
println!(" ");
}
}
}

}
pub fn main() {
mine_blocks(10);
}
13 changes: 7 additions & 6 deletions code/src/week_2/task_3.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
enum Network {
pub enum Network {
Mainnet,
Testnet,
Regtest,
Regtest
}

fn get_rpc_url(network: &Network) -> &str {
pub fn get_rpc_url(network : &Network) -> &str {
match network {
Network::Mainnet => "https://mainnet.example.com",
Network::Testnet => "https://testnet.example.com",
Network::Regtest => "http://localhost:8332",
Network::Mainnet => "https://a_mainnet_rpc_url.com",
Network::Testnet => "https://a_testnet_rpc_url.com",
Network::Regtest => "https://a_regtest_rpc_url.com",
}
}
}

fn print_network_details(network: &Network) {
match network {
Expand Down