1use core::hint::assert_unchecked;
2
3use super::{large::INITIAL_ACCUMULATORS, *};
4
5pub unsafe trait FixedBuffer: AsRef<[u8]> {}
11
12pub unsafe trait FixedMutBuffer: FixedBuffer + AsMut<[u8]> {}
20
21unsafe impl<const N: usize> FixedBuffer for [u8; N] {}
23
24unsafe impl<const N: usize> FixedMutBuffer for [u8; N] {}
26
27unsafe impl<const N: usize> FixedBuffer for &[u8; N] {}
29
30unsafe impl<const N: usize> FixedBuffer for &mut [u8; N] {}
32
33unsafe impl<const N: usize> FixedMutBuffer for &mut [u8; N] {}
35
36const STRIPE_BYTES: usize = 64;
37const BUFFERED_STRIPES: usize = 4;
38const BUFFERED_BYTES: usize = STRIPE_BYTES * BUFFERED_STRIPES;
39type Buffer = [u8; BUFFERED_BYTES];
40
41const _: () = assert!(BUFFERED_BYTES > CUTOFF);
43
44#[derive(Clone)]
47pub struct SecretBuffer<S> {
48 seed: u64,
49 secret: S,
50 buffer: Buffer,
51}
52
53impl<S> SecretBuffer<S> {
54 pub fn into_secret(self) -> S {
56 self.secret
57 }
58}
59
60impl<S> SecretBuffer<S>
61where
62 S: FixedBuffer,
63{
64 pub fn new(seed: u64, secret: S) -> Result<Self, SecretTooShortError<S>> {
68 match Secret::new(secret.as_ref()) {
69 Ok(_) => Ok(Self {
70 seed,
71 secret,
72 buffer: [0; BUFFERED_BYTES],
73 }),
74 Err(e) => Err(SecretTooShortError(e, secret)),
75 }
76 }
77
78 #[inline(always)]
79 #[cfg(test)]
80 fn is_valid(&self) -> bool {
81 let secret = self.secret.as_ref();
82
83 secret.len() >= SECRET_MINIMUM_LENGTH
84 }
85
86 #[inline]
87 fn n_stripes(&self) -> usize {
88 Self::secret(&self.secret).n_stripes()
89 }
90
91 #[inline]
92 fn parts(&self) -> (u64, &Secret, &Buffer) {
93 (self.seed, Self::secret(&self.secret), &self.buffer)
94 }
95
96 #[inline]
97 fn parts_mut(&mut self) -> (u64, &Secret, &mut Buffer) {
98 (self.seed, Self::secret(&self.secret), &mut self.buffer)
99 }
100
101 fn secret(secret: &S) -> &Secret {
102 let secret = secret.as_ref();
103 unsafe { Secret::new_unchecked(secret) }
106 }
107}
108
109impl<S> SecretBuffer<S>
110where
111 S: FixedMutBuffer,
112{
113 pub fn with_seed(seed: u64, mut secret: S) -> Result<Self, SecretWithSeedError<S>> {
117 match <&mut DefaultSecret>::try_from(secret.as_mut()) {
118 Ok(secret_slice) => {
119 *secret_slice = DEFAULT_SECRET_RAW;
120 derive_secret(seed, secret_slice);
121
122 Ok(Self {
123 seed,
124 secret,
125 buffer: [0; BUFFERED_BYTES],
126 })
127 }
128 Err(_) => Err(SecretWithSeedError(secret)),
129 }
130 }
131}
132
133impl SecretBuffer<&'static [u8; DEFAULT_SECRET_LENGTH]> {
134 #[inline]
136 pub const fn default() -> Self {
137 SecretBuffer {
138 seed: DEFAULT_SEED,
139 secret: &DEFAULT_SECRET_RAW,
140 buffer: [0; BUFFERED_BYTES],
141 }
142 }
143}
144
145#[derive(Clone)]
146pub struct RawHasherCore<S> {
147 secret_buffer: SecretBuffer<S>,
148 buffer_usage: usize,
149 stripe_accumulator: StripeAccumulator,
150 total_bytes: usize,
151}
152
153impl<S> RawHasherCore<S> {
154 pub fn new(secret_buffer: SecretBuffer<S>) -> Self {
155 Self {
156 secret_buffer,
157 buffer_usage: 0,
158 stripe_accumulator: StripeAccumulator::new(),
159 total_bytes: 0,
160 }
161 }
162
163 pub fn into_secret(self) -> S {
164 self.secret_buffer.into_secret()
165 }
166}
167
168impl<S> RawHasherCore<S>
169where
170 S: FixedBuffer,
171{
172 #[inline]
173 pub fn write(&mut self, input: &[u8]) {
174 let this = self;
175 dispatch! {
176 fn write_impl<S>(this: &mut RawHasherCore<S>, input: &[u8])
177 [S: FixedBuffer]
178 }
179 }
180
181 #[inline]
182 pub fn finish<F>(&self, finalize: F) -> F::Output
183 where
184 F: Finalize,
185 {
186 let this = self;
187 dispatch! {
188 fn finish_impl<S, F>(this: &RawHasherCore<S>, finalize: F) -> F::Output
189 [S: FixedBuffer, F: Finalize]
190 }
191 }
192}
193
194#[inline(always)]
195fn write_impl<S>(vector: impl Vector, this: &mut RawHasherCore<S>, mut input: &[u8])
196where
197 S: FixedBuffer,
198{
199 if input.is_empty() {
200 return;
201 }
202
203 let RawHasherCore {
204 secret_buffer,
205 buffer_usage,
206 stripe_accumulator,
207 total_bytes,
208 } = this;
209
210 let n_stripes = secret_buffer.n_stripes();
211 let (_, secret, buffer) = secret_buffer.parts_mut();
212
213 *total_bytes += input.len();
214
215 unsafe {
217 debug_assert!(*buffer_usage <= buffer.len());
218 assert_unchecked(*buffer_usage <= buffer.len());
219 }
220
221 if !buffer.is_empty() {
223 let remaining = &mut buffer[*buffer_usage..];
224 let n_to_copy = usize::min(remaining.len(), input.len());
225
226 let (remaining_head, remaining_tail) = remaining.split_at_mut(n_to_copy);
227 let (input_head, input_tail) = input.split_at(n_to_copy);
228
229 remaining_head.copy_from_slice(input_head);
230 *buffer_usage += n_to_copy;
231
232 input = input_tail;
233
234 if !remaining_tail.is_empty() {
236 return;
237 }
238
239 if input.is_empty() {
241 return;
242 }
243
244 let (stripes, _) = buffer.bp_as_chunks();
245 for stripe in stripes {
246 stripe_accumulator.process_stripe(vector, stripe, n_stripes, secret);
247 }
248 *buffer_usage = 0;
249 }
250
251 debug_assert!(*buffer_usage == 0);
252
253 if let Some(len) = input.len().checked_sub(STRIPE_BYTES) {
257 let full_block_point = (len / STRIPE_BYTES) * STRIPE_BYTES;
258 let (stripes, remainder) = unsafe { input.split_at_unchecked(full_block_point) };
266 let (stripes, _) = stripes.bp_as_chunks();
267
268 for stripe in stripes {
269 stripe_accumulator.process_stripe(vector, stripe, n_stripes, secret);
270 }
271 input = remainder;
272 }
273
274 debug_assert!(*buffer_usage == 0);
277 debug_assert!(!input.is_empty());
278
279 let buffer_head = unsafe {
283 debug_assert!(input.len() < 2 * STRIPE_BYTES);
284 debug_assert!(2 * STRIPE_BYTES < buffer.len());
285 buffer.get_unchecked_mut(..input.len())
286 };
287
288 buffer_head.copy_from_slice(input);
289 *buffer_usage = input.len();
290}
291
292#[inline(always)]
293fn finish_impl<S, F>(vector: impl Vector, this: &RawHasherCore<S>, finalize: F) -> F::Output
294where
295 S: FixedBuffer,
296 F: Finalize,
297{
298 let RawHasherCore {
299 ref secret_buffer,
300 buffer_usage,
301 mut stripe_accumulator,
302 total_bytes,
303 } = *this;
304
305 let n_stripes = secret_buffer.n_stripes();
306 let (seed, secret, buffer) = secret_buffer.parts();
307
308 unsafe {
310 debug_assert!(buffer_usage <= buffer.len());
311 assert_unchecked(buffer_usage <= buffer.len());
312 }
313
314 if total_bytes > CUTOFF {
315 let input = &buffer[..buffer_usage];
316
317 let (stripes, remainder) = stripes_with_tail(input);
319 for stripe in stripes {
320 stripe_accumulator.process_stripe(vector, stripe, n_stripes, secret);
321 }
322
323 let mut temp = [0; 64];
324
325 let last_stripe = match input.last_chunk() {
326 Some(chunk) => chunk,
327 None => {
328 let n_to_reuse = 64 - input.len();
329 let to_reuse = buffer.len() - n_to_reuse;
330
331 let (temp_head, temp_tail) = temp.split_at_mut(n_to_reuse);
332 temp_head.copy_from_slice(&buffer[to_reuse..]);
333 temp_tail.copy_from_slice(input);
334
335 &temp
336 }
337 };
338
339 finalize.large(
340 vector,
341 stripe_accumulator.accumulator,
342 remainder,
343 last_stripe,
344 secret,
345 total_bytes,
346 )
347 } else {
348 finalize.small(DEFAULT_SECRET, seed, &buffer[..total_bytes])
349 }
350}
351
352pub trait Finalize {
353 type Output;
354
355 fn small(&self, secret: &Secret, seed: u64, input: &[u8]) -> Self::Output;
356
357 fn large(
358 &self,
359 vector: impl Vector,
360 acc: [u64; 8],
361 last_block: &[u8],
362 last_stripe: &[u8; 64],
363 secret: &Secret,
364 len: usize,
365 ) -> Self::Output;
366}
367
368#[cfg(feature = "alloc")]
369#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
370pub mod with_alloc {
371 use ::alloc::boxed::Box;
372
373 use super::*;
374
375 unsafe impl FixedBuffer for Box<[u8]> {}
377
378 unsafe impl FixedMutBuffer for Box<[u8]> {}
380
381 type AllocSecretBuffer = SecretBuffer<Box<[u8]>>;
382
383 impl AllocSecretBuffer {
384 pub fn allocate_default() -> Self {
387 Self {
388 seed: DEFAULT_SEED,
389 secret: DEFAULT_SECRET_RAW.to_vec().into(),
390 buffer: [0; BUFFERED_BYTES],
391 }
392 }
393
394 pub fn allocate_with_seed(seed: u64) -> Self {
397 let mut secret = DEFAULT_SECRET_RAW;
398 derive_secret(seed, &mut secret);
399
400 Self {
401 seed,
402 secret: secret.to_vec().into(),
403 buffer: [0; BUFFERED_BYTES],
404 }
405 }
406
407 pub fn allocate_with_seed_and_secret(
410 seed: u64,
411 secret: impl Into<Box<[u8]>>,
412 ) -> Result<Self, SecretTooShortError<Box<[u8]>>> {
413 Self::new(seed, secret.into())
414 }
415 }
416
417 pub type AllocRawHasher = RawHasherCore<Box<[u8]>>;
418
419 impl AllocRawHasher {
420 pub fn allocate_default() -> Self {
421 Self::new(SecretBuffer::allocate_default())
422 }
423
424 pub fn allocate_with_seed(seed: u64) -> Self {
425 Self::new(SecretBuffer::allocate_with_seed(seed))
426 }
427
428 pub fn allocate_with_seed_and_secret(
429 seed: u64,
430 secret: impl Into<Box<[u8]>>,
431 ) -> Result<Self, SecretTooShortError<Box<[u8]>>> {
432 SecretBuffer::allocate_with_seed_and_secret(seed, secret).map(Self::new)
433 }
434 }
435}
436
437#[cfg(feature = "alloc")]
438pub use with_alloc::AllocRawHasher;
439
440#[derive(Copy, Clone)]
443pub struct StripeAccumulator {
444 accumulator: [u64; 8],
445 current_stripe: usize,
446}
447
448impl StripeAccumulator {
449 pub fn new() -> Self {
450 Self {
451 accumulator: INITIAL_ACCUMULATORS,
452 current_stripe: 0,
453 }
454 }
455
456 #[inline]
457 pub fn process_stripe(
458 &mut self,
459 vector: impl Vector,
460 stripe: &[u8; 64],
461 n_stripes: usize,
462 secret: &Secret,
463 ) {
464 let Self {
465 accumulator,
466 current_stripe,
467 ..
468 } = self;
469
470 let secret_stripe = unsafe { secret.stripe(*current_stripe) };
475 vector.accumulate(accumulator, stripe, secret_stripe);
476
477 *current_stripe += 1;
478
479 if *current_stripe == n_stripes {
481 let secret_end = secret.last_stripe();
482 vector.round_scramble(accumulator, secret_end);
483
484 *current_stripe = 0;
485 }
486 }
487}
488
489pub struct SecretWithSeedError<S>(S);
492
493impl<S> SecretWithSeedError<S> {
494 pub fn into_secret(self) -> S {
496 self.0
497 }
498}
499
500impl<S> core::error::Error for SecretWithSeedError<S> {}
501
502impl<S> core::fmt::Debug for SecretWithSeedError<S> {
503 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
504 f.debug_tuple("SecretWithSeedError").finish()
505 }
506}
507
508impl<S> core::fmt::Display for SecretWithSeedError<S> {
509 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
510 write!(
511 f,
512 "The secret must be exactly {DEFAULT_SECRET_LENGTH} bytes"
513 )
514 }
515}
516
517pub struct SecretTooShortError<S>(secret::Error, S);
520
521impl<S> SecretTooShortError<S> {
522 pub fn into_secret(self) -> S {
524 self.1
525 }
526}
527
528impl<S> core::error::Error for SecretTooShortError<S> {}
529
530impl<S> core::fmt::Debug for SecretTooShortError<S> {
531 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
532 f.debug_tuple("SecretTooShortError").finish()
533 }
534}
535
536impl<S> core::fmt::Display for SecretTooShortError<S> {
537 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
538 self.0.fmt(f)
539 }
540}
541
542#[cfg(test)]
543mod test {
544 use super::*;
545
546 #[test]
547 fn secret_buffer_default_is_valid() {
548 assert!(SecretBuffer::default().is_valid());
549 }
550
551 #[test]
552 fn secret_buffer_allocate_default_is_valid() {
553 assert!(SecretBuffer::allocate_default().is_valid());
554 }
555
556 #[test]
557 fn secret_buffer_allocate_with_seed_is_valid() {
558 assert!(SecretBuffer::allocate_with_seed(0xdead_beef).is_valid());
559 }
560}