//! SHA3-256 hashing (FIPS 202). use sha3::{Digest, Sha3_256}; /// Compute SHA3-256 hash of `data`. #[must_use] pub fn hash(data: &[u8]) -> [u8; 32] { Sha3_256::digest(data).into() } /// Compute the hex-encoded fingerprint (SHA3-256) of a public key. #[must_use] pub fn fingerprint_hex(pk: &[u8]) -> String { let digest = hash(pk); hex_encode(&digest) } /// Encode bytes as lowercase hex string. fn hex_encode(bytes: &[u8]) -> String { use std::fmt::Write; let mut s = String::with_capacity(bytes.len() * 2); for &b in bytes { // fmt::Write for String is infallible — the Result is always Ok. let _ = write!(s, "{b:02x}"); } s } #[cfg(test)] mod tests { use super::*; use hex_literal::hex; #[test] fn empty_input() { assert_eq!( hash(b""), hex!("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a") ); } #[test] fn abc() { assert_eq!( hash(b"abc"), hex!("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532") ); } #[test] fn long_message() { assert_eq!( hash(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"), hex!("41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376") ); } #[test] fn fingerprint_hex_format() { let fp = fingerprint_hex(b"test"); assert_eq!(fp.len(), 64); assert!( fp.chars() .all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase()) ); } #[test] fn fingerprint_hex_deterministic() { let a = fingerprint_hex(b"test"); let b = fingerprint_hex(b"test"); assert_eq!(a, b); } #[test] fn fingerprint_hex_matches_hash() { let data = b"hello world"; let fp = fingerprint_hex(data); let expected = hex::encode(hash(data)); assert_eq!(fp, expected); } }