libsoliton/soliton/src/primitives/sha3_256.rs
Kamal Tufekcic d73755a275
initial commit
Signed-off-by: Kamal Tufekcic <kamal@lo.sh>
2026-04-23 15:51:07 +03:00

82 lines
1.9 KiB
Rust

//! 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);
}
}