Skip to main content

twox_hash/xxhash3/
streaming.rs

1use core::hint::assert_unchecked;
2
3use super::{large::INITIAL_ACCUMULATORS, *};
4
5/// A buffer containing the secret bytes.
6///
7/// # Safety
8///
9/// Must always return a slice with the same number of elements.
10pub unsafe trait FixedBuffer: AsRef<[u8]> {}
11
12/// A mutable buffer to contain the secret bytes.
13///
14/// # Safety
15///
16/// Must always return a slice with the same number of elements. The
17/// slice must always be the same as that returned from
18/// [`AsRef::as_ref`][].
19pub unsafe trait FixedMutBuffer: FixedBuffer + AsMut<[u8]> {}
20
21// Safety: An array will never change size.
22unsafe impl<const N: usize> FixedBuffer for [u8; N] {}
23
24// Safety: An array will never change size.
25unsafe impl<const N: usize> FixedMutBuffer for [u8; N] {}
26
27// Safety: An array will never change size.
28unsafe impl<const N: usize> FixedBuffer for &[u8; N] {}
29
30// Safety: An array will never change size.
31unsafe impl<const N: usize> FixedBuffer for &mut [u8; N] {}
32
33// Safety: An array will never change size.
34unsafe 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
41// Ensure that a full buffer always implies we are in the 241+ byte case.
42const _: () = assert!(BUFFERED_BYTES > CUTOFF);
43
44/// Holds secret and temporary buffers that are ensured to be
45/// appropriately sized.
46#[derive(Clone)]
47pub struct SecretBuffer<S> {
48    seed: u64,
49    secret: S,
50    buffer: Buffer,
51}
52
53impl<S> SecretBuffer<S> {
54    /// Returns the secret.
55    pub fn into_secret(self) -> S {
56        self.secret
57    }
58}
59
60impl<S> SecretBuffer<S>
61where
62    S: FixedBuffer,
63{
64    /// Takes the seed, secret, and buffer and performs no
65    /// modifications to them, only validating that the sizes are
66    /// appropriate.
67    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        // Safety: We established the length at construction and the
104        // length is not allowed to change.
105        unsafe { Secret::new_unchecked(secret) }
106    }
107}
108
109impl<S> SecretBuffer<S>
110where
111    S: FixedMutBuffer,
112{
113    /// Fills the secret buffer with a secret derived from the seed
114    /// and the default secret. The secret must be exactly
115    /// [`DEFAULT_SECRET_LENGTH`][] bytes long.
116    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    /// Use the default seed and secret values while allocating nothing.
135    #[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    // Safety: This is an invariant of the buffer.
216    unsafe {
217        debug_assert!(*buffer_usage <= buffer.len());
218        assert_unchecked(*buffer_usage <= buffer.len());
219    }
220
221    // We have some previous data saved; try to fill it up and process it first
222    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        // We did not fill up the buffer
235        if !remaining_tail.is_empty() {
236            return;
237        }
238
239        // We don't know this isn't the last of the data
240        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    // Process as much of the input data in-place as possible,
254    // while leaving at least one full stripe for the
255    // finalization.
256    if let Some(len) = input.len().checked_sub(STRIPE_BYTES) {
257        let full_block_point = (len / STRIPE_BYTES) * STRIPE_BYTES;
258        // Safety: We know that `full_block_point` must be less than
259        // `input.len()` as we subtracted and then integer-divided
260        // (which rounds down) and then multiplied back. That's not
261        // evident to the compiler and `split_at` results in a
262        // potential panic.
263        //
264        // https://github.com/llvm/llvm-project/issues/104827
265        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    // Any remaining data has to be less than the buffer, and the
275    // buffer is empty so just fill up the buffer.
276    debug_assert!(*buffer_usage == 0);
277    debug_assert!(!input.is_empty());
278
279    // Safety: We have parsed all the full blocks of input except one
280    // and potentially a full block minus one byte. That amount of
281    // data must be less than the buffer.
282    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    // Safety: This is an invariant of the buffer.
309    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        // Ingest final stripes
318        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    // Safety: A plain slice will never change size.
376    unsafe impl FixedBuffer for Box<[u8]> {}
377
378    // Safety: A plain slice will never change size.
379    unsafe impl FixedMutBuffer for Box<[u8]> {}
380
381    type AllocSecretBuffer = SecretBuffer<Box<[u8]>>;
382
383    impl AllocSecretBuffer {
384        /// Allocates the secret and temporary buffers and fills them
385        /// with the default seed and secret values.
386        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        /// Allocates the secret and temporary buffers and uses the
395        /// provided seed to construct the secret value.
396        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        /// Allocates the temporary buffer and uses the provided seed
408        /// and secret buffer.
409        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/// Tracks which stripe we are currently on to know which part of the
441/// secret we should be using.
442#[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        // For each stripe
471
472        // Safety: The number of stripes is determined by the
473        // block size, which is determined by the secret size.
474        let secret_stripe = unsafe { secret.stripe(*current_stripe) };
475        vector.accumulate(accumulator, stripe, secret_stripe);
476
477        *current_stripe += 1;
478
479        // After a full block's worth
480        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
489/// The provided secret was not exactly [`DEFAULT_SECRET_LENGTH`][]
490/// bytes.
491pub struct SecretWithSeedError<S>(S);
492
493impl<S> SecretWithSeedError<S> {
494    /// Returns the secret.
495    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
517/// The provided secret was not at least [`SECRET_MINIMUM_LENGTH`][]
518/// bytes.
519pub struct SecretTooShortError<S>(secret::Error, S);
520
521impl<S> SecretTooShortError<S> {
522    /// Returns the secret.
523    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}