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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
//! SHA-384 hash function implementation.
//!
//! # Purpose
//!
//! This module provides the SHA-384 algorithm as defined in FIPS 180-4.
//! SHA-384 is structurally identical to SHA-512 but produces a 384-bit
//! (48-byte) digest instead of 512 bits, and uses a different initial
//! vector (IV). The algorithm operates on 1024-bit message blocks and uses
//! the same 64-bit word operations as SHA-512.
//!
//! # Availability
//!
//! This module is only compiled when the `sha384` feature is enabled. It is
//! part of the default feature set. If the feature is disabled, the module
//! and its re-exports are absent from the crate.
//!
//! # Design Rationale
//!
//! SHA-384 is implemented as a thin wrapper around the core SHA-512
//! [`crate::sha512::Hash`] and [`crate::sha512::State`] types. This reuse
//! avoids code duplication because the message schedule, compression
//! function, and block processing are identical. The differences are:
//!
//! - A distinct initial vector (`new_state()`) replaces the SHA-512 IV.
//! - The final digest is truncated to the first 48 bytes of the 64-byte
//! SHA-512 output.
//!
//! This approach follows the official specification and guarantees that
//! SHA-384 results are exactly the leftmost 384 bits of the SHA-512 hash
//! computed with the SHA-384 IV.
//!
//! # HMAC and HKDF
//!
//! The module also instantiates HMAC-SHA-384 and HKDF-SHA-384 via the
//! crate's [`impl_hmac!`] and [`impl_hkdf!`] macros, providing ready-to-use
//! keyed-hash and key-derivation functions with 48-byte output and 128-byte
//! block size.
//!
//! # Security Considerations
//!
//! - **No unsafe code**: This module contains no `unsafe` blocks.
//! - **Zeroization**: The [`Hash::zeroize`] method clears internal state to
//! reduce the lifetime of sensitive data in memory.
//! - **Verification**: The hash verification uses a non-short-circuiting
//! comparison to reduce timing side-channel leakage (see
//! [`crate::utils::verify`]).
//!
//! # Internal Mechanism
//!
//! The internal [`Hash`] struct owns a full [`Sha512Hash`] instance, but
//! initialised with the SHA-384 IV. The `new_state()` function creates the
//! IV by loading the 64-byte constant big-endian and converting it to eight
//! 64-bit words. During `finalize`, the inner SHA-512 hasher produces a
//! 64-byte digest; the first 48 bytes are copied to the output. This
//! guarantees that SHA-384 and SHA-512 share the same core logic, reducing
//! the amount of code to audit.
//!
//! # Examples
//!
//! Computing a SHA-384 hash in one shot:
//!
//! ```
//! # use libvctrl_sha512::sha384::Hash;
//! let digest = Hash::hash(b"hello world");
//! assert_eq!(digest.len(), 48);
//! ```
//!
//! Verifying against a known test vector:
//!
//! ```
//! # use libvctrl_sha512::sha384::Hash;
//! let digest = Hash::hash(b"abc");
//! let expected: [u8; 48] = [
//! 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b,
//! 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07,
//! 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
//! 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed,
//! 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23,
//! 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7,
//! ];
//! assert_eq!(digest, expected);
//! ```
use crate;
use crateload_be;
/// Constructs the SHA-384 initial state vector as defined in FIPS 180-4.
///
/// # Purpose
///
/// This function builds the 8×64-bit IV by loading the constant big-endian
/// bytes specified for SHA-384. The values are the first 64 bits of the
/// fractional parts of the square roots of the 9th through 16th primes,
/// which differ from those used for SHA-512.
///
/// # Design Rationale
///
/// Using a distinct IV is what makes SHA-384 a separate function from
/// SHA-512 while sharing the same compression logic. This design ensures
/// the two algorithms produce unrelated outputs even for identical inputs.
///
/// # How It Works
///
/// The constant 64-byte IV is stored as a byte array. The function loops
/// over eight chunks of 8 bytes, converts each chunk from big-endian to a
/// `u64`, and assembles them into a [`State`] tuple. This state is then
/// used to initialise the inner [`Sha512Hash`] when a new SHA-384 hasher is
/// created.
///
/// # Examples
///
/// The function is private and not directly callable by users. It is shown
/// here for completeness of the module documentation.
/// SHA-384 hasher.
///
/// # Purpose
///
/// Wraps the full SHA-512 hasher ([`Sha512Hash`]) but initialises it with
/// the SHA-384 IV and truncates the final digest to 48 bytes. All update
/// operations are delegated to the inner hasher, so the performance
/// characteristics are identical to SHA-512.
///
/// # Design Rationale
///
/// The wrapper pattern avoids duplicating the SHA-512 compression logic.
/// It also makes the implementation easier to audit because the only
/// differences are the IV and the final truncation. The struct is
/// [`Clone`] but not [`Copy`] because the inner hasher owns its state and
/// buffer.
///
/// # Memory Layout
///
/// The struct contains one `Sha512Hash`, which in turn holds:
///
/// - An 8-element `u64` state (64 bytes).
/// - A 128-byte message buffer.
/// - A `usize` buffer index.
/// - A `u128` message length.
///
/// Total size is about 192 bytes. No heap allocation is performed.
///
/// # Security Considerations
///
/// Like SHA-512, the hasher supports zeroization of internal state via
/// [`Hash::zeroize`]. For verification, use [`Hash::verify`] to compare
/// digests with reduced timing side-channel leakage.
///
/// # Examples
///
/// Incremental hashing:
///
/// ```
/// # use libvctrl_sha512::sha384::Hash;
/// let mut h = Hash::new();
/// h.update(b"hello ");
/// h.update(b"world");
/// let result = h.finalize();
/// assert_eq!(result.len(), 48);
/// ```
///
/// One-shot hashing with a known answer:
///
/// ```
/// # use libvctrl_sha512::sha384::Hash;
/// let digest = Hash::hash(b"abc");
/// assert_eq!(digest, [
/// 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b,
/// 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07,
/// 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
/// 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed,
/// 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23,
/// 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7,
/// ]);
/// ```
;
// The following macro invocations generate HMAC-SHA-384 and HKDF-SHA-384
// structures directly inside this module. See the crate-level documentation for
// the `impl_hmac!` and `impl_hkdf!` macros for details on usage.
impl_hmac!;
impl_hkdf!;