Weekly Rust Trivia is a problem-oriented series of articles that assist developers while learning Rust. Every article solves simple, everyday development tasks using the Rust standard library or leveraging popular and proven crates.

Question: How to compute a SHA256 hash of a file in Rust?

The sha2 crate is an implementation of cryptographic hash algorithms that we can use to compute hashes. We can combine functionality provided by the crate with the fs and io modules from Rusts standard library to solve this trivia. We also use the anyhow crate, to streamline error handling.

First let’s add the following dependencies using cargo add:

# Add anyhow as dependency
cargo add anyhow

# Add the sha2 crate as dependency
cargo add sha2

Having the crates added to our project, we can move on and implement creating the SHA256 hash of a file:

use std::{fs::File, io::Read};
use anyhow::Result;
use sha2::{Sha256, Digest};

fn compute_sha256_hash_of_file(file: &str) -> Result<String> {
    // Open the file
    let mut file = File::open(file)?;

    // Create a SHA-256 "hasher"
    let mut hasher = Sha256::new();

    // Read the file in 4KB chunks and feed them to the hasher
    let mut buffer = [0; 4096];
    loop {
        let bytes_read = file.read(&mut buffer)?;
        if bytes_read == 0 {
            break;
        }
        hasher.update(&buffer[..bytes_read]);
    }

    // Finalize the hash and get the result as a byte array
    Ok(format!("{:x}", hasher.finalize()))
}

The compute_sha256_hash_of_file function takes a file path as an argument and returns a anyhow::Result<String> containing computed hash if the operation was successful. If any error occurs, the Error variant is returned instead. The function starts by opening the file using the File::open() method, and then creates a SHA-256 hasher using the Sha256::new() method from the sha2 crate. The function then reads the file in 4KB chunks and feeds them to the hasher using the update() method. Finally, the function finalizes the hash and gets the result as a byte array, which is then formatted as a hexadecimal string and returned as part of the Result object.

We can use the compute_sha256_hash_of_file as shown below:

fn main() {
    match compute_sha256_hash_of_file("Cargo.toml") {
        Ok(hash) => println!("Hash: {}", hash),
        Err(e) => println!("Error: {}", e),
    }
}