Skip to main content

zeph_common/
hash.rs

1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Hash utilities: BLAKE3 hex digests and fast SipHash-based u64 hashing.
5
6use std::hash::{DefaultHasher, Hash, Hasher};
7
8/// Returns the BLAKE3 hex digest of arbitrary bytes.
9#[must_use]
10pub fn blake3_hex(data: &[u8]) -> String {
11    blake3::hash(data).to_hex().to_string()
12}
13
14/// Returns the BLAKE3 hex digest of a UTF-8 string.
15#[must_use]
16pub fn blake3_hex_str(s: &str) -> String {
17    blake3_hex(s.as_bytes())
18}
19
20/// Returns a fast non-cryptographic `u64` hash of a string (`SipHash` via [`DefaultHasher`]).
21#[must_use]
22pub fn fast_hash(s: &str) -> u64 {
23    let mut h = DefaultHasher::new();
24    s.hash(&mut h);
25    h.finish()
26}
27
28#[cfg(test)]
29mod tests {
30    use super::*;
31
32    #[test]
33    fn blake3_hex_is_64_chars() {
34        let h = blake3_hex(b"hello");
35        assert_eq!(h.len(), 64);
36        assert!(h.chars().all(|c| c.is_ascii_hexdigit()));
37    }
38
39    #[test]
40    fn blake3_hex_deterministic() {
41        assert_eq!(blake3_hex(b"foo"), blake3_hex(b"foo"));
42    }
43
44    #[test]
45    fn blake3_hex_str_matches_bytes() {
46        assert_eq!(blake3_hex_str("hello"), blake3_hex(b"hello"));
47    }
48
49    #[test]
50    fn fast_hash_deterministic() {
51        assert_eq!(fast_hash("abc"), fast_hash("abc"));
52    }
53
54    #[test]
55    fn fast_hash_different_inputs_differ() {
56        assert_ne!(fast_hash("abc"), fast_hash("def"));
57    }
58
59    #[test]
60    fn fast_hash_empty() {
61        let _ = fast_hash(""); // must not panic
62    }
63}