proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
use sha2::{Digest, Sha256};
use std::io::{Read, Result};

pub struct HashUtils;

impl HashUtils {
    pub fn get_sha256_from_stream<R: Read>(mut reader: R) -> Result<String> {
        let mut hasher = Sha256::new();
        let mut buffer = [0; 65536]; // 64KB chunks

        loop {
            let n = reader.read(&mut buffer)?;
            if n == 0 {
                break;
            }
            hasher.update(&buffer[..n]);
        }

        Ok(hex::encode(hasher.finalize()))
    }

    pub fn get_sha256_from_bytes(data: &[u8]) -> String {
        let mut hasher = Sha256::new();
        hasher.update(data);
        hex::encode(hasher.finalize())
    }
}

pub fn calculate_hash(data: &[u8]) -> String {
    HashUtils::get_sha256_from_bytes(data)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    #[test]
    fn test_calculate_hash_empty() {
        let data = b"";
        let hash = calculate_hash(data);
        // SHA256 of empty string
        assert_eq!(
            hash,
            "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
        );
    }

    #[test]
    fn test_calculate_hash_hello_world() {
        let data = b"Hello, World!";
        let hash = calculate_hash(data);
        // SHA256 of "Hello, World!"
        assert_eq!(
            hash,
            "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
        );
    }

    #[test]
    fn test_calculate_hash_consistency() {
        let data = b"test data for consistency";
        let hash1 = calculate_hash(data);
        let hash2 = calculate_hash(data);
        assert_eq!(hash1, hash2);
    }

    #[test]
    fn test_get_sha256_from_stream() {
        let data = b"test stream data";
        let cursor = Cursor::new(data);
        let hash = HashUtils::get_sha256_from_stream(cursor).unwrap();

        // Should match calculate_hash for same data
        let expected = calculate_hash(data);
        assert_eq!(hash, expected);
    }

    #[test]
    fn test_get_sha256_from_stream_empty() {
        let data = b"";
        let cursor = Cursor::new(data);
        let hash = HashUtils::get_sha256_from_stream(cursor).unwrap();
        assert_eq!(
            hash,
            "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
        );
    }

    #[test]
    fn test_get_sha256_from_stream_large() {
        let data = vec![0u8; 10000]; // 10KB of zeros
        let cursor = Cursor::new(&data);
        let hash = HashUtils::get_sha256_from_stream(cursor).unwrap();

        let expected = calculate_hash(&data);
        assert_eq!(hash, expected);
    }

    #[test]
    fn test_get_sha256_from_bytes() {
        let data = b"test bytes";
        let hash = HashUtils::get_sha256_from_bytes(data);
        let expected = calculate_hash(data);
        assert_eq!(hash, expected);
    }
}