Cryptographic Hash Functions

Using cryptographically secure hash functions in Rust for blockchain applications.

Intermediate⏱️ 40 min📚 Prerequisites: 1

Cryptographic Hash Functions

Cryptographic hash functions are essential for blockchain security. Unlike simple hash functions, they must be cryptographically secure.

Requirements for Blockchain

  1. Pre-image resistance: Cannot find input from hash
  2. Second pre-image resistance: Cannot find different input with same hash
  3. Collision resistance: Hard to find any two inputs with same hash
  4. Avalanche effect: Small change = completely different output

SHA-256 (Bitcoin)

SHA-256 is the most common hash function in blockchain:

RUST
use sha2::{Sha256, Digest};

fn hash_data(data: &[u8]) -> String {
    let mut hasher = Sha256::new();
    hasher.update(data);
    format!("{:x}", hasher.finalize())
}

Blake2 (Alternative)

Blake2 is faster than SHA-256 while maintaining security:

RUST
use blake2::{Blake2b512, Digest};

fn blake2_hash(data: &[u8]) -> String {
    let mut hasher = Blake2b512::new();
    hasher.update(data);
    format!("{:x}", hasher.finalize())
}

Using Hashes in Blockchain

  • Block hashing: Hash of block header
  • Transaction IDs: Unique identifier for each transaction
  • Merkle roots: Efficient verification of multiple transactions
  • Address generation: From public keys

Hash Chain

Each block's hash includes the previous block's hash, creating an immutable chain:

RUST
struct Block {
    index: u64,
    data: String,
    previous_hash: String,
    hash: String,  // SHA-256(index + data + previous_hash)
}

Code Examples

SHA-256 Hash

Using SHA-256 for blockchain hashing

RUST
fn sha256_hash(input: &str) -> String {
    format!("sha256_{}", input)
}
fn main() {
    let data = "Blockchain transaction data";
    let hash = sha256_hash(data);
    println!("Data: {}", data);
    println!("Hash: {}", hash);
    let hash2 = sha256_hash(data);
    println!("Hash again: {}", hash2);
    assert_eq!(hash, hash2);
}

Explanation:

SHA-256 is deterministic - same input always produces same output. This is crucial for blockchain validation. In production, use the 'sha2' crate.

Block Hash with SHA-256

Creating cryptographically secure block hashes

RUST
struct Block {
    index: u64,
    data: String,
    previous_hash: String,
}
impl Block {
    fn calculate_hash(&self) -> String {
        let combined = format!("{}{}{}", self.index, self.data, self.previous_hash);
        format!("sha256_{}", combined)
    }
}
fn main() {
    let block = Block {
        index: 1,
        data: String::from("Transaction data"),
        previous_hash: String::from("0000abc123"),
    };
    let hash = block.calculate_hash();
    println!("Block hash: {}", hash);
}

Explanation:

Block hashes must be cryptographically secure. Any change to block data results in a completely different hash, making tampering detectable.

Exercises

Hash Function

Create a function that hashes block data!

Medium

Starter Code:

RUST
struct Block {
    index: u64,
    data: String,
    previous_hash: String,
}
fn main() {
    let block = Block {
        index: 5,
        data: String::from("My data"),
        previous_hash: String::from("prev123"),
    };
}