waddling_errors_hash/
xxhash_impl.rs

1//! xxHash3 implementation for WDP-compliant hashing
2//!
3//! Provides xxHash3 (xxh3) implementation, the WDP-specified hash algorithm.
4//! xxHash3 is optimized for small inputs, making it ideal for error code hashing.
5
6#[cfg(not(feature = "std"))]
7extern crate alloc;
8
9#[cfg(feature = "std")]
10use std::string::String;
11
12#[cfg(not(feature = "std"))]
13use alloc::string::String;
14
15use crate::base62::to_base62;
16
17/// Compute xxHash3 hash with u64 seed
18///
19/// xxHash3 is the WDP-specified hash algorithm, optimized for small inputs
20/// (15-30 byte error codes) and achieving excellent performance.
21///
22/// # Performance
23/// - Speed: ~30 GB/s
24/// - Optimized for small inputs (perfect for error codes!)
25/// - Security: NOT cryptographically secure (not needed for error codes)
26/// - Cross-platform: C, Python, JS, Go, Java, Rust, etc.
27///
28/// # WDP Compliance
29///
30/// Per WDP Part 5, use seed `0x000031762D706477` for standard error codes.
31///
32/// # Examples
33///
34/// ```
35/// use waddling_errors_hash::xxhash_impl::compute_xxhash3;
36/// use waddling_errors_hash::WDP_SEED;
37///
38/// let hash = compute_xxhash3("E.AUTH.TOKEN.001", WDP_SEED);
39/// assert_eq!(hash.len(), 5);
40/// ```
41pub fn compute_xxhash3(input: &str, seed: u64) -> String {
42    use xxhash_rust::xxh3::xxh3_64_with_seed;
43
44    // Compute xxHash3 (64-bit variant) with proper seeding
45    let hash = xxh3_64_with_seed(input.as_bytes(), seed);
46
47    // Convert to base62 (first 40 bits)
48    let bytes = [
49        (hash >> 32) as u8,
50        (hash >> 24) as u8,
51        (hash >> 16) as u8,
52        (hash >> 8) as u8,
53        hash as u8,
54    ];
55
56    to_base62(&bytes)
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::algorithm::WDP_SEED;
63
64    #[test]
65    fn test_xxhash3_length() {
66        let hash = compute_xxhash3("E.AUTH.TOKEN.001", WDP_SEED);
67        assert_eq!(hash.len(), 5);
68    }
69
70    #[test]
71    fn test_xxhash3_alphanumeric() {
72        let hash = compute_xxhash3("E.AUTH.TOKEN.001", WDP_SEED);
73        assert!(hash.chars().all(|c| c.is_ascii_alphanumeric()));
74    }
75
76    #[test]
77    fn test_xxhash3_deterministic() {
78        let hash1 = compute_xxhash3("E.AUTH.TOKEN.001", WDP_SEED);
79        let hash2 = compute_xxhash3("E.AUTH.TOKEN.001", WDP_SEED);
80        assert_eq!(hash1, hash2);
81    }
82
83    #[test]
84    fn test_xxhash3_different_inputs() {
85        let hash1 = compute_xxhash3("E.AUTH.TOKEN.001", WDP_SEED);
86        let hash2 = compute_xxhash3("E.AUTH.TOKEN.002", WDP_SEED);
87        assert_ne!(hash1, hash2);
88    }
89
90    #[test]
91    fn test_xxhash3_different_seeds() {
92        let hash1 = compute_xxhash3("E.AUTH.TOKEN.001", 0x12345678);
93        let hash2 = compute_xxhash3("E.AUTH.TOKEN.001", 0x87654321);
94        assert_ne!(hash1, hash2);
95    }
96
97    #[test]
98    fn test_xxhash3_empty_string() {
99        let hash = compute_xxhash3("", WDP_SEED);
100        assert_eq!(hash.len(), 5);
101        assert!(hash.chars().all(|c| c.is_ascii_alphanumeric()));
102    }
103
104    #[test]
105    fn test_xxhash3_unicode() {
106        let hash = compute_xxhash3("E.AUTH.TOKEN.🦆", WDP_SEED);
107        assert_eq!(hash.len(), 5);
108        assert!(hash.chars().all(|c| c.is_ascii_alphanumeric()));
109    }
110
111    #[test]
112    fn test_xxhash3_long_input() {
113        let long_input = "E.AUTH.TOKEN.".to_string() + &"A".repeat(1000);
114        let hash = compute_xxhash3(&long_input, WDP_SEED);
115        assert_eq!(hash.len(), 5);
116    }
117
118    #[test]
119    fn test_wdp_seed_produces_consistent_hash() {
120        // This test verifies the WDP seed produces consistent results
121        let hash = compute_xxhash3("E.AUTH.TOKEN.001", WDP_SEED);
122        // The hash should be deterministic - same input + seed = same output
123        assert_eq!(hash.len(), 5);
124        assert!(hash.chars().all(|c| c.is_ascii_alphanumeric()));
125    }
126}