Rust Logosha2

SHA-2 (Secure Hash Algorithm 2) is a family of cryptographic hash functions designed by the National Security Agency (NSA) and published in 2001 by NIST as a U.S. Federal Information Processing Standard (FIPS). It comprises several hash functions with different digest sizes: SHA-256, SHA-512, SHA-224, SHA-384, SHA-512/224, and SHA-512/256.

These functions are fundamental tools in cryptography, used for various purposes including:
* Data Integrity Verification: Ensuring that data has not been tampered with. If even a single bit of the input changes, the resulting hash will be drastically different.
* Digital Signatures: Used to create a condensed, fixed-size representation of a message before signing it, ensuring the authenticity and integrity of digital documents.
* Password Storage: Storing hashes of passwords instead of the passwords themselves to protect against data breaches.
* Cryptocurrencies and Blockchain: Central to the proof-of-work mechanisms and transaction verification.

A cryptographic hash function takes an input (or 'message') of arbitrary length and produces a fixed-size string of bytes, known as a 'hash value', 'message digest', 'digital fingerprint', or simply 'hash'. The key properties that make SHA-2 suitable for cryptographic applications include:
1. Deterministic: The same input message will always produce the same hash output.
2. One-way (Preimage Resistance): It is computationally infeasible to reverse the process; that is, to find the original input message given only its hash value.
3. Collision Resistance: It is computationally infeasible to find two different input messages that produce the same hash output. While collisions theoretically exist (due to the pigeonhole principle), finding them is practically impossible for strong hash functions like SHA-2.

In Rust, the `sha2` crate provides an efficient and secure implementation of the SHA-2 family of hash functions. It integrates with the `digest` trait, which defines a common interface for cryptographic hash functions, allowing for a consistent way to compute hashes. To use `sha2`, you typically add it as a dependency in your `Cargo.toml` file.

Example Code

// First, add the sha2 crate to your Cargo.toml:
// [dependencies]
// sha2 = "0.10"
// hex = "0.4" // For easy hexadecimal output

use sha2::{Sha256, Sha512, Digest};
use hex; // To convert the hash bytes to a hexadecimal string

fn main() {
    let message_sha256 = "Hello, SHA-256!";
    let message_sha512 = "This is a longer message for SHA-512 hashing.";

    // --- SHA-256 Hashing ---
    println!("Hashing with SHA-256:");
    let mut hasher_256 = Sha256::new(); // Create a new Sha256 hasher instance
    hasher_256.update(message_sha256.as_bytes()); // Update the hasher with the message bytes
    let result_256 = hasher_256.finalize(); // Finalize the hash to get the digest

    println!("Original message: \"{}\"", message_sha256);
    // Convert the result (a fixed-size array of bytes) to a hexadecimal string for display
    println!("SHA-256 hash: {}", hex::encode(&result_256));
    println!("Digest length: {} bytes ({} bits)\n", result_256.len(), result_256.len() * 8);

    // --- SHA-512 Hashing ---
    println!("Hashing with SHA-512:");
    let mut hasher_512 = Sha512::new(); // Create a new Sha512 hasher instance
    hasher_512.update(message_sha512.as_bytes()); // Update the hasher with the message bytes
    let result_512 = hasher_512.finalize(); // Finalize the hash to get the digest

    println!("Original message: \"{}\"", message_sha512);
    // Convert the result to a hexadecimal string
    println!("SHA-512 hash: {}", hex::encode(&result_512));
    println!("Digest length: {} bytes ({} bits)\n", result_512.len(), result_512.len() * 8);

    // Demonstrate with an empty string
    println!("Hashing an empty string with SHA-256:");
    let mut hasher_empty = Sha256::new();
    hasher_empty.update("".as_bytes());
    let result_empty = hasher_empty.finalize();
    println!("SHA-256 hash of empty string: {}", hex::encode(&result_empty));

    // Demonstrate with different input, showing different hash
    println!("\nDemonstrating collision resistance (different input, different hash):");
    let message1 = "Rust programming";
    let message2 = "rust programming"; // Different case
    let mut hasher1 = Sha256::new();
    hasher1.update(message1.as_bytes());
    let hash1 = hasher1.finalize();
    println!("Hash of \"{}\": {}", message1, hex::encode(hash1));

    let mut hasher2 = Sha256::new();
    hasher2.update(message2.as_bytes());
    let hash2 = hasher2.finalize();
    println!("Hash of \"{}\": {}", message2, hex::encode(hash2));
    println!("Hashes are different: {}", hash1 != hash2);
}