1mod encoding;
32pub mod hazmat;
33mod params;
34mod sponge;
35
36#[cfg(feature = "gpu")]
37pub mod gpu;
38
39pub use params::{
41 CAPACITY, COLLISION_BITS, OUTPUT_BYTES, OUTPUT_ELEMENTS, RATE, RATE_BYTES, ROUNDS_F, ROUNDS_P,
42 SBOX_DEGREE, WIDTH,
43};
44pub use sponge::{Hash, Hasher, OutputReader};
45
46pub fn hash(input: &[u8]) -> Hash {
48 let mut hasher = Hasher::new();
49 hasher.update(input);
50 hasher.finalize()
51}
52
53pub fn keyed_hash(key: &[u8; OUTPUT_BYTES], input: &[u8]) -> Hash {
55 let mut hasher = Hasher::new_keyed(key);
56 hasher.update(input);
57 hasher.finalize()
58}
59
60pub fn derive_key(context: &str, key_material: &[u8]) -> [u8; OUTPUT_BYTES] {
66 let ctx_hasher = Hasher::new_derive_key_context(context);
67 let ctx_hash = ctx_hasher.finalize();
68 let mut material_hasher = Hasher::new_derive_key_material(&ctx_hash);
69 material_hasher.update(key_material);
70 let result = material_hasher.finalize();
71 *result.as_bytes()
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn hash_basic() {
80 let h = hash(b"hello");
81 assert_ne!(h.as_bytes(), &[0u8; OUTPUT_BYTES]);
82 }
83
84 #[test]
85 fn hash_deterministic() {
86 let h1 = hash(b"test");
87 let h2 = hash(b"test");
88 assert_eq!(h1, h2);
89 }
90
91 #[test]
92 fn hash_different_inputs() {
93 assert_ne!(hash(b""), hash(b"a"));
94 assert_ne!(hash(b"a"), hash(b"b"));
95 assert_ne!(hash(b"ab"), hash(b"ba"));
96 }
97
98 #[test]
99 fn hash_matches_streaming() {
100 let data = b"streaming consistency test with enough data to cross boundaries!!";
101 let direct = hash(data);
102 let streamed = {
103 let mut h = Hasher::new();
104 h.update(&data[..10]);
105 h.update(&data[10..]);
106 h.finalize()
107 };
108 assert_eq!(direct, streamed);
109 }
110
111 #[test]
112 fn keyed_hash_differs_from_plain() {
113 let data = b"test";
114 assert_ne!(hash(data), keyed_hash(&[0u8; OUTPUT_BYTES], data));
115 }
116
117 #[test]
118 fn keyed_hash_different_keys() {
119 let data = b"test";
120 let h1 = keyed_hash(&[0u8; OUTPUT_BYTES], data);
121 let h2 = keyed_hash(&[1u8; OUTPUT_BYTES], data);
122 assert_ne!(h1, h2);
123 }
124
125 #[test]
126 fn derive_key_basic() {
127 let key = derive_key("my context", b"material");
128 assert_ne!(key, [0u8; OUTPUT_BYTES]);
129 }
130
131 #[test]
132 fn derive_key_differs_from_hash() {
133 let data = b"material";
134 let h = hash(data);
135 let k = derive_key("context", data);
136 assert_ne!(h.as_bytes(), &k);
137 }
138
139 #[test]
140 fn derive_key_different_contexts() {
141 let k1 = derive_key("context A", b"material");
142 let k2 = derive_key("context B", b"material");
143 assert_ne!(k1, k2);
144 }
145
146 #[test]
147 fn derive_key_different_materials() {
148 let k1 = derive_key("context", b"material A");
149 let k2 = derive_key("context", b"material B");
150 assert_ne!(k1, k2);
151 }
152
153 #[test]
154 fn xof_extends_hash() {
155 let mut xof = Hasher::new().update(b"xof test").finalize_xof();
156 let mut out = [0u8; OUTPUT_BYTES * 2];
157 xof.fill(&mut out);
158 let h = hash(b"xof test");
160 assert_eq!(&out[..OUTPUT_BYTES], h.as_bytes());
161 }
162
163 #[test]
164 fn large_input() {
165 let data = vec![0x42u8; 10_000];
166 let h = hash(&data);
167 assert_ne!(h.as_bytes(), &[0u8; OUTPUT_BYTES]);
168
169 let mut hasher = Hasher::new();
171 for chunk in data.chunks(137) {
172 hasher.update(chunk);
173 }
174 assert_eq!(h, hasher.finalize());
175 }
176}