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