1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
//! # BLAKE2b One-Shot Hashing Functions
//!
//! This module provides functions for computing BLAKE2b hashes in a single call.
//! These functions are convenient when the entire message is available at once and
//! you don't need the incremental API provided by the `state` module.
//!
//! ## One-Shot vs. Incremental Hashing
//!
//! - **One-Shot Hashing**: Process the entire message in a single function call
//! - Advantages: Simpler API, less code, potentially more efficient for small messages
//! - Disadvantages: Requires the entire message to be in memory
//!
//! - **Incremental Hashing**: Process the message in chunks using the `State` API
//! - Advantages: Memory-efficient for large messages, can process streaming data
//! - Disadvantages: Slightly more complex API, requires managing state
//!
//! ## BLAKE2b Security Properties
//!
//! - **Collision resistance**: Computationally infeasible to find two different inputs with the same hash
//! - **Preimage resistance**: Given a hash value, computationally infeasible to find an input that produces it
//! - **Second preimage resistance**: Given an input, computationally infeasible to find another input with the same hash
//! - **Pseudorandomness**: Output bits are indistinguishable from random when the input is unknown
//! - **Length-extension resistance**: Unlike SHA-1/SHA-2, knowing H(m) doesn't allow computing H(m||m')
//!
//! BLAKE2b produces hash values
//! of any size between 1 and 64 bytes.
//!
//! BLAKE2b features:
//! - High speed on 64-bit platforms
//! - Security comparable to SHA-3
//! - Simpler design than SHA-2
//! - Optimized for modern CPUs
//! - Optional key for MAC computation
//! - Optional salt and personalization parameters
//! - Parallel and tree hashing modes
//!
//! For incremental hashing (processing data in chunks), use the `State` struct instead.
use State;
/// Computes a BLAKE2b hash of the input data
///
/// This function computes a BLAKE2b hash of the input data with the specified output length.
/// It provides a simple one-shot interface for hashing data that is already available in memory.
///
/// ## Security Properties
///
/// - **Cryptographic strength**: BLAKE2b provides up to 256 bits of security (with 64-byte output)
/// - **Collision resistance**: Finding two different inputs with the same hash is computationally infeasible
/// - **Preimage resistance**: Given a hash value, finding an input that produces it is computationally infeasible
/// - **Deterministic**: The same input always produces the same output
///
/// ## Performance
///
/// BLAKE2b is optimized for 64-bit platforms and is typically faster than SHA-1, SHA-2, and SHA-3
/// while providing stronger security guarantees.
///
/// ## Arguments
///
/// * `input` - The data to hash
/// * `output_len` - Length of the output hash in bytes. Must be between `BYTES_MIN` (1)
/// and `BYTES_MAX` (64) bytes.
///
/// ## Returns
///
/// * `Result<Vec<u8>>` - The computed hash or an error
///
/// ## Errors
///
/// Returns an error if the output length is not between `BYTES_MIN` (1) and `BYTES_MAX` (64) bytes
///
/// ## Example
///
/// ```rust
/// use libsodium_rs as sodium;
/// use sodium::crypto_generichash::blake2b;
/// use sodium::ensure_init;
///
/// // Initialize libsodium
/// ensure_init().expect("Failed to initialize libsodium");
///
/// // Compute a 32-byte hash
/// let data = b"Hello, world!";
/// let hash = blake2b::hash(data, 32);
///
/// assert_eq!(hash.len(), 32);
/// ```
/// Computes a BLAKE2b hash of the input data with a key
///
/// This function computes a BLAKE2b hash of the input data using a key
/// for keyed hashing (MAC). It provides a convenient one-shot interface for hashing
/// data that is already available in memory.
///
/// ## Security Properties
///
/// - **Collision resistance**: Computationally infeasible to find two distinct inputs that
/// hash to the same output
/// - **Preimage resistance**: Given a hash value, it is computationally infeasible to find an
/// input that hashes to that value
/// - **Second preimage resistance**: Given an input, it is computationally infeasible to find
/// another input that hashes to the same value
/// - **Keyed mode**: When used with a key, BLAKE2b provides authentication (MAC functionality)
///
/// ## Use Cases
///
/// - **Data integrity verification**: Ensure data hasn't been altered
/// - **Password hashing**: Store password hashes securely (though specialized password
/// hashing functions like Argon2 are preferred)
/// - **Message authentication**: When used with a key
/// - **Checksums**: Verify file integrity
/// - **Pseudorandom number generation**: As part of a PRNG construction
///
/// ## Arguments
///
/// * `input` - Data to hash
/// * `key` - The key for keyed hashing (MAC). This turns the hash function
/// into a MAC (Message Authentication Code)
/// * `output_len` - Length of the output hash in bytes (between 1 and 64 bytes)
///
/// ## Returns
///
/// * `Result<Vec<u8>>` - The computed hash or an error
///
/// ## Errors
///
/// Returns an error if:
/// - The output length is not between `BYTES_MIN` (1) and `BYTES_MAX` (64) bytes
/// - The key length is not between `KEYBYTES_MIN` (0) and `KEYBYTES_MAX` (64) bytes
///
/// ## Example
///
/// ```rust
/// use libsodium_rs as sodium;
/// use sodium::crypto_generichash::blake2b;
/// use sodium::ensure_init;
///
/// // Initialize libsodium
/// ensure_init().expect("Failed to initialize libsodium");
///
/// // Simple hashing without a key
/// let data = b"Hello, world!";
/// let key2 = b"secret key";
/// let mac2 = blake2b::hash_with_key(data, key2, 32);
/// assert_eq!(mac2.len(), 32);
///
/// // Keyed hashing (MAC)
/// let key = b"secret key";
/// let mac = blake2b::hash_with_key(data, key, 32);
/// assert_eq!(mac.len(), 32);
/// ```
/// Computes a BLAKE2b hash with salt and personalization
///
/// This function computes a BLAKE2b hash with optional key, salt, and personalization
/// parameters. These parameters allow customizing the hash function for different applications
/// and creating domain separation between different uses of the same hash function.
///
/// ## Customization Parameters
///
/// - **Salt**: An optional 16-byte value that can be used to derive different hash functions
/// from the same algorithm. Unlike the key, the salt is not secret and can be publicly known.
/// It's useful for creating different hash functions for different applications or contexts.
///
/// - **Personalization**: An optional 16-byte string that identifies a particular application
/// or use case. This provides domain separation between different uses of the same hash function.
/// For example, you might use different personalization strings for "file checksums" vs "password hashing".
///
/// ## Security Benefits
///
/// Using salt and personalization provides several security benefits:
///
/// - **Domain separation**: Prevents hash values from one application being used in another
/// - **Uniqueness**: Creates distinct hash functions for different purposes
/// - **Isolation**: Ensures that a vulnerability in one usage context doesn't affect others
/// - **Versioning**: Allows for algorithm updates while maintaining backward compatibility
///
/// ## Arguments
///
/// * `input` - The data to hash
/// * `key` - Optional key for keyed hashing (MAC). If provided, must be at most
/// `KEYBYTES_MAX` (64) bytes long.
/// * `output_len` - Length of the output hash in bytes. Must be between `BYTES_MIN` (1)
/// and `BYTES_MAX` (64) bytes.
/// * `salt` - Optional salt for customizing the hash. If provided, must be exactly
/// `SALTBYTES` (16) bytes long.
/// * `personal` - Optional personalization string for customizing the hash. If provided,
/// must be exactly `PERSONALBYTES` (16) bytes long.
///
/// ## Returns
///
/// * `Result<Vec<u8>>` - The computed hash or an error
///
/// ## Errors
///
/// Returns an error if:
/// - The output length is not between `BYTES_MIN` (1) and `BYTES_MAX` (64) bytes
/// - The key length is greater than `KEYBYTES_MAX` (64) bytes
/// - The salt is provided and its length is not `SALTBYTES` (16) bytes
/// - The personalization is provided and its length is not `PERSONALBYTES` (16) bytes
///
/// ## Example
///
/// ```rust
/// use libsodium_rs as sodium;
/// use sodium::crypto_generichash::blake2b;
/// use sodium::ensure_init;
///
/// // Initialize libsodium
/// ensure_init().expect("Failed to initialize libsodium");
///
/// // Data to hash
/// let data = b"Hello, world!";
///
/// // Optional parameters
/// let key = b"secret key";
/// let salt = b"0123456789abcdef"; // Must be exactly 16 bytes
/// let personal = b"my-app-v1.0.0000"; // Must be exactly 16 bytes
///
/// // Compute hash with all parameters
/// let hash = blake2b::hash_with_salt_and_personal(
/// data,
/// Some(key),
/// 32, // 32-byte output
/// Some(salt),
/// Some(personal)
/// ).expect("Failed to compute hash");
///
/// assert_eq!(hash.len(), 32);
///
/// // Different personalization produces different hash for same input
/// let personal2 = b"my-app-v2.0.0000"; // Must be exactly 16 bytes
/// let hash2 = blake2b::hash_with_salt_and_personal(
/// data,
/// Some(key),
/// 32,
/// Some(salt),
/// Some(personal2)
/// ).expect("Failed to compute hash");
///
/// // The hashes should be different despite same input and key
/// assert_ne!(hash, hash2);
/// ```