core_identity/
hash.rs

1//! Hash provider abstraction for identity operations
2//!
3//! This module provides a trait-based abstraction for hashing operations,
4//! allowing the core-identity crate to remain decoupled from specific
5//! hash implementations.
6
7use blake3;
8
9/// Hash provider trait for identity operations
10///
11/// This trait abstracts the hashing algorithm used for identity operations,
12/// following the Dependency Inversion Principle (DIP). The core identity
13/// logic depends on this abstraction rather than concrete implementations.
14///
15/// ## Design Rationale
16///
17/// - **Decoupling**: Core identity logic doesn't depend on Blake3 directly
18/// - **Testability**: Can use mock hash providers in tests
19/// - **Flexibility**: Easy to switch hash algorithms if needed
20/// - **Future-proofing**: Supports quantum-resistant hashes in the future
21pub trait HashProvider {
22    /// Hash arbitrary data to a 32-byte digest
23    ///
24    /// # Arguments
25    ///
26    /// * `data` - The data to hash
27    ///
28    /// # Returns
29    ///
30    /// A 32-byte hash digest
31    fn hash(&self, data: &[u8]) -> [u8; 32];
32
33    /// Get the name of this hash provider (for debugging/logging)
34    fn name(&self) -> &'static str;
35}
36
37/// Default Blake3 hash provider
38///
39/// This is the default implementation using Blake3, a fast cryptographic
40/// hash function. Blake3 provides:
41///
42/// - **Speed**: Faster than SHA-256, SHA-3, and BLAKE2
43/// - **Security**: 256-bit security level
44/// - **Simplicity**: Single-pass, no configuration needed
45/// - **Parallelism**: Can leverage multiple cores
46///
47/// ## Example
48///
49/// ```
50/// use core_identity::hash::{HashProvider, Blake3HashProvider};
51///
52/// let provider = Blake3HashProvider;
53/// let hash = provider.hash(b"Hello, world!");
54/// assert_eq!(hash.len(), 32);
55/// ```
56#[derive(Debug, Clone, Copy, Default)]
57pub struct Blake3HashProvider;
58
59impl HashProvider for Blake3HashProvider {
60    fn hash(&self, data: &[u8]) -> [u8; 32] {
61        blake3::hash(data).into()
62    }
63
64    fn name(&self) -> &'static str {
65        "blake3"
66    }
67}
68
69/// Global hash provider instance
70///
71/// This is the default hash provider used throughout the crate.
72/// Currently set to Blake3, but can be changed in the future if needed.
73static HASH_PROVIDER: Blake3HashProvider = Blake3HashProvider;
74
75/// Get the current hash provider
76///
77/// Returns a reference to the global hash provider. This allows
78/// the entire crate to use a consistent hashing algorithm.
79///
80/// ## Example
81///
82/// ```
83/// use core_identity::hash::{hash_provider, HashProvider};
84///
85/// let provider = hash_provider();
86/// let hash = provider.hash(b"data");
87/// ```
88pub fn hash_provider() -> &'static impl HashProvider {
89    &HASH_PROVIDER
90}
91
92/// Convenience function for hashing data
93///
94/// This is a shorthand for `hash_provider().hash(data)`.
95///
96/// ## Example
97///
98/// ```
99/// use core_identity::hash::hash;
100///
101/// let digest = hash(b"Hello, world!");
102/// assert_eq!(digest.len(), 32);
103/// ```
104#[inline]
105pub fn hash(data: &[u8]) -> [u8; 32] {
106    hash_provider().hash(data)
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn test_blake3_provider() {
115        let provider = Blake3HashProvider;
116        let hash1 = provider.hash(b"test");
117        let hash2 = provider.hash(b"test");
118
119        // Same input should produce same output
120        assert_eq!(hash1, hash2);
121
122        // Different input should produce different output
123        let hash3 = provider.hash(b"different");
124        assert_ne!(hash1, hash3);
125    }
126
127    #[test]
128    fn test_hash_function() {
129        let hash1 = hash(b"test data");
130        let hash2 = hash(b"test data");
131
132        assert_eq!(hash1, hash2);
133        assert_eq!(hash1.len(), 32);
134    }
135
136    #[test]
137    fn test_provider_name() {
138        let provider = Blake3HashProvider;
139        assert_eq!(provider.name(), "blake3");
140    }
141
142    #[test]
143    fn test_empty_input() {
144        let hash = hash(b"");
145        assert_eq!(hash.len(), 32);
146        // Blake3 of empty string is a known value
147        assert_ne!(hash, [0u8; 32]);
148    }
149}