Skip to main content

blake3_servil/
lib.rs

1//! `blake3-servil` is a fast [BLAKE3] implementation for 64-bit Arm and
2//! x86-64. It produces the same digests as official BLAKE3, with a call
3//! for each way programs hash (the table below).
4//!
5//! # Examples
6//!
7//! ```
8//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
9//! // Once per process, before any other call (see Startup self-test).
10//! blake3_servil::initialize();
11//!
12//! // Hash an input all at once.
13//! let hash1 = blake3_servil::hash(b"foobarbaz");
14//!
15//! // Hash an input incrementally.
16//! let mut hasher = blake3_servil::Hasher::new();
17//! hasher.update(b"foo");
18//! hasher.update(b"bar");
19//! hasher.update(b"baz");
20//! let hash2 = hasher.finalize();
21//! assert_eq!(hash1, hash2);
22//!
23//! // Extended output. OutputReader also implements Read and Seek.
24//! # #[cfg(feature = "std")] {
25//! let mut output = [0; 1000];
26//! let mut output_reader = hasher.finalize_xof();
27//! output_reader.fill(&mut output);
28//! assert_eq!(hash1, output[..32]);
29//! # }
30//!
31//! // Print a hash as hex.
32//! println!("{}", hash1);
33//! # Ok(())
34//! # }
35//! ```
36//!
37//! # Which call to use
38//!
39//! | Your data | Call |
40//! |---|---|
41//! | One message in memory | [`hash_multithreaded`] |
42//! | One message arriving in pieces | [`Hasher::update`] |
43//! | Many messages of one length, in one buffer | [`hash_many_multithreaded`] |
44//! | Many messages of different lengths, in memory | [`hash_each_multithreaded_with`] |
45//! | Many messages arriving at once (a server's uploads) | [`Hasher::update_each`] |
46//! | A stream of messages read, made, or arriving | [`stream`] |
47//! | A message read in verified ranges (Bao, iroh-blobs) | [`outboard_with`], [`verify_range_with`], [`Verifier`] |
48//!
49//! Each call returns once its hash is done, and uses other CPU cores
50//! where that is faster (the forms without `multithreaded` stay on the
51//! calling thread). A [`stream`] is different: your program submits
52//! messages and goes on to read or make the next ones while other threads
53//! hash them; each digest arrives in the place your program named, a
54//! little later. Choose it when reading or making the data keeps your
55//! thread busy, such as files read from memory or a fast disk: it hashes
56//! the most bytes per second.
57//!
58//! Short messages hash fastest together: 1024 messages of 64 bytes in one
59//! [`hash_many`] call take about a fifth of the time of 1024 [`hash`]
60//! calls.
61//!
62//! **Keyed hashing and key derivation** run at the plain hash's speed
63//! through a [`Mode`], passed to a call's `_with` form ([`hash_with`],
64//! [`hash_many_with`], ...), to [`Hasher::new_with`], or to a [`stream`].
65//!
66//! **Hashing now and then** (rather than nonstop) is slower per byte on
67//! every hash function, since its code and data must come back into the
68//! CPU's caches and a resting core runs slower at first: hashing 64 KiB
69//! after a pause takes about three times as long as nonstop on an Apple M4
70//! Max.
71//!
72//! **Apple M4 and later** have one matrix unit that this crate uses for
73//! inputs of 16 KiB and more; when several threads of a program hash such
74//! inputs at the same moment, one runs at full speed and the others at
75//! about two thirds of it. The multithreaded calls share the work among
76//! the cores themselves, so a program gets the most from one thread making
77//! them.
78//!
79//! # Memory
80//!
81//! - **A [`Hasher`] is about 18 KiB**; box it where that matters.
82//! - **Single-threaded calls allocate nothing**: [`hash`], [`hash_with`], [`hash_many`], [`hash_many_with`],
83//!   [`Hasher::update`] and [`Hasher::finalize`], and [`OutputReader`].
84//!   [`Hasher::update_reader`] uses a 1 MiB buffer while it reads past
85//!   64 KiB, and [`hash_each_with`] 32 bytes for each chunk of its messages
86//!   of 2 to 15 chunks, each freed when it returns. [`outboard_with`]
87//!   returns the outboard it allocates (64 bytes for each 16 KiB), and
88//!   [`verify_range_with`] allocates 32 bytes for each group of its range,
89//!   freed when it returns. A [`Verifier`] keeps up to 16 KiB, for a group
90//!   that arrives in pieces, and 48 bytes for each level of the tree; each
91//!   [`Verifier::update`] allocates about 100 bytes for each node its piece
92//!   holds, and its groups' working space (about 60 bytes a chunk), freed when it
93//!   returns.
94//! - **Multithreaded calls** allocate nothing below 512 KiB, where they
95//!   hash on the calling thread. Above it they keep a list of the pieces
96//!   they hand out, freed when they return: 48 bytes for each 128 KiB of
97//!   input, and at most 200 bytes for each CPU (1 GiB on 16 CPUs: 390 KiB).
98//! - **A [`stream`]** takes its storage (its 2 MiB ring and its entries)
99//!   from a pool the process keeps: a thread's first stream allocates it
100//!   and later streams reuse it, never freed.
101//! - **Once per process**: the startup self-test's buffers, about 45 KiB
102//!   of the calling thread's stack while it runs (it allocates nothing),
103//!   and the threads: by default a worker per CPU beyond the first, each with the
104//!   standard library's stack, started by [`initialize_multithreaded`].
105//!
106//! # Startup self-test
107//!
108//! **Every program calls [`initialize`] (or [`initialize_multithreaded`])
109//! once, before any other call of this crate**: a call before it panics, in
110//! every build, saying so. The check costs nothing: it is part of the
111//! platform load every call makes. **A program that makes multithreaded
112//! calls or streams calls [`initialize_multithreaded`]**: a
113//! multithreaded call or a stream before it panics (one load per call).
114//!
115//! `initialize` checks the build and the CPU before the process first
116//! hashes, in well under a millisecond. It runs every assembly kernel built
117//! for this machine on fixed inputs and compares the outputs with the
118//! reference implementation's. A mismatch stops the program with a panic
119//! naming the code path. Other threads that call `initialize` meanwhile
120//! wait for it, and stop with it if it fails.
121//!
122//! # Cargo Features
123//!
124//! The `std` feature (the only feature enabled by default) enables the
125//! [`Write`] implementation and the [`update_reader`](Hasher::update_reader)
126//! method for [`Hasher`], and also the [`Read`] and [`Seek`] implementations
127//! for [`OutputReader`].
128//!
129//! The `zeroize` feature (off by default, on for [docs.rs])
130//! implements
131//! [`Zeroize`](https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html) for
132//! this crate's types.
133//!
134//! The `serde` feature (off by default, on for [docs.rs]) implements
135//! [`serde::Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) and
136//! [`serde::Deserialize`](https://docs.rs/serde/latest/serde/trait.Deserialize.html)
137//! for [`Hash`](struct@Hash).
138//!
139//! [BLAKE3]: https://blake3.io
140//! [docs.rs]: https://docs.rs/
141//! [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
142//! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
143//! [`Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html
144//! [`digest`]: https://crates.io/crates/digest
145//! [`signature`]: https://crates.io/crates/signature
146
147#![cfg_attr(not(feature = "std"), no_std)]
148
149// The tests use std in every build, the no_std one included.
150#[cfg(all(test, not(feature = "std")))]
151#[macro_use]
152extern crate std;
153
154#[cfg(test)]
155mod test;
156
157#[cfg(feature = "std")]
158mod each;
159#[cfg(feature = "std")]
160pub use each::{hash_each_multithreaded_with, hash_each_with};
161#[cfg(feature = "std")]
162mod outboard;
163#[cfg(feature = "std")]
164#[doc(hidden)]
165#[cfg(feature = "std")]
166pub use outboard::{GROUP_LEN, Verifier, outboard_multithreaded_with, outboard_with, verify_range_with};
167
168mod platform;
169
170// Platform-specific implementations of the compression function. These
171// BLAKE3-specific cfg flags are set in build.rs.
172// The intrinsics AVX2 kernels: `avx2` itself without the assembly, and
173// everywhere on x86 the pass of whole chunks with a partial one (as in
174// rust_sse41).
175#[cfg(target_arch = "x86_64")]
176#[cfg_attr(not(blake3_avx2_rust), allow(dead_code))]
177mod rust_avx2;
178#[cfg(blake3_avx2_rust)]
179use rust_avx2 as avx2;
180#[cfg(blake3_avx2_ffi)]
181#[path = "ffi_avx2.rs"]
182mod avx2;
183#[cfg(blake3_avx512_ffi)]
184#[path = "ffi_avx512.rs"]
185mod avx512;
186#[cfg(blake3_neon)]
187#[path = "ffi_neon_hybrid.rs"]
188mod neon_hybrid;
189mod portable;
190#[cfg(target_arch = "x86_64")]
191#[cfg_attr(not(blake3_sse41_rust), allow(dead_code))]
192mod rust_sse41;
193#[cfg(blake3_sme2)]
194#[path = "ffi_sme2.rs"]
195mod sme2;
196#[cfg(blake3_sse41_rust)]
197use rust_sse41 as sse41;
198#[cfg(blake3_sse41_ffi)]
199#[path = "ffi_sse41.rs"]
200mod sse41;
201
202#[cfg(feature = "std")]
203mod io;
204/// The primitives src/finish.rs runs on: the standard library's here, and
205/// Shuttle's in tests/shuttle_finish.rs, which compiles that file beside its own
206/// `finish_sync`.
207#[cfg(feature = "std")]
208mod finish_sync {
209    pub use std::sync::Mutex;
210    pub use std::sync::atomic::{AtomicUsize, Ordering};
211    pub use std::thread;
212}
213#[cfg(feature = "std")]
214mod finish;
215/// The primitives src/park.rs runs on: the standard library's here, and
216/// Shuttle's in tests/shuttle_park.rs, which compiles that file beside its
217/// own `park_sync`.
218#[cfg(feature = "std")]
219mod park_sync {
220    pub use std::sync::OnceLock;
221    pub use std::sync::atomic::{AtomicU64, Ordering};
222    pub use std::thread;
223}
224#[cfg(feature = "std")]
225mod lanes;
226mod many;
227#[cfg(feature = "std")]
228mod park;
229#[cfg(feature = "std")]
230#[cfg(feature = "std")]
231#[cfg(feature = "std")]
232mod stream;
233mod tree;
234#[cfg(feature = "std")]
235pub use stream::{Stream, stream};
236mod pair;
237mod self_test;
238
239/// A kind of kernel or path a call ran, for the tests that check which
240/// path a call took. Each build notes the kinds it has.
241#[derive(Clone, Copy)]
242#[allow(dead_code)]
243pub(crate) enum Ran {
244    /// The call went to the pool.
245    Pool = 1,
246    /// The call wanted SME2 and another thread held the turn.
247    TurnTaken = 2,
248}
249
250#[cfg(all(test, feature = "std"))]
251std::thread_local! {
252    /// The kinds this thread's calls ran since the test last cleared it.
253    pub(crate) static RAN: core::cell::Cell<u32> = const { core::cell::Cell::new(0) };
254}
255
256/// Note that `kind` happened: in the tests' record, and nothing in any
257/// other build (some of which have no kernel to note).
258#[inline(always)]
259#[allow(dead_code)]
260pub(crate) fn ran(kind: Ran) {
261    #[cfg(all(test, feature = "std"))]
262    RAN.with(|r| r.set(r.get() | kind as u32));
263    let _ = kind;
264}
265
266#[cfg(all(test, feature = "std"))]
267std::thread_local! {
268    /// The assembly entry points this thread's calls ran since the test
269    /// last cleared it, by address.
270    pub(crate) static RAN_ENTRIES: core::cell::RefCell<std::collections::BTreeSet<usize>> = const { core::cell::RefCell::new(std::collections::BTreeSet::new()) };
271}
272
273/// Note that the assembly entry point at `entry` ran (in the tests'
274/// record; nothing in any other build).
275#[inline(always)]
276#[allow(dead_code)]
277pub(crate) fn ran_kernel(entry: *const ()) {
278    #[cfg(all(test, feature = "std"))]
279    RAN_ENTRIES.with(|r| r.borrow_mut().insert(entry as usize));
280    let _ = entry;
281}
282
283use arrayvec::{ArrayString, ArrayVec};
284use core::cmp;
285use core::fmt;
286use platform::{MAX_SIMD_DEGREE, MAX_SIMD_DEGREE_OR_2, Platform};
287#[cfg(feature = "zeroize")]
288use zeroize::Zeroize;
289
290/// The number of bytes in a [`Hash`](struct.Hash.html), 32.
291pub const OUT_LEN: usize = 32;
292
293/// The number of bytes in a key, 32.
294pub const KEY_LEN: usize = 32;
295
296/// The number of bytes in a block, 64.
297///
298/// You don't usually need to think about this number. One case where it matters is calling
299/// [`OutputReader::fill`] in a loop, where using a `buf` argument that's a multiple of `BLOCK_LEN`
300/// avoids repeating work.
301pub const BLOCK_LEN: usize = 64;
302
303/// The number of bytes in a chunk, 1024.
304///
305/// You don't usually need to think about this number, but it often comes up in benchmarks, because
306/// the maximum degree of parallelism used by the implementation equals the number of chunks.
307pub const CHUNK_LEN: usize = 1024;
308
309const MAX_DEPTH: usize = 54; // 2^54 * CHUNK_LEN = 2^64
310
311// While iterating the compression function within a chunk, the CV is
312// represented as words, to avoid doing two extra endianness conversions for
313// each compression in the portable implementation. But the hash_many interface
314// needs to hash both input bytes and parent nodes, so it's better for its
315// output CVs to be represented as bytes.
316type CVWords = [u32; 8];
317type CVBytes = [u8; 32]; // little-endian
318
319const IV: &CVWords = &[0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19];
320
321const MSG_SCHEDULE: [[usize; 16]; 7] = [
322    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
323    [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8],
324    [3, 4, 10, 12, 13, 2, 7, 14, 6, 5, 9, 0, 11, 15, 8, 1],
325    [10, 7, 12, 9, 14, 3, 13, 15, 4, 0, 11, 2, 5, 8, 1, 6],
326    [12, 13, 9, 11, 15, 10, 14, 8, 7, 2, 5, 3, 0, 1, 6, 4],
327    [9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7],
328    [11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13],
329];
330
331// These are the internal flags that we use to domain separate root/non-root,
332// chunk/parent, and chunk beginning/middle/end. These get set at the high end
333// of the block flags word in the compression function, so their values start
334// high and go down.
335const CHUNK_START: u8 = 1 << 0;
336const CHUNK_END: u8 = 1 << 1;
337const PARENT: u8 = 1 << 2;
338const ROOT: u8 = 1 << 3;
339const KEYED_HASH: u8 = 1 << 4;
340const DERIVE_KEY_CONTEXT: u8 = 1 << 5;
341const DERIVE_KEY_MATERIAL: u8 = 1 << 6;
342
343#[inline]
344fn counter_low(counter: u64) -> u32 {
345    counter as u32
346}
347
348#[inline]
349fn counter_high(counter: u64) -> u32 {
350    (counter >> 32) as u32
351}
352
353/// An output of the default size, 32 bytes, which provides constant-time
354/// equality checking.
355///
356/// `Hash` implements [`From`] and [`Into`] for `[u8; 32]`, and it provides
357/// [`from_bytes`] and [`as_bytes`] for explicit conversions between itself and
358/// `[u8; 32]`. However, byte arrays and slices don't provide constant-time
359/// equality checking, which is often a security requirement in software that
360/// handles private data. `Hash` doesn't implement [`Deref`] or [`AsRef`], to
361/// avoid situations where a type conversion happens implicitly and the
362/// constant-time property is accidentally lost.
363///
364/// `Hash` provides the [`to_hex`] and [`from_hex`] methods for converting to
365/// and from hexadecimal. It also implements [`Display`] and [`FromStr`].
366///
367/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
368/// [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html
369/// [`as_bytes`]: #method.as_bytes
370/// [`from_bytes`]: #method.from_bytes
371/// [`Deref`]: https://doc.rust-lang.org/stable/std/ops/trait.Deref.html
372/// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
373/// [`to_hex`]: #method.to_hex
374/// [`from_hex`]: #method.from_hex
375/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
376/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
377#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
378#[derive(Clone, Copy, Hash, Eq)]
379#[repr(transparent)]
380pub struct Hash([u8; OUT_LEN]);
381
382impl Hash {
383    /// The raw bytes of the `Hash`. Note that byte arrays don't provide
384    /// constant-time equality checking, so if you need to compare hashes,
385    /// prefer the `Hash` type.
386    #[inline]
387    pub const fn as_bytes(&self) -> &[u8; OUT_LEN] {
388        &self.0
389    }
390
391    /// Create a `Hash` from its raw bytes representation.
392    pub const fn from_bytes(bytes: [u8; OUT_LEN]) -> Self {
393        Self(bytes)
394    }
395
396    /// The raw bytes of the `Hash`, as a slice. Useful for serialization. Note that byte arrays
397    /// don't provide constant-time equality checking, so if you need to compare hashes, prefer
398    /// the `Hash` type.
399    #[inline]
400    pub const fn as_slice(&self) -> &[u8] {
401        self.0.as_slice()
402    }
403
404    /// Create a `Hash` from its raw bytes representation as a slice.
405    ///
406    /// Returns an error if the slice is not exactly 32 bytes long.
407    pub fn from_slice(bytes: &[u8]) -> Result<Self, core::array::TryFromSliceError> {
408        Ok(Self::from_bytes(bytes.try_into()?))
409    }
410
411    /// Encode a `Hash` in lowercase hexadecimal.
412    ///
413    /// The returned [`ArrayString`] is a fixed size and doesn't allocate memory
414    /// on the heap. Note that [`ArrayString`] doesn't provide constant-time
415    /// equality checking, so if you need to compare hashes, prefer the `Hash`
416    /// type.
417    ///
418    /// [`ArrayString`]: https://docs.rs/arrayvec/0.5.1/arrayvec/struct.ArrayString.html
419    pub fn to_hex(&self) -> ArrayString<{ 2 * OUT_LEN }> {
420        let mut s = ArrayString::new();
421        let table = b"0123456789abcdef";
422        for &b in self.0.iter() {
423            s.push(table[(b >> 4) as usize] as char);
424            s.push(table[(b & 0xf) as usize] as char);
425        }
426        s
427    }
428
429    /// Decode a `Hash` from hexadecimal. Both uppercase and lowercase ASCII
430    /// bytes are supported.
431    ///
432    /// Any byte outside the ranges `'0'...'9'`, `'a'...'f'`, and `'A'...'F'`
433    /// results in an error. An input length other than 64 also results in an
434    /// error.
435    ///
436    /// Note that `Hash` also implements `FromStr`, so `Hash::from_hex("...")`
437    /// is equivalent to `"...".parse()`.
438    pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, HexError> {
439        fn hex_val(byte: u8) -> Result<u8, HexError> {
440            match byte {
441                b'A'..=b'F' => Ok(byte - b'A' + 10),
442                b'a'..=b'f' => Ok(byte - b'a' + 10),
443                b'0'..=b'9' => Ok(byte - b'0'),
444                _ => Err(HexError(HexErrorInner::InvalidByte(byte))),
445            }
446        }
447        let hex_bytes: &[u8] = hex.as_ref();
448        if hex_bytes.len() != OUT_LEN * 2 {
449            return Err(HexError(HexErrorInner::InvalidLen(hex_bytes.len())));
450        }
451        let mut hash_bytes: [u8; OUT_LEN] = [0; OUT_LEN];
452        for i in 0..OUT_LEN {
453            hash_bytes[i] = 16 * hex_val(hex_bytes[2 * i])? + hex_val(hex_bytes[2 * i + 1])?;
454        }
455        Ok(Hash::from(hash_bytes))
456    }
457}
458
459impl From<[u8; OUT_LEN]> for Hash {
460    #[inline]
461    fn from(bytes: [u8; OUT_LEN]) -> Self {
462        Self::from_bytes(bytes)
463    }
464}
465
466impl From<Hash> for [u8; OUT_LEN] {
467    #[inline]
468    fn from(hash: Hash) -> Self {
469        hash.0
470    }
471}
472
473impl core::str::FromStr for Hash {
474    type Err = HexError;
475
476    fn from_str(s: &str) -> Result<Self, Self::Err> {
477        Hash::from_hex(s)
478    }
479}
480
481#[cfg(feature = "zeroize")]
482impl Zeroize for Hash {
483    fn zeroize(&mut self) {
484        // Destructuring to trigger compile error as a reminder to update this impl.
485        let Self(bytes) = self;
486        bytes.zeroize();
487    }
488}
489
490/// This implementation is constant-time.
491impl PartialEq for Hash {
492    #[inline]
493    fn eq(&self, other: &Hash) -> bool {
494        constant_time_eq::constant_time_eq_32(&self.0, &other.0)
495    }
496}
497
498/// This implementation is constant-time.
499impl PartialEq<[u8; OUT_LEN]> for Hash {
500    #[inline]
501    fn eq(&self, other: &[u8; OUT_LEN]) -> bool {
502        constant_time_eq::constant_time_eq_32(&self.0, other)
503    }
504}
505
506/// This implementation is constant-time if the target is 32 bytes long.
507impl PartialEq<[u8]> for Hash {
508    #[inline]
509    fn eq(&self, other: &[u8]) -> bool {
510        constant_time_eq::constant_time_eq(&self.0, other)
511    }
512}
513
514impl fmt::Display for Hash {
515    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
516        // Formatting field as `&str` to reduce code size since the `Debug`
517        // dynamic dispatch table for `&str` is likely needed elsewhere already,
518        // but that for `ArrayString<[u8; 64]>` is not.
519        let hex = self.to_hex();
520        let hex: &str = hex.as_str();
521
522        f.write_str(hex)
523    }
524}
525
526impl fmt::Debug for Hash {
527    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
528        // Formatting field as `&str` to reduce code size since the `Debug`
529        // dynamic dispatch table for `&str` is likely needed elsewhere already,
530        // but that for `ArrayString<[u8; 64]>` is not.
531        let hex = self.to_hex();
532        let hex: &str = hex.as_str();
533
534        f.debug_tuple("Hash").field(&hex).finish()
535    }
536}
537
538/// The error type for [`Hash::from_hex`].
539///
540/// The `.to_string()` representation of this error currently distinguishes between bad length
541/// errors and bad character errors. This is to help with logging and debugging, but it isn't a
542/// stable API detail, and it may change at any time.
543#[derive(Clone, Debug)]
544pub struct HexError(HexErrorInner);
545
546#[derive(Clone, Debug)]
547enum HexErrorInner {
548    InvalidByte(u8),
549    InvalidLen(usize),
550}
551
552impl fmt::Display for HexError {
553    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
554        match self.0 {
555            HexErrorInner::InvalidByte(byte) => {
556                if byte < 128 {
557                    write!(f, "invalid hex character: {:?}", byte as char)
558                } else {
559                    write!(f, "invalid hex character: 0x{:x}", byte)
560                }
561            }
562            HexErrorInner::InvalidLen(len) => {
563                write!(f, "expected 64 hex bytes, received {}", len)
564            }
565        }
566    }
567}
568
569#[cfg(feature = "std")]
570impl std::error::Error for HexError {}
571
572type Output = hasher::Output<Platform>;
573
574impl Clone for Output {
575    fn clone(&self) -> Self {
576        hasher::Output {
577            block: self.block,
578            input_chaining_value: self.input_chaining_value,
579            block_len: self.block_len,
580            counter: self.counter,
581            flags: self.flags,
582            platform: self.platform,
583        }
584    }
585}
586
587impl Output {
588    fn root_hash(&self) -> Hash {
589        debug_assert_eq!(self.counter, 0);
590        Hash(self.root_bytes())
591    }
592
593    fn root_output_block(&self) -> [u8; 2 * OUT_LEN] {
594        self.platform.compress_xof(&self.input_chaining_value, &self.block, self.block_len, self.counter, self.flags | ROOT)
595    }
596}
597
598#[cfg(feature = "zeroize")]
599impl Zeroize for Output {
600    fn zeroize(&mut self) {
601        // Destructuring to trigger compile error as a reminder to update this impl.
602        let Self { input_chaining_value, block, block_len, counter, flags, platform: _ } = self;
603
604        input_chaining_value.zeroize();
605        block.zeroize();
606        block_len.zeroize();
607        counter.zeroize();
608        flags.zeroize();
609    }
610}
611
612type ChunkState = hasher::ChunkState<Platform>;
613
614impl hasher::Blocks for Platform {
615    #[inline(always)]
616    fn compress_in_place(&self, cv: &mut CVWords, block: &[u8; BLOCK_LEN], block_len: u8, counter: u64, flags: u8) {
617        Platform::compress_in_place(self, cv, block, block_len, counter, flags)
618    }
619
620    #[inline(always)]
621    fn compress_blocks(&self, cv: &mut CVWords, blocks: &[u8], count: usize, counter: u64, flags: u8, flags_start: u8) {
622        Platform::compress_blocks(self, cv, blocks, count, counter, flags, flags_start)
623    }
624}
625
626impl Clone for ChunkState {
627    fn clone(&self) -> Self {
628        hasher::ChunkState {
629            buf: self.buf,
630            cv: self.cv,
631            chunk_counter: self.chunk_counter,
632            buf_len: self.buf_len,
633            blocks_compressed: self.blocks_compressed,
634            flags: self.flags,
635            platform: self.platform,
636        }
637    }
638}
639
640impl ChunkState {
641    // Try to avoid buffering as much as possible, by compressing directly from
642    // the input slice when full blocks are available (src/hasher.rs).
643    #[inline(always)]
644    fn update(&mut self, input: &[u8]) -> &mut Self {
645        self.absorb(input);
646        debug_assert!(self.count() <= CHUNK_LEN);
647        self
648    }
649}
650
651#[cfg(feature = "zeroize")]
652impl Zeroize for ChunkState {
653    fn zeroize(&mut self) {
654        // Destructuring to trigger compile error as a reminder to update this impl.
655        let Self { cv, chunk_counter, buf, buf_len, blocks_compressed, flags, platform: _ } = self;
656
657        cv.zeroize();
658        chunk_counter.zeroize();
659        buf.zeroize();
660        buf_len.zeroize();
661        blocks_compressed.zeroize();
662        flags.zeroize();
663    }
664}
665
666// IMPLEMENTATION NOTE
667// ===================
668/// Undocumented and unstable, for benchmarks only.
669#[doc(hidden)]
670#[derive(Clone, Copy)]
671pub enum IncrementCounter {
672    Yes,
673    No,
674}
675
676impl IncrementCounter {
677    #[inline]
678    fn yes(&self) -> bool {
679        match self {
680            IncrementCounter::Yes => true,
681            IncrementCounter::No => false,
682        }
683    }
684}
685
686/// The lanes of the one pass that hashes `whole` whole chunks with a
687/// partial one of `partial` bytes after them, where the pass costs less
688/// than the partial chunk's blocks after the whole ones: three whole
689/// chunks in four lanes (SSE4.1 and AVX2), and in eight (AVX2) six or
690/// seven, or five with a partial chunk of six blocks or more (with fewer,
691/// an i7-12700K's efficiency core ran the eight lanes up to 7% slower; a
692/// pass of eight lanes costs 1.6 times one of four on its performance
693/// core). AVX-512 keeps its own widths (unmeasured).
694#[cfg(target_arch = "x86_64")]
695#[inline]
696fn spare_lane(platform: Platform, whole: usize, partial: usize) -> Option<usize> {
697    match (platform, whole) {
698        (Platform::SSE41 | Platform::AVX2, 3) => Some(4),
699        (Platform::AVX2, 6..=7) => Some(8),
700        (Platform::AVX2, 5) if partial > 5 * BLOCK_LEN => Some(8),
701        _ => None,
702    }
703}
704
705// Use SIMD parallelism to hash up to MAX_SIMD_DEGREE chunks at the same time
706// on a single thread. Write out the chunk chaining values and return the
707// number of chunks hashed. These chunks are never the root and never empty;
708// those cases use a different codepath.
709fn compress_chunks_parallel(input: &[u8], key: &CVWords, chunk_counter: u64, flags: u8, platform: Platform, out: &mut [u8]) -> usize {
710    debug_assert!(!input.is_empty(), "empty chunks below the root");
711    debug_assert!(input.len() <= MAX_SIMD_DEGREE * CHUNK_LEN);
712
713    let mut chunks_exact = input.chunks_exact(CHUNK_LEN);
714    let mut chunks_array = ArrayVec::<&[u8; CHUNK_LEN], MAX_SIMD_DEGREE>::new();
715    for chunk in &mut chunks_exact {
716        chunks_array.push(chunk.try_into().unwrap());
717    }
718    // A whole chunk and a partial one, on AVX2 or AVX-512: their first
719    // blocks side by side (pair.rs).
720    if pair::takes(platform, input.len()) {
721        out[..2 * OUT_LEN].copy_from_slice(&pair::parent(input, key, chunk_counter, flags, platform));
722        return 2;
723    }
724    // Whole chunks that leave a lane spare, and a partial one: one pass,
725    // the partial chunk in the spare lane.
726    #[cfg(target_arch = "x86_64")]
727    if let (false, Some(lanes)) = (chunks_exact.remainder().is_empty(), spare_lane(platform, chunks_array.len(), chunks_exact.remainder().len())) {
728        let (whole, partial) = (&chunks_array[..], chunks_exact.remainder());
729        // Sound: spare_lane admits each width only on a platform whose CPU
730        // has its instructions.
731        if lanes == 4 {
732            unsafe { rust_sse41::hash_chunks_with_partial(whole, partial, key, chunk_counter, flags, out) };
733        } else {
734            unsafe { rust_avx2::hash_chunks_with_partial(whole, partial, key, chunk_counter, flags, out) };
735        }
736        return whole.len() + 1;
737    }
738    // Whole chunks and a partial one, on the NEON hybrids: where a q kernel
739    // covers the count, the partial chunk runs on the scalar units beside
740    // the whole chunks rather than after them.
741    #[cfg(blake3_neon)]
742    let hybrids = matches!(platform, Platform::NEON);
743    #[cfg(blake3_sme2)]
744    let hybrids = hybrids || matches!(platform, Platform::SME2);
745    #[cfg(blake3_neon)]
746    if !chunks_exact.remainder().is_empty()
747        && hybrids
748        && neon_hybrid::partial_pays(chunks_array.len(), chunks_exact.remainder().len())
749        && neon_hybrid::sha3_detected()
750    {
751        // Safe: the kernel exists for this count and the CPU has SHA-3.
752        unsafe {
753            neon_hybrid::hash_chunks_with_partial(&chunks_array, chunks_exact.remainder(), key, chunk_counter, flags, CHUNK_START, CHUNK_END, out);
754        }
755        return chunks_array.len() + 1;
756    }
757    platform.hash_many(&chunks_array, key, chunk_counter, IncrementCounter::Yes, flags, CHUNK_START, CHUNK_END, out);
758
759    // Hash the remaining partial chunk, if there is one. Note that the empty
760    // chunk (meaning the empty message) is a different codepath.
761    let chunks_so_far = chunks_array.len();
762    if !chunks_exact.remainder().is_empty() {
763        let counter = chunk_counter + chunks_so_far as u64;
764        let mut chunk_state = ChunkState::new(key, counter, flags, platform);
765        chunk_state.update(chunks_exact.remainder());
766        *<&mut [u8; OUT_LEN]>::try_from(&mut out[chunks_so_far * OUT_LEN..][..OUT_LEN]).unwrap() = chunk_state.output().chaining_value();
767        chunks_so_far + 1
768    } else {
769        chunks_so_far
770    }
771}
772
773// Use SIMD parallelism to hash up to MAX_SIMD_DEGREE parents at the same time
774// on a single thread. Write out the parent chaining values and return the
775// number of parents hashed. (If there's an odd input chaining value left over,
776// return it as an additional output.) These parents are never the root and
777// never empty; those cases use a different codepath.
778fn compress_parents_parallel(child_chaining_values: &[u8], key: &CVWords, flags: u8, platform: Platform, out: &mut [u8]) -> usize {
779    debug_assert_eq!(child_chaining_values.len() % OUT_LEN, 0, "wacky hash bytes");
780    let num_children = child_chaining_values.len() / OUT_LEN;
781    debug_assert!(num_children >= 2, "not enough children");
782    debug_assert!(num_children <= 2 * MAX_SIMD_DEGREE_OR_2, "too many");
783
784    let mut parents_exact = child_chaining_values.chunks_exact(BLOCK_LEN);
785    // Use MAX_SIMD_DEGREE_OR_2 rather than MAX_SIMD_DEGREE here: the walk
786    // (src/tree.rs) returns at least 2 values.
787    let mut parents_array = ArrayVec::<&[u8; BLOCK_LEN], MAX_SIMD_DEGREE_OR_2>::new();
788    for parent in &mut parents_exact {
789        parents_array.push(parent.try_into().unwrap());
790    }
791    platform.hash_many(
792        &parents_array,
793        key,
794        0, // Parents always use counter 0.
795        IncrementCounter::No,
796        flags | PARENT,
797        0, // Parents have no start flags.
798        0, // Parents have no end flags.
799        out,
800    );
801
802    // If there's an odd child left over, it becomes an output.
803    let parents_so_far = parents_array.len();
804    if !parents_exact.remainder().is_empty() {
805        out[parents_so_far * OUT_LEN..][..OUT_LEN].copy_from_slice(parents_exact.remainder());
806        parents_so_far + 1
807    } else {
808        parents_so_far
809    }
810}
811
812// Hash a subtree with the walk (src/tree.rs, `children`), condensing its
813// chaining values down to a single parent node. Don't compress that
814// last parent node, however. Instead, return its message bytes (the
815// concatenated chaining values of its children). This is necessary when the
816// first call to update() supplies a complete subtree, because the topmost
817// parent node of that subtree could end up being the root. It's also necessary
818// for extended output in the general case.
819//
820// This function is not used on inputs of 1 chunk or less. That's a
821// different codepath. Its arrays live in tree::root_children, out of line.
822#[inline]
823fn compress_subtree_to_parent_node(input: &[u8], ahead: usize, key: &CVWords, chunk_counter: u64, flags: u8, platform: Platform) -> [u8; BLOCK_LEN] {
824    debug_assert!(input.len() > CHUNK_LEN);
825    let kernels = tree::PlatformKernels { key, flags, platform };
826    let [left, right] = tree::root_children(&kernels, input, ahead, chunk_counter);
827    let mut block = [0u8; BLOCK_LEN];
828    block[..OUT_LEN].copy_from_slice(&left);
829    block[OUT_LEN..].copy_from_slice(&right);
830    block
831}
832
833// The root hash of an input of one chunk or less, in one kernel call. The
834// whole blocks are read in place, the final one too when it is full; a
835// short final block (and the empty block for the empty input) is copied
836// into a zero-padded buffer, which is the copy ChunkState::update() makes
837// too. The scalar kernel runs on every AArch64 core, so this path needs no
838// platform check.
839#[cfg(blake3_neon)]
840#[inline]
841fn hash_one_chunk_root(input: &[u8], key: &CVWords, flags: u8) -> Hash {
842    debug_assert!(input.len() <= CHUNK_LEN);
843    let blocks = cmp::max(1, input.len().div_ceil(BLOCK_LEN));
844    let whole = (blocks - 1) * BLOCK_LEN;
845    let tail = &input[whole..];
846    /// The padded last block, 64-byte aligned as hasher::Output's is
847    /// (src/hasher.rs explains).
848    #[repr(align(64))]
849    struct Aligned64([u8; BLOCK_LEN]);
850    let padded;
851    let last: &[u8; BLOCK_LEN] = match tail.try_into() {
852        Ok(full) => full,
853        Err(_) => {
854            let mut block = Aligned64([0; BLOCK_LEN]);
855            block.0[..tail.len()].copy_from_slice(tail);
856            padded = block;
857            &padded.0
858        }
859    };
860    let mut out = [0u8; OUT_LEN];
861    // Safe: `input` holds `whole` bytes before `tail`, and blocks is 1..=16.
862    unsafe {
863        neon_hybrid::hash_chunk(input.as_ptr(), blocks, last, tail.len() as u8, key, 0, flags, CHUNK_START, CHUNK_END | ROOT, &mut out);
864    }
865    Hash(out)
866}
867
868// Hash a whole subtree at its chunk counter (or the whole input at zero).
869// Unlike the wider helpers above, this also handles one chunk or less.
870// The pool's pieces (lanes.rs) use it; the one-shot calls go through
871// tree::hash.
872#[cfg(feature = "std")]
873#[inline]
874fn hash_all_at_once(input: &[u8], key: &CVWords, chunk_counter: u64, flags: u8, platform: Platform) -> Output {
875    // The input is a complete subtree at chunk_counter, or the whole
876    // input (including empty) at counter zero. Its byte offset fits u64.
877    debug_assert!(chunk_counter <= u64::MAX / CHUNK_LEN as u64);
878    debug_assert!(chunk_counter == 0 || (!input.is_empty() && input.len() as u64 <= max_subtree_len(chunk_counter * CHUNK_LEN as u64).unwrap()));
879
880    // If the whole subtree is one chunk, hash it directly with a ChunkState.
881    if input.len() <= CHUNK_LEN {
882        return ChunkState::new(key, chunk_counter, flags, platform).update(input).output();
883    }
884
885    // Otherwise construct an Output object from the parent node returned by
886    // compress_subtree_to_parent_node().
887    hasher::Output {
888        input_chaining_value: *key,
889        block: compress_subtree_to_parent_node(input, 0, key, chunk_counter, flags, platform),
890        block_len: BLOCK_LEN as u8,
891        counter: 0,
892        flags: flags | PARENT,
893        platform,
894    }
895}
896
897/// The hash of `input`, on the calling thread.
898///
899/// ```
900/// # blake3_servil::initialize();
901/// let hash = blake3_servil::hash(b"foo");
902/// # let hash1 = hash;
903///
904/// let hash = blake3_servil::Hasher::new().update(b"foo").finalize();
905/// # let hash2 = hash;
906/// # assert_eq!(hash1, hash2);
907/// ```
908///
909/// Choose it for short inputs, or where your program wants one thread; for
910/// any input in memory, [`hash_multithreaded`] is never slower. For output
911/// sizes other than 32 bytes, see [`Hasher::finalize_xof`] and
912/// [`OutputReader`].
913///
914/// **Speed**, nonstop on an Apple M4 Max: about 50 ns for 64 bytes, 0.7 µs
915/// for 1 KiB, 4 GB/s at 16 KiB, and 6 GB/s from 1 MiB. A call after a pause
916/// or after other work takes longer (its code and data have left the
917/// CPU's caches): 64 bytes then take about 0.2 to 0.6 µs. On Apple M4 and
918/// later, threads that hash inputs of 16 KiB or more at the same moment
919/// share one accelerator: one runs at full speed and the others at about
920/// two thirds of it.
921///
922/// The first hash in a process first runs a self-test (see the crate's
923/// documentation), under 0.2 ms; [`initialize`] moves it to start-up.
924// Inlined into its caller: its one call, out of line, sat apart from
925// hash_serial, one more code line to fetch from DRAM in a call after a pause
926// (i7-12700K, after idling, 64 B: -16.5%, 8 fresh layouts a side).
927#[inline]
928pub fn hash(input: &[u8]) -> Hash {
929    hash_serial(input, IV, 0)
930}
931
932/// The hash of `input`, using other CPU cores where that is faster: the same
933/// [`Hash`](struct@Hash) as [`hash`], never slower.
934///
935/// ```
936/// # blake3_servil::initialize_multithreaded(None);
937/// let hash = blake3_servil::hash_multithreaded(&[0u8; 1 << 20]);
938/// assert_eq!(hash, blake3_servil::hash(&[0u8; 1 << 20]));
939/// ```
940///
941/// The default choice for one message in memory.
942///
943/// **Speed**, on an Apple M4 Max (16 cores): below 512 KiB it hashes on the
944/// calling thread, at [`hash`]'s speed; from 512 KiB it uses the other cores
945/// too: about 12 GB/s at 1 MiB, 20 GB/s at 4 MiB, and 25 GB/s from 16 MiB,
946/// 4 to 6 times [`hash`]. The extra threads wait asleep between calls and
947/// use no CPU then.
948///
949/// **Several callers at once**: calls from several threads of one program
950/// share the cores in turn, each getting a fair part; a call that finds the
951/// cores all busy hashes on its own thread, at [`hash`]'s speed.
952///
953/// **CPUs with performance and efficiency cores** (Intel's since Alder
954/// Lake): a multithreaded call or stream uses every core, and afterwards
955/// the OS sometimes leaves the calling thread on an efficiency core for a
956/// while, where single-threaded hashing runs at about half speed (AVX2's
957/// 256-bit operations run as two halves there). Measured on an i7-12700K
958/// under Linux 7.0: beside nonstop multithreaded streams, 7% of 16 KiB
959/// single-threaded hashes ran partly on an efficiency core, 2.2 times
960/// slower, about 6% on their average. A program that alternates the two
961/// and needs its single-threaded speed steady can keep that thread on the
962/// performance cores (`sched_setaffinity` on Linux).
963///
964/// The program calls [`initialize_multithreaded`] first; a call before it
965/// panics.
966#[cfg(feature = "std")]
967pub fn hash_multithreaded(input: &[u8]) -> Hash {
968    lanes::require();
969    lanes::hash(input)
970}
971
972/// Run the startup self-test and detect the CPU: every program calls this
973/// (or [`initialize_multithreaded`]) once, before any other call of this
974/// crate, and a call before it panics. Under 0.2 ms, once per process
975/// (see the crate's documentation); later calls return at once.
976///
977/// ```
978/// blake3_servil::initialize();
979/// let hash = blake3_servil::hash(b"foo");
980/// # assert_eq!(hash, blake3_servil::Hasher::new().update(b"foo").finalize());
981/// ```
982pub fn initialize() {
983    self_test::ensure();
984    platform::Platform::detect_unchecked().record();
985}
986
987/// [`initialize`], and start the threads that the multithreaded calls and
988/// [`stream`] use: every program that makes such calls calls this once,
989/// before them, in place of `initialize`. It starts `threads - 1` workers,
990/// and each multithreaded call hashes on its calling thread and the
991/// workers (calls made at once share the workers), and on CPUs with SME2
992/// (Apple M4) the SME2 thread too; `None` means one thread
993/// a CPU (`std::thread::available_parallelism`, which follows the CPU
994/// affinity the program runs under). With 1, calls hash on their calling
995/// thread alone: no workers start, nor the SME2 thread. Otherwise it
996/// starts the first worker and returns; the first worker starts the others
997/// (each 20-30 us on Linux x86-64), and calls run on the workers started
998/// so far. The
999/// threads wait asleep whenever no call has work for them (their memory:
1000/// see [Memory](crate#memory)). Later calls return at once, and must ask
1001/// for the same number: another `Some` panics. A panic on a worker thread
1002/// (a bug in this crate) ends the process, its message printed, rather
1003/// than leaving the call that waits for that worker's piece waiting
1004/// forever.
1005///
1006/// ```
1007/// blake3_servil::initialize_multithreaded(None);
1008/// let hash = blake3_servil::hash_multithreaded(&[0u8; 1 << 20]);
1009/// assert_eq!(hash, blake3_servil::hash(&[0u8; 1 << 20]));
1010/// ```
1011#[cfg(feature = "std")]
1012pub fn initialize_multithreaded(threads: Option<core::num::NonZeroUsize>) {
1013    static STARTED: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
1014    let cpus = || std::thread::available_parallelism().map_or(1, |n| n.get());
1015    let started = *STARTED.get_or_init(|| {
1016        let threads = threads.map_or_else(cpus, |n| n.get());
1017        initialize();
1018        lanes::initialize(threads);
1019        threads
1020    });
1021    if let Some(threads) = threads {
1022        assert_eq!(
1023            started,
1024            threads.get(),
1025            "blake3-servil: the multithreaded calls were started with {started} threads; initialize_multithreaded cannot change that to {threads}"
1026        );
1027    }
1028}
1029
1030/// Whether every worker of the multithreaded calls' pool is parked (false
1031/// before [`initialize_multithreaded`]). Undocumented and unstable, for
1032/// tests only: a test that needs the pool idle waits for this, not for a
1033/// sleep that a loaded machine could outlast.
1034#[cfg(feature = "std")]
1035#[doc(hidden)]
1036pub fn __all_workers_parked() -> bool {
1037    lanes::all_workers_parked()
1038}
1039
1040/// An alias to distinguish [`hash_derive_key_context`] outputs from other keys.
1041pub type ContextKey = [u8; KEY_LEN];
1042
1043/// Hash a key-derivation context string and return a [`ContextKey`].
1044///
1045/// This has the same security requirement as key derivation. **The context
1046/// string should be hardcoded, globally unique, and application-specific.**
1047///
1048/// Its one use is [`Mode::DeriveKeyMaterial`]: a program that derives many
1049/// keys from one context hashes the context once.
1050///
1051/// # Example
1052///
1053/// ```
1054/// # blake3_servil::initialize();
1055/// use blake3_servil::Mode;
1056///
1057/// let context_key = blake3_servil::hash_derive_key_context("foo");
1058/// let derived = blake3_servil::hash_with(Mode::DeriveKeyMaterial(&context_key), b"bar");
1059/// assert_eq!(derived, blake3_servil::hash_with(Mode::DeriveKey("foo"), b"bar"));
1060/// ```
1061pub fn hash_derive_key_context(context: &str) -> ContextKey {
1062    hash_serial(context.as_bytes(), IV, DERIVE_KEY_CONTEXT).0
1063}
1064
1065/// The most bytes a subtree starting at byte `input_offset` of a message
1066/// can hold: `None` at offset zero (the whole message), else the largest
1067/// power-of-two multiple of a chunk the offset is aligned to. Requires a
1068/// whole-chunk offset.
1069#[inline(always)]
1070pub(crate) fn max_subtree_len(input_offset: u64) -> Option<u64> {
1071    if input_offset == 0 {
1072        return None;
1073    }
1074    assert_eq!(input_offset % CHUNK_LEN as u64, 0);
1075    let counter = input_offset / CHUNK_LEN as u64;
1076    let max_chunks = 1 << counter.trailing_zeros();
1077    Some(max_chunks * CHUNK_LEN as u64)
1078}
1079
1080/// Which of BLAKE3's three functions a call computes: the plain hash
1081/// ([`hash`]), the keyed hash, or key derivation. Every call that takes a mode runs each one at the same
1082/// speed, but for `DeriveKey`, which first hashes its context string (once
1083/// per call; [`DeriveKeyMaterial`](Mode::DeriveKeyMaterial) takes it hashed
1084/// once for many calls).
1085#[derive(Clone, Copy)]
1086pub enum Mode<'a> {
1087    /// The default hash function, as [`hash`].
1088    Hash,
1089    /// The keyed hash function with this key.
1090    Keyed(&'a [u8; KEY_LEN]),
1091    /// The key derivation function with this context string; the input
1092    /// is the key material.
1093    DeriveKey(&'a str),
1094    /// The key derivation function with its context string already hashed
1095    /// ([`hash_derive_key_context`]); the input is the key material.
1096    DeriveKeyMaterial(&'a ContextKey),
1097}
1098
1099impl Mode<'_> {
1100    /// The key words and flags this mode hashes with.
1101    fn key_and_flags(self) -> (CVWords, u8) {
1102        match self {
1103            Mode::Hash => (*IV, 0),
1104            Mode::Keyed(key) => (platform::words_from_le_bytes_32(key), KEYED_HASH),
1105            Mode::DeriveKey(context) => (platform::words_from_le_bytes_32(&hash_derive_key_context(context)), DERIVE_KEY_MATERIAL),
1106            Mode::DeriveKeyMaterial(context_key) => (platform::words_from_le_bytes_32(context_key), DERIVE_KEY_MATERIAL),
1107        }
1108    }
1109}
1110
1111/// [`hash`] in any [`Mode`]: the plain hash, the keyed hash, or key
1112/// derivation, at [`hash`]'s speed.
1113///
1114/// ```
1115/// # blake3_servil::initialize();
1116/// use blake3_servil::Mode;
1117/// let key = [7u8; 32];
1118/// assert_eq!(blake3_servil::hash_with(Mode::Keyed(&key), b"foo").as_bytes().len(), 32);
1119/// ```
1120pub fn hash_with(mode: Mode, input: &[u8]) -> Hash {
1121    let (key, flags) = mode.key_and_flags();
1122    hash_serial(input, &key, flags)
1123}
1124
1125/// [`hash_multithreaded`] in any [`Mode`], at its speed.
1126///
1127/// ```
1128/// # blake3_servil::initialize_multithreaded(None);
1129/// use blake3_servil::Mode;
1130/// let key = [7u8; 32];
1131/// let input = vec![1u8; 1 << 20];
1132/// assert_eq!(blake3_servil::hash_multithreaded_with(Mode::Keyed(&key), &input), blake3_servil::hash_with(Mode::Keyed(&key), &input));
1133/// ```
1134#[cfg(feature = "std")]
1135pub fn hash_multithreaded_with(mode: Mode, input: &[u8]) -> Hash {
1136    lanes::require();
1137    let (key, flags) = mode.key_and_flags();
1138    lanes::hash_with_key(input, &key, flags)
1139}
1140
1141/// The whole input on the calling thread, in the given mode: the one-chunk
1142/// kernel call up to CHUNK_LEN, the subtree walk above. hash(),
1143/// hash() in its modes and hash_multithreaded()'s short path all come
1144/// through here.
1145#[inline]
1146fn hash_serial(input: &[u8], key: &CVWords, flags: u8) -> Hash {
1147    hash_serial_from(Platform::detect(), input, key, flags)
1148}
1149
1150/// [`hash_serial`] from `platform`: the startup self-test's way in, which
1151/// has not run `Platform::detect`'s check (it is that check).
1152#[inline]
1153fn hash_serial_from(platform: Platform, input: &[u8], key: &CVWords, flags: u8) -> Hash {
1154    let turn = platform::Sme2Turn::take(platform, input.len() >= SME2_SIZED_LEN);
1155    // One comparison on the path of a chunk or less: everything else is
1156    // out of line, so that path's code stays as small as it was (a call
1157    // after other work fetches every line of it from DRAM).
1158    #[cfg(all(blake3_neon, feature = "std"))]
1159    if (CHUNK_LEN + 1..PREFETCH_BELOW).contains(&input.len()) {
1160        prefetch_after_pause(input.len(), turn.platform(), false);
1161    }
1162    hash_serial_on(input, key, flags, turn.platform())
1163}
1164
1165/// Below this length a one-shot call that follows a pause prefetches its
1166/// kernels' code: after other work the call then fetches it from DRAM in
1167/// parallel, not one miss at a time (M4 Max, after other work: 4 KiB
1168/// x0.61, 8 KiB x0.51, 16 KiB x0.66; 32 KiB and up level, the hashing's
1169/// own time dwarfing it; jobs 971-975). The streaming paths (Hasher,
1170/// batches, the streams' tasks) run back to back with their code near.
1171/// A cold call of 2-8 KiB spends about a third of its time on its code
1172/// (10-24 KB of kernels and glue); from 3 KiB what remains is the kernels
1173/// starting before their lines arrive. Tried and set aside: prefetching
1174/// for a chunk or less (2-10% gained, less than the pause check costs);
1175/// prefetching the 16 KiB of Rust around the kernels too (every call
1176/// 400-500 ns slower: prefetches beyond some number in flight are
1177/// dropped); a rolled four-lane NEON path for calls after a pause (1.3 KB,
1178/// 1.2-1.5x slower: a four-lane NEON BLAKE3 is bound by its chains'
1179/// latency, where the hybrids' integer lanes fill the idle issue slots).
1180#[cfg(all(blake3_neon, feature = "std"))]
1181const PREFETCH_BELOW: usize = 64 * 1024;
1182
1183/// After a pause (code_may_be_cold), prefetch the kernels hashing `len`
1184/// bytes runs: a one-shot call's (prefetch_kernels), or with `fresh_hasher`
1185/// a fresh Hasher's first update's (prefetch_update_kernels).
1186#[cfg(all(blake3_neon, feature = "std"))]
1187// Cold for layout: the path of a chunk or less falls through past its
1188// call, on the lines it had before the call existed.
1189#[cold]
1190#[inline(never)]
1191fn prefetch_after_pause(len: usize, platform: Platform, fresh_hasher: bool) {
1192    if code_may_be_cold() {
1193        if fresh_hasher {
1194            prefetch_update_kernels(len, platform);
1195        } else {
1196            prefetch_kernels(len, platform);
1197        }
1198    }
1199}
1200
1201/// Whether this thread's last call in the prefetching range was over
1202/// 100 us ago (or never). Calls back to back find their code near, where
1203/// the prefetch would cost them 2-4% (jobs 972-975); one that follows a
1204/// pause is the one other work may have taken the code from.
1205#[cfg(all(blake3_neon, feature = "std"))]
1206#[inline]
1207fn code_may_be_cold() -> bool {
1208    std::thread_local! {
1209        static LAST_CALL: core::cell::Cell<u64> = const { core::cell::Cell::new(0) };
1210    }
1211    let now = platform::counter();
1212    let last = LAST_CALL.with(|last| last.replace(now));
1213    now.wrapping_sub(last) > platform::ticks_in_100_us()
1214}
1215
1216/// Batches of one-block messages up to this many prefetch their code after
1217/// a pause: past it the hashing's own time dwarfs a cold kernel's.
1218#[cfg(all(blake3_neon, feature = "std"))]
1219const PREFETCH_BATCH_BELOW: usize = 64;
1220
1221/// Batches of 1 to this many one-block messages run on the pair kernel
1222/// alone after a pause (neon_hybrid::hash_pairs): its code (2.9 KB) is a
1223/// fraction of the plans' for 3 to 16 (up to 17 KB) and less than the one
1224/// message's kernel (3.9 KB), and after a pause the code comes from memory
1225/// (Mac jobs 1320-1337: 12 and 16 run faster after idling and slower after
1226/// other work this way).
1227#[cfg(all(blake3_neon, feature = "std"))]
1228const PAIRS_AFTER_PAUSE_UPTO: usize = 8;
1229
1230/// After a pause (code_may_be_cold), a batch of `count` one-block
1231/// messages: 1 to PAIRS_AFTER_PAUSE_UPTO hashed here on the pair kernel
1232/// (true: done); otherwise its kernels' code prefetched (false: hash it as
1233/// usual), SME2's message kernel where it takes the batch, else the
1234/// hybrids' parent plans.
1235#[cfg(all(blake3_neon, feature = "std"))]
1236#[cold]
1237#[inline(never)]
1238fn batch_after_pause(input: &[u8], message_len: usize, key: &CVWords, flags: u8, out: &mut [[u8; OUT_LEN]], platform: Platform) -> bool {
1239    if !code_may_be_cold() {
1240        return false;
1241    }
1242    let count = out.len();
1243    #[cfg(blake3_sme2)]
1244    if matches!(platform, Platform::SME2) && count >= many::ONE_BLOCK_PAD_MIN {
1245        sme2::prefetch_code();
1246        return false;
1247    }
1248    let _ = platform;
1249    if !neon_hybrid::sha3_detected() {
1250        return false;
1251    }
1252    if message_len == 0 || !(1..=PAIRS_AFTER_PAUSE_UPTO).contains(&count) {
1253        neon_hybrid::prefetch_message_code(count);
1254        return false;
1255    }
1256    many::assert_slots(input, message_len, count);
1257    neon_hybrid::prefetch_pair_code();
1258    let mut table: [&[u8; BLOCK_LEN]; PAIRS_AFTER_PAUSE_UPTO] = [&[0; BLOCK_LEN]; PAIRS_AFTER_PAUSE_UPTO];
1259    for (slot, message) in table.iter_mut().zip(input.chunks_exact(BLOCK_LEN)) {
1260        *slot = message.try_into().unwrap();
1261    }
1262    // Sound: the SHA-3 extension is here (above).
1263    unsafe { neon_hybrid::hash_pairs(&table[..count], key, flags, CHUNK_START, CHUNK_END | ROOT, message_len, out.as_flattened_mut()) };
1264    true
1265}
1266
1267/// Prefetch the code of the kernels hashing `len` bytes on `platform`
1268/// runs: SME2's from 16 chunks, else the hybrids', chunks to root.
1269#[cfg(all(blake3_neon, feature = "std"))]
1270fn prefetch_kernels(len: usize, platform: Platform) {
1271    #[cfg(blake3_sme2)]
1272    if matches!(platform, Platform::SME2) && len >= SME2_SIZED_LEN {
1273        sme2::prefetch_code();
1274        // Below the flat walk, sixteen chunks' values merge on the hybrids.
1275        if !sme2::flat_takes(len) {
1276            neon_hybrid::prefetch_parent_code(16);
1277        }
1278        return;
1279    }
1280    // Below 16 chunks the SME2 platform runs the hybrids too.
1281    #[cfg(blake3_sme2)]
1282    let hybrids = matches!(platform, Platform::NEON | Platform::SME2);
1283    #[cfg(not(blake3_sme2))]
1284    let hybrids = matches!(platform, Platform::NEON);
1285    if hybrids && neon_hybrid::sha3_detected() {
1286        let whole = (len / CHUNK_LEN).min(16);
1287        neon_hybrid::prefetch_tree_code(whole, if whole == 16 { 0 } else { len % CHUNK_LEN });
1288    }
1289}
1290
1291/// Prefetch the code a fresh Hasher's update of `len` bytes runs: the
1292/// subtrees its loop cuts (hasher::subtree_len from counter 0, up to the last
1293/// chunk, which waits in the chunk state), each one's kernels.
1294#[cfg(all(blake3_neon, feature = "std"))]
1295fn prefetch_update_kernels(len: usize, platform: Platform) {
1296    if !neon_hybrid::sha3_detected() {
1297        return;
1298    }
1299    let (mut counter, mut left) = (0u64, len);
1300    while left > CHUNK_LEN {
1301        let subtree = hasher::subtree_len(counter, left);
1302        let chunks = subtree / CHUNK_LEN;
1303        #[cfg(blake3_sme2)]
1304        if matches!(platform, Platform::SME2) && chunks >= 16 {
1305            sme2::prefetch_code();
1306            if !sme2::flat_takes(subtree) {
1307                neon_hybrid::prefetch_parent_code(16);
1308            }
1309            counter += chunks as u64;
1310            left -= subtree;
1311            continue;
1312        }
1313        neon_hybrid::prefetch_tree_code(chunks.min(16), 0);
1314        counter += chunks as u64;
1315        left -= subtree;
1316    }
1317    let _ = platform;
1318}
1319
1320/// The smallest input the SME2 kernels take part in: one group of sixteen
1321/// chunks. Below it the SME2 platform runs the NEON hybrids.
1322pub(crate) const SME2_SIZED_LEN: usize = 16 * CHUNK_LEN;
1323
1324/// The fewest messages a batch has when the SME2 kernels take part: one
1325/// group of sixteen messages.
1326pub(crate) const SME2_SIZED_BATCH: usize = 16;
1327
1328/// [`hash_serial`] with the tree's kernels chosen by the caller (a pool
1329/// piece runs the NEON hybrids); one chunk or less runs the scalar kernel
1330/// on every platform.
1331#[inline]
1332fn hash_serial_on(input: &[u8], key: &CVWords, flags: u8, platform: Platform) -> Hash {
1333    Hash(tree::hash(&tree::PlatformKernels { key, flags, platform }, input))
1334}
1335
1336/// The hashes of many messages of one length, laid out in one buffer, on
1337/// the calling thread: `out[i]` becomes the [`hash`] of message `i`.
1338///
1339/// Message `i` starts at byte `i * stride` of `input`, where `stride` is
1340/// `message_len` rounded up to a multiple of 64 (64 for empty messages), so
1341/// messages whose length is a multiple of 64 sit back to back. `input`
1342/// holds exactly `out.len()` strides, and the bytes between a message's end
1343/// and the next stride are zero (debug builds check; another byte there
1344/// changes that message's hash). This is the shape of a Merkle tree's
1345/// layer: leaves of one size, or nodes of two 32-byte children
1346/// (`message_len` 64).
1347///
1348/// ```
1349/// # blake3_servil::initialize();
1350/// let leaves = vec![7u8; 1000 * 256];
1351/// let mut hashes = vec![[0u8; 32]; 1000];
1352/// blake3_servil::hash_many(&leaves, 256, &mut hashes);
1353/// assert_eq!(hashes[3], *blake3_servil::hash(&leaves[3 * 256..4 * 256]).as_bytes());
1354///
1355/// // 100-byte messages sit 128 bytes apart, zero between them.
1356/// let mut records = vec![0u8; 10 * 128];
1357/// for (i, record) in records.chunks_mut(128).enumerate() {
1358///     record[..100].fill(i as u8 + 1);
1359/// }
1360/// let mut digests = vec![[0u8; 32]; 10];
1361/// blake3_servil::hash_many(&records, 100, &mut digests);
1362/// assert_eq!(digests[9], *blake3_servil::hash(&[10u8; 100]).as_bytes());
1363/// ```
1364///
1365/// **Speed**: short messages hash several at a time, so a batch beats a
1366/// loop of [`hash`]: on an Apple M4 Max, 64-byte messages take about 10 to
1367/// 20 ns each in batches of 16 or more, against about 50 for one [`hash`]
1368/// each. Messages longer than 15 KiB cost what [`hash`] costs. For the
1369/// same hashes over several cores, see [`hash_many_multithreaded`].
1370pub fn hash_many(input: &[u8], message_len: usize, out: &mut [[u8; OUT_LEN]]) {
1371    hash_many_serial(input, message_len, IV, 0, out);
1372}
1373
1374/// [`hash_many`] in the mode of `key` and `flags`, on the calling thread.
1375#[inline]
1376pub(crate) fn hash_many_serial(input: &[u8], message_len: usize, key: &CVWords, flags: u8, out: &mut [[u8; OUT_LEN]]) {
1377    hash_many_serial_from(Platform::detect(), input, message_len, key, flags, out);
1378}
1379
1380/// [`hash_many_serial`] from `platform` (the self-test's way in, as
1381/// [`hash_serial_from`]).
1382#[inline]
1383fn hash_many_serial_from(platform: Platform, input: &[u8], message_len: usize, key: &CVWords, flags: u8, out: &mut [[u8; OUT_LEN]]) {
1384    let turn = platform::Sme2Turn::take(platform, many::sme2_sized(message_len, out.len()));
1385    // A small batch of one-block messages after a pause fetches its kernels'
1386    // code in parallel (as hash_serial does): its time is mostly that code.
1387    #[cfg(all(blake3_neon, feature = "std"))]
1388    if message_len <= BLOCK_LEN && (1..=PREFETCH_BATCH_BELOW).contains(&out.len()) && batch_after_pause(input, message_len, key, flags, out, turn.platform()) {
1389        return;
1390    }
1391    many::hash_many_on(input, message_len, key, flags, out, turn.platform());
1392}
1393
1394/// [`hash_many`], using other CPU cores where that is faster: the same
1395/// hashes, never slower.
1396///
1397/// ```
1398/// # blake3_servil::initialize_multithreaded(None);
1399/// let leaves = vec![7u8; 4096 * 256];
1400/// let mut hashes = vec![[0u8; 32]; 4096];
1401/// blake3_servil::hash_many_multithreaded(&leaves, 256, &mut hashes);
1402/// assert!(hashes.iter().all(|h| h == blake3_servil::hash(&[7u8; 256]).as_bytes()));
1403/// ```
1404///
1405/// **Speed**: below 512 KiB in all it runs on the calling thread, at
1406/// [`hash_many`]'s speed; larger batches use the other cores too (on an
1407/// Apple M4 Max, 64-byte messages from about 10 down to 3 ns each). It
1408/// shares the cores with other callers as [`hash_multithreaded`] does.
1409#[cfg(feature = "std")]
1410pub fn hash_many_multithreaded(input: &[u8], message_len: usize, out: &mut [[u8; OUT_LEN]]) {
1411    lanes::require();
1412    lanes::hash_many(input, message_len, IV, 0, out);
1413}
1414
1415/// [`hash_many`] in any [`Mode`], at its speed.
1416///
1417/// ```
1418/// # blake3_servil::initialize();
1419/// use blake3_servil::Mode;
1420/// let key = [7u8; 32];
1421/// let nodes = vec![1u8; 20 * 64];
1422/// let mut macs = vec![[0u8; 32]; 20];
1423/// blake3_servil::hash_many_with(Mode::Keyed(&key), &nodes, 64, &mut macs);
1424/// assert_eq!(macs[5], *blake3_servil::hash_with(blake3_servil::Mode::Keyed(&key), &[1u8; 64]).as_bytes());
1425/// ```
1426pub fn hash_many_with(mode: Mode, input: &[u8], message_len: usize, out: &mut [[u8; OUT_LEN]]) {
1427    let (key, flags) = mode.key_and_flags();
1428    hash_many_serial(input, message_len, &key, flags, out);
1429}
1430
1431/// [`hash_many_multithreaded`] in any [`Mode`], at its speed.
1432///
1433/// ```
1434/// # blake3_servil::initialize_multithreaded(None);
1435/// use blake3_servil::Mode;
1436/// let key = [7u8; 32];
1437/// let nodes = vec![1u8; 20000 * 64];
1438/// let mut macs = vec![[0u8; 32]; 20000];
1439/// blake3_servil::hash_many_multithreaded_with(Mode::Keyed(&key), &nodes, 64, &mut macs);
1440/// assert_eq!(macs[5], *blake3_servil::hash_with(blake3_servil::Mode::Keyed(&key), &[1u8; 64]).as_bytes());
1441/// ```
1442#[cfg(feature = "std")]
1443pub fn hash_many_multithreaded_with(mode: Mode, input: &[u8], message_len: usize, out: &mut [[u8; OUT_LEN]]) {
1444    lanes::require();
1445    let (key, flags) = mode.key_and_flags();
1446    lanes::hash_many(input, message_len, &key, flags, out);
1447}
1448
1449/// A message's hash, fed in pieces: [`update`](Hasher::update) with each
1450/// piece, in order, then [`finalize`](Hasher::finalize). The pieces may be
1451/// of any lengths; the hash is the same as [`hash`] of them all at once.
1452///
1453/// A `Hasher` is about 18 KiB (it holds short pieces until it has 16 KiB
1454/// to hash at once); box it where that matters.
1455///
1456/// # Examples
1457///
1458/// ```
1459/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1460/// # blake3_servil::initialize();
1461/// // Hash an input incrementally.
1462/// let mut hasher = blake3_servil::Hasher::new();
1463/// hasher.update(b"foo");
1464/// hasher.update(b"bar");
1465/// hasher.update(b"baz");
1466/// assert_eq!(hasher.finalize(), blake3_servil::hash(b"foobarbaz"));
1467///
1468/// // Extended output. OutputReader also implements Read and Seek.
1469/// # #[cfg(feature = "std")] {
1470/// let mut output = [0; 1000];
1471/// let mut output_reader = hasher.finalize_xof();
1472/// output_reader.fill(&mut output);
1473/// assert_eq!(&output[..32], blake3_servil::hash(b"foobarbaz").as_bytes());
1474/// # }
1475/// # Ok(())
1476/// # }
1477/// ```
1478#[derive(Clone)]
1479pub struct Hasher {
1480    core: HasherCore,
1481    /// The message's bytes from its last 16 KiB boundary, gathered while
1482    /// they arrive in shorter updates: the first `staged`.
1483    staged: usize,
1484    stage: [core::mem::MaybeUninit<u8>; STAGE_LEN],
1485}
1486
1487/// The bytes a Hasher gathers before they hash side by side: 16 chunks,
1488/// the widest kernels' lanes.
1489const STAGE_LEN: usize = 16 * CHUNK_LEN;
1490
1491/// The tree's state behind a [`Hasher`]: its chunk, and the chaining values
1492/// of its finished subtrees.
1493#[derive(Clone)]
1494pub(crate) struct HasherCore {
1495    key: CVWords,
1496    chunk_state: ChunkState,
1497    initial_chunk_counter: u64,
1498    // The stack size is MAX_DEPTH + 1 because we do lazy merging. For example,
1499    // with 7 chunks, we have 3 entries in the stack. Adding an 8th chunk
1500    // requires a 4th entry, rather than merging everything down to 1, because
1501    // we don't know whether more input is coming. This is different from how
1502    // the reference implementation does things.
1503    cv_stack: CvStack,
1504}
1505
1506mod hasher;
1507use hasher::CvStack;
1508
1509/// What the Hasher's kernels take from the library (hasher::Hooks): with
1510/// `pooled`, subtrees of lanes::MIN_SPLIT_LEN and more on the pool; whole
1511/// subtrees on `platform` (an SME2 turn's); `chunk_platform`, the chunk
1512/// state's, otherwise.
1513struct HasherHooks<'a> {
1514    key: &'a CVWords,
1515    flags: u8,
1516    chunk_platform: Platform,
1517    platform: Platform,
1518    pooled: bool,
1519}
1520
1521impl hasher::Hooks for HasherHooks<'_> {
1522    #[inline(always)]
1523    #[allow(unused_variables)]
1524    fn subtree_cv(&self, input: &[u8], ahead: usize, counter: u64) -> Option<CVBytes> {
1525        // After the first input, no subtree is the root: on SME2 the flat
1526        // walk runs it down to its own chaining value, so one value goes
1527        // on the stack and about one merge runs on the core between SME2
1528        // kernels (about 0.2 us of other work between them puts the SME
1529        // unit in its slow state: `sme2`'s documentation).
1530        #[cfg(blake3_sme2)]
1531        if !self.pooled && matches!(self.platform, Platform::SME2) && sme2::flat_takes(input.len()) {
1532            // Safe: the SME2 platform is selected only where the CPU has it.
1533            return Some(unsafe { sme2::compress_subtree_flat_to_cv(input, ahead, self.key, counter, self.flags) });
1534        }
1535        None
1536    }
1537
1538    #[inline(always)]
1539    fn children(&self, input: &[u8], ahead: usize, counter: u64) -> [CVBytes; 2] {
1540        #[cfg(feature = "std")]
1541        let pool_takes = self.pooled && input.len() >= lanes::MIN_SPLIT_LEN;
1542        #[cfg(not(feature = "std"))]
1543        let pool_takes = false;
1544        let pair = if pool_takes {
1545            #[cfg(feature = "std")]
1546            {
1547                lanes::subtree_children(input, self.key, counter, self.flags)
1548            }
1549            #[cfg(not(feature = "std"))]
1550            unreachable!()
1551        } else if self.pooled {
1552            // Pooled, the subtrees below take the lock one at a time, and
1553            // the pool's own never use SME2.
1554            let own = platform::Sme2Turn::take(self.chunk_platform, input.len() >= SME2_SIZED_LEN);
1555            compress_subtree_to_parent_node(input, ahead, self.key, counter, self.flags, own.platform())
1556        } else {
1557            compress_subtree_to_parent_node(input, ahead, self.key, counter, self.flags, self.platform)
1558        };
1559        [pair[..OUT_LEN].try_into().unwrap(), pair[OUT_LEN..].try_into().unwrap()]
1560    }
1561}
1562
1563/// The Hasher's kernels: chunks, nodes, and parents on the chunk state's
1564/// platform, the rest from `hooks`.
1565type HasherKernels<'a> = hasher::Kernels<'a, Platform, HasherHooks<'a>>;
1566
1567/// A Hasher's kernels on its key and chunk state (see HasherHooks).
1568#[inline(always)]
1569fn kernels_on<'a>(key: &'a CVWords, chunk_state: &ChunkState, platform: Platform, pooled: bool) -> HasherKernels<'a> {
1570    hasher::Kernels {
1571        key,
1572        flags: chunk_state.flags,
1573        platform: chunk_state.platform,
1574        hooks: HasherHooks { key, flags: chunk_state.flags, chunk_platform: chunk_state.platform, platform, pooled },
1575    }
1576}
1577
1578impl Hasher {
1579    fn from_core(core: HasherCore) -> Self {
1580        Self { core, staged: 0, stage: [core::mem::MaybeUninit::uninit(); STAGE_LEN] }
1581    }
1582
1583    /// The bytes gathered in the stage.
1584    fn staged_bytes(&self) -> &[u8] {
1585        // Sound: the first `staged` bytes of the stage were written (gather).
1586        unsafe { core::slice::from_raw_parts(self.stage.as_ptr() as *const u8, self.staged) }
1587    }
1588
1589    /// Copy `bytes` into the stage after what it holds.
1590    fn stage(&mut self, bytes: &[u8]) {
1591        // Sound: MaybeUninit<u8> has u8's layout, and the bytes fit (gather).
1592        let room = unsafe { core::slice::from_raw_parts_mut(self.stage.as_mut_ptr().add(self.staged) as *mut u8, bytes.len()) };
1593        room.copy_from_slice(bytes);
1594        self.staged += bytes.len();
1595    }
1596
1597    /// `update`'s gathering: an update of STAGE_LEN or more from a 16 KiB
1598    /// boundary of the message (or an empty stage) goes to the core whole;
1599    /// shorter ones gather in the stage until it reaches the next boundary
1600    /// (but a fresh hasher's first chunk goes to the core),
1601    /// and the stage goes to the core as one update, its chunks side by
1602    /// side in the lanes.
1603    fn gather(&mut self, input: &[u8], pooled: bool) -> &mut Self {
1604        self.gather_part(input, pooled, false);
1605        self
1606    }
1607
1608    /// [`gather`](Hasher::gather), but with `hold`, a stage that fills a
1609    /// whole group (from offset zero) is kept for the caller to hash with
1610    /// others' (`held_group`), and the rest of `input`
1611    /// returned; else nothing is left.
1612    fn gather_part<'a>(&mut self, mut input: &'a [u8], pooled: bool, hold: bool) -> &'a [u8] {
1613        self.core.assert_room(self.count(), input.len());
1614        while !input.is_empty() {
1615            // Whole groups, and a fresh hasher's first chunk (which hashes
1616            // serially either way), skip the stage.
1617            if self.staged == 0 && (input.len() >= STAGE_LEN || self.core.count() + input.len() as u64 <= CHUNK_LEN as u64) {
1618                self.core.update_pooled(input, pooled);
1619                return &[];
1620            }
1621            let at = (self.core.initial_chunk_counter * CHUNK_LEN as u64 + self.count()) % STAGE_LEN as u64;
1622            let to_boundary = STAGE_LEN - at as usize;
1623            let take = cmp::min(to_boundary, input.len());
1624            // The loop's variant: every pass stages at least one byte of
1625            // the input, which is not empty (`at` is below STAGE_LEN).
1626            assert!(take > 0, "the stage took nothing");
1627            self.stage(&input[..take]);
1628            input = &input[take..];
1629            if take < to_boundary {
1630                return &[];
1631            }
1632            if hold && self.held_group().is_some() {
1633                return input;
1634            }
1635            let staged = core::mem::replace(&mut self.staged, 0);
1636            // Sound: the first `staged` bytes were written; the core reads
1637            // them before the stage is written again.
1638            let bytes = unsafe { core::slice::from_raw_parts(self.stage.as_ptr() as *const u8, staged) };
1639            self.core.update_pooled(bytes, pooled);
1640        }
1641        &[]
1642    }
1643
1644    /// A whole group in the stage, from offset zero: its first chunk's
1645    /// counter and its bytes.
1646    #[cfg(feature = "std")]
1647    fn held_group(&self) -> Option<(u64, &[u8; STAGE_LEN])> {
1648        (self.staged == STAGE_LEN && self.core.initial_chunk_counter == 0)
1649            .then(|| (self.core.count() / CHUNK_LEN as u64, self.staged_bytes().try_into().unwrap()))
1650    }
1651
1652    #[cfg(not(feature = "std"))]
1653    fn held_group(&self) -> Option<(u64, &[u8; STAGE_LEN])> {
1654        None
1655    }
1656
1657    /// The held group's subtree, as [`HasherCore::update_with_results`]
1658    /// takes it (its two halves' values at chunk zero, else its own), into
1659    /// the core; the stage empty again.
1660    #[cfg(feature = "std")]
1661    fn take_held(&mut self, result: &[u8; BLOCK_LEN]) {
1662        let staged = core::mem::replace(&mut self.staged, 0);
1663        // Sound: as in gather_part.
1664        let bytes = unsafe { core::slice::from_raw_parts(self.stage.as_ptr() as *const u8, staged) };
1665        self.core.update_with_results(bytes, &mut core::iter::once(result));
1666    }
1667
1668    /// The root's output: the core's, after the stage's bytes.
1669    fn final_output(&self) -> Output {
1670        if self.staged == 0 {
1671            return self.core.final_output();
1672        }
1673        let mut core = self.core.clone();
1674        core.update(self.staged_bytes());
1675        core.final_output()
1676    }
1677
1678    /// Construct a new `Hasher` for the regular hash function.
1679    pub fn new() -> Self {
1680        Self::from_core(HasherCore::new_internal(IV, 0))
1681    }
1682
1683    /// Construct a new `Hasher` in a [`Mode`]: the keyed hash, or key
1684    /// derivation with a context string or a context hashed once.
1685    pub fn new_with(mode: Mode) -> Self {
1686        let (key, flags) = mode.key_and_flags();
1687        Self::from_core(HasherCore::new_internal(&key, flags))
1688    }
1689
1690    /// Reset the `Hasher` to its initial state.
1691    ///
1692    /// This is functionally the same as overwriting the `Hasher` with a new
1693    /// one, using the same key or context string if any.
1694    pub fn reset(&mut self) -> &mut Self {
1695        self.core.reset();
1696        self.staged = 0;
1697        self
1698    }
1699
1700    /// Add the message's next piece, of any length, on the calling thread.
1701    ///
1702    /// **Speed**: pieces of any size hash at nearly the speed of whole
1703    /// buffers: short pieces are copied into the `Hasher` until it holds
1704    /// 16 KiB, which then hash at once. Pieces of 16 KiB and more, starting
1705    /// at a multiple of 16 KiB of the message, skip the copy (about 5% of the
1706    /// time on an Apple M4). For a whole message in memory, [`hash`] is a
1707    /// little faster; for a file or reader, see
1708    /// [`update_reader`](#method.update_reader).
1709    pub fn update(&mut self, input: &[u8]) -> &mut Self {
1710        // A fresh hasher's first update is a one-shot call's work (a
1711        // Hasher per message, the digest traits): it prefetches its code
1712        // after a pause, as hash() does.
1713        #[cfg(all(blake3_neon, feature = "std"))]
1714        if self.count() == 0 && (CHUNK_LEN + 1..PREFETCH_BELOW).contains(&input.len()) {
1715            prefetch_after_pause(input.len(), self.core.chunk_state.platform, true);
1716        }
1717        self.gather(input, false)
1718    }
1719
1720    /// [`update`](Hasher::update), using other CPU cores where that is
1721    /// faster: the same result, never slower. Pieces of 512 KiB and more
1722    /// use them, as [`hash_multithreaded`] does; shorter ones hash on the
1723    /// calling thread. One `Hasher` may mix the two calls. When reading
1724    /// the pieces keeps your thread busy, a [`stream`] is faster
1725    /// ([`Stream::submit_reader`], or [`Stream::submit_with`]): it hashes
1726    /// each piece while your thread reads the next.
1727    ///
1728    /// ```
1729    /// # blake3_servil::initialize_multithreaded(None);
1730    /// let input = vec![7u8; 3 << 20];
1731    /// let mut hasher = blake3_servil::Hasher::new();
1732    /// for piece in input.chunks(64 * 1024) {
1733    ///     hasher.update_multithreaded(piece);
1734    /// }
1735    /// assert_eq!(hasher.finalize(), blake3_servil::hash(&input));
1736    /// ```
1737    #[cfg(feature = "std")]
1738    pub fn update_multithreaded(&mut self, input: &[u8]) -> &mut Self {
1739        lanes::require();
1740        self.gather(input, true)
1741    }
1742
1743    /// Finalize the hash state and return the [`Hash`](struct.Hash.html) of
1744    /// the input.
1745    ///
1746    /// This method is idempotent. Calling it twice will give the same result.
1747    /// You can also add more input and finalize again.
1748    pub fn finalize(&self) -> Hash {
1749        assert_eq!(self.core.initial_chunk_counter, 0, "set_input_offset must be used with finalize_non_root",);
1750        self.final_output().root_hash()
1751    }
1752
1753    /// Finalize the hash state and return an [`OutputReader`], which can
1754    /// supply any number of output bytes.
1755    ///
1756    /// This method is idempotent. Calling it twice will give the same result.
1757    /// You can also add more input and finalize again.
1758    ///
1759    /// [`OutputReader`]: struct.OutputReader.html
1760    pub fn finalize_xof(&self) -> OutputReader {
1761        assert_eq!(self.core.initial_chunk_counter, 0, "set_input_offset must be used with finalize_non_root",);
1762        OutputReader::new(self.final_output())
1763    }
1764
1765    /// The number of bytes passed to [`update`](Hasher::update) so far.
1766    pub fn count(&self) -> u64 {
1767        self.core.count() + self.staged as u64
1768    }
1769
1770    /// As [`update`](Hasher::update), but reading from a
1771    /// [`std::io::Read`](https://doc.rust-lang.org/std/io/trait.Read.html) implementation.
1772    ///
1773    /// [`Hasher`] implements
1774    /// [`std::io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html), so it's possible to
1775    /// use [`std::io::copy`](https://doc.rust-lang.org/std/io/fn.copy.html) to update a [`Hasher`]
1776    /// from any reader. Unfortunately, this standard approach can limit performance, because
1777    /// `copy` currently uses an internal 8 KiB buffer that isn't big enough to take advantage of
1778    /// all SIMD instruction sets. (In particular, [AVX-512](https://en.wikipedia.org/wiki/AVX-512)
1779    /// needs a 16 KiB buffer.) `update_reader` avoids this performance problem and is slightly
1780    /// more convenient.
1781    ///
1782    /// The internal buffer size this method uses may change at any time, and it may be different
1783    /// for different targets. The only guarantee is that it will be large enough for all of this
1784    /// crate's SIMD implementations on the current platform.
1785    ///
1786    /// The most common implementer of
1787    /// [`std::io::Read`](https://doc.rust-lang.org/std/io/trait.Read.html) might be
1788    /// [`std::fs::File`](https://doc.rust-lang.org/std/fs/struct.File.html).
1789    ///
1790    /// This method requires the `std` Cargo feature, which is enabled by default.
1791    ///
1792    /// # Example
1793    ///
1794    /// ```no_run
1795    /// # use std::fs::File;
1796    /// # use std::io;
1797    /// # fn main() -> io::Result<()> {
1798    /// # blake3_servil::initialize();
1799    /// // Hash standard input.
1800    /// let mut hasher = blake3_servil::Hasher::new();
1801    /// hasher.update_reader(std::io::stdin().lock())?;
1802    /// println!("{}", hasher.finalize());
1803    /// # Ok(())
1804    /// # }
1805    /// ```
1806    #[cfg(feature = "std")]
1807    pub fn update_reader(&mut self, reader: impl std::io::Read) -> std::io::Result<&mut Self> {
1808        io::copy_wide(reader, self)?;
1809        Ok(self)
1810    }
1811}
1812
1813impl HasherCore {
1814    pub(crate) fn new_internal(key: &CVWords, flags: u8) -> Self {
1815        Self::new_from(key, flags, Platform::detect())
1816    }
1817
1818    /// [`HasherCore::new_internal`] on `platform` (the self-test's way in,
1819    /// as [`hash_serial_from`]).
1820    pub(crate) fn new_from(key: &CVWords, flags: u8, platform: Platform) -> Self {
1821        Self { key: *key, chunk_state: ChunkState::new(key, 0, flags, platform), initial_chunk_counter: 0, cv_stack: CvStack::new() }
1822    }
1823
1824    /// Back to the empty message, with the same key, flags, and platform.
1825    pub(crate) fn reset(&mut self) -> &mut Self {
1826        self.chunk_state = ChunkState::new(&self.key, 0, self.chunk_state.flags, self.chunk_state.platform);
1827        self.cv_stack.clear();
1828        self
1829    }
1830
1831    // As described in push_cv() below, we do "lazy merging", delaying merges
1832    // until right before the next CV is about to be added. This is different
1833    // from the reference implementation. Another difference is that we aren't
1834    // always merging 1 chunk at a time. Instead, each CV might represent any
1835    // power-of-two number of chunks, as long as the smaller-above-larger stack
1836    // order is maintained. Instead of the "count the trailing 0-bits"
1837    // algorithm described in the spec (which assumes you're adding one chunk
1838    // at a time), we use a "count the total number of 1-bits" variant (which
1839    // doesn't assume that). The principle is the same: each CV that should
1840    // remain in the stack is represented by a 1-bit in the total number of
1841    // chunks (or bytes) so far.
1842    #[cfg(feature = "std")]
1843    fn merge_cv_stack(&mut self, chunk_counter: u64) {
1844        // Its callers (the queue's hashers, and a Hasher's held group) start
1845        // at offset zero; a positioned subtree's offset takes the core's path.
1846        debug_assert_eq!(self.initial_chunk_counter, 0, "a hasher at offset zero");
1847        let post_merge_stack_len = hasher::ones(chunk_counter);
1848        let kernels = kernels_on(&self.key, &self.chunk_state, self.chunk_state.platform, false);
1849        self.cv_stack.merge(&kernels, post_merge_stack_len);
1850    }
1851
1852    /// The kernels on this Hasher's key and flags (see HasherKernels).
1853    #[inline(always)]
1854    fn kernels(&self, platform: Platform, pooled: bool) -> HasherKernels<'_> {
1855        kernels_on(&self.key, &self.chunk_state, platform, pooled)
1856    }
1857
1858    // In reference_impl.rs, we merge the new CV with existing CVs from the
1859    // stack before pushing it. We can do that because we know more input is
1860    // coming, so we know none of the merges are root.
1861    //
1862    // This setting is different. We want to feed as much input as possible to
1863    // the walk (`tree::wide`), without setting aside anything for the
1864    // chunk_state. If the user gives us 64 KiB, we want to parallelize over
1865    // all 64 KiB at once as a single subtree, if at all possible.
1866    //
1867    // This leads to two problems:
1868    // 1) This 64 KiB input might be the only call that ever gets made to
1869    //    update. In this case, the root node of the 64 KiB subtree would be
1870    //    the root node of the whole tree, and it would need to be ROOT
1871    //    finalized. We can't compress it until we know.
1872    // 2) This 64 KiB input might complete a larger tree, whose root node is
1873    //    similarly going to be the root of the whole tree. For example,
1874    //    maybe we have 196 KiB (that is, 128 + 64) hashed so far. We can't
1875    //    compress the node at the root of the 256 KiB subtree until we know
1876    //    how to finalize it.
1877    //
1878    // The second problem is solved with "lazy merging". That is, when we're
1879    // about to add a CV to the stack, we don't merge it with anything first,
1880    // as the reference impl does. Instead we do merges using the *previous* CV
1881    // that was added, which is sitting on top of the stack, and we put the new
1882    // CV (unmerged) on top of the stack afterwards. This guarantees that we
1883    // never merge the root node until finalize().
1884    //
1885    // Solving the first problem requires an additional tool,
1886    // compress_subtree_to_parent_node(). That function always returns the top
1887    // *two* chaining values of the subtree it's compressing. We then do lazy
1888    // merging with each of them separately, so that the second CV will always
1889    // remain unmerged. (That also helps us support extendable output when
1890    // we're hashing an input all-at-once.)
1891    #[cfg(feature = "std")]
1892    fn push_cv(&mut self, new_cv: &CVBytes, chunk_counter: u64) {
1893        self.merge_cv_stack(chunk_counter);
1894        self.cv_stack.push(*new_cv);
1895    }
1896
1897    /// [`update`](Hasher::update) with every whole subtree's result taken
1898    /// from `results`, one a whole subtree in order (in parts of
1899    /// [`lanes::TASK_LEN`], as [`hasher::subtree_len`] cuts them), as
1900    /// [`lanes::Task`] computes them.
1901    #[cfg(feature = "std")]
1902    pub(crate) fn update_with_results<'a>(&mut self, input: &[u8], results: &mut impl Iterator<Item = &'a [u8; BLOCK_LEN]>) {
1903        for part in input.chunks(lanes::TASK_LEN) {
1904            self.update_part_with_results(part, results);
1905        }
1906    }
1907
1908    #[cfg(feature = "std")]
1909    fn update_part_with_results<'a>(&mut self, mut input: &[u8], results: &mut impl Iterator<Item = &'a [u8; BLOCK_LEN]>) {
1910        // Its one caller hands it a whole held group, from a group boundary,
1911        // where the core's chunk is empty (Hasher::take_held).
1912        debug_assert_eq!(self.chunk_state.count(), 0, "a held group starts where the core's chunk is empty");
1913        while input.len() > CHUNK_LEN {
1914            let len = hasher::subtree_len(self.chunk_state.chunk_counter, input.len());
1915            let chunks = (len / CHUNK_LEN) as u64;
1916            let result = results.next().expect("a result for every planned subtree");
1917            let counter = self.chunk_state.chunk_counter;
1918            if counter == 0 && len > CHUNK_LEN {
1919                self.push_cv(result[..OUT_LEN].try_into().unwrap(), counter);
1920                self.push_cv(result[OUT_LEN..].try_into().unwrap(), counter + chunks / 2);
1921            } else {
1922                self.push_cv(result[..OUT_LEN].try_into().unwrap(), counter);
1923            }
1924            self.chunk_state.chunk_counter += chunks;
1925            input = &input[len..];
1926        }
1927        if !input.is_empty() {
1928            self.chunk_state.update(input);
1929            self.merge_cv_stack(self.chunk_state.chunk_counter);
1930        }
1931    }
1932
1933    /// `update`'s loop; with `pooled`, whole subtrees of
1934    /// `lanes::MIN_SPLIT_LEN` and more go to the pool.
1935    pub(crate) fn update_pooled(&mut self, input: &[u8], pooled: bool) -> &mut Self {
1936        #[cfg(not(feature = "std"))]
1937        let _ = pooled;
1938        self.assert_room(self.count(), input.len());
1939        // The partial chunk first (hasher::fill), then whole subtrees and the
1940        // last chunk (hasher::feed), as src/hasher.rs describes.
1941        let fill_kernels = kernels_on(&self.key, &self.chunk_state, self.chunk_state.platform, pooled);
1942        let rest = hasher::fill(&fill_kernels, &mut self.chunk_state, &mut self.cv_stack, self.initial_chunk_counter, input);
1943        if rest.is_empty() {
1944            return self;
1945        }
1946        // Pooled, the subtrees take the lock one at a time (children).
1947        let turn = platform::Sme2Turn::take(self.chunk_state.platform, !pooled && rest.len() >= SME2_SIZED_LEN);
1948        let kernels = kernels_on(&self.key, &self.chunk_state, turn.platform(), pooled);
1949        hasher::feed(&kernels, &mut self.chunk_state, &mut self.cv_stack, self.initial_chunk_counter, rest);
1950        self
1951    }
1952
1953    pub(crate) fn final_output(&self) -> Output {
1954        hasher::final_node(&self.kernels(self.chunk_state.platform, false), &self.chunk_state, &self.cv_stack)
1955    }
1956
1957    /// The serial update: whole subtrees now, the last chunk kept.
1958    pub(crate) fn update(&mut self, input: &[u8]) -> &mut Self {
1959        self.update_pooled(input, false)
1960    }
1961
1962    /// Requires that `len` more bytes after `count` fit the subtree that
1963    /// set_input_offset started (max_subtree_len).
1964    pub(crate) fn assert_room(&self, count: u64, len: usize) {
1965        let input_offset = self.initial_chunk_counter * CHUNK_LEN as u64;
1966        if let Some(max) = max_subtree_len(input_offset) {
1967            assert!(len as u64 <= max - count, "the subtree starting at {} contains at most {} bytes (found {})", input_offset, max, count + len as u64,);
1968        }
1969    }
1970
1971    /// Start the subtree at byte `offset` of the message (the outboard's
1972    /// positioned subtrees; set_input_offset in the tests).
1973    #[cfg(any(feature = "std", test))]
1974    pub(crate) fn set_input_offset(&mut self, offset: u64) -> &mut Self {
1975        assert_eq!(self.count(), 0, "hasher has already accepted input");
1976        assert_eq!(offset % CHUNK_LEN as u64, 0, "offset ({offset}) must be a chunk boundary (divisible by {CHUNK_LEN})",);
1977        let counter = offset / CHUNK_LEN as u64;
1978        self.chunk_state.chunk_counter = counter;
1979        self.initial_chunk_counter = counter;
1980        self
1981    }
1982
1983    /// Bytes so far, counted from the input offset.
1984    pub(crate) fn count(&self) -> u64 {
1985        (self.chunk_state.chunk_counter - self.initial_chunk_counter) * CHUNK_LEN as u64 + self.chunk_state.count() as u64
1986    }
1987}
1988
1989// Don't derive(Debug), because the state may be secret.
1990impl fmt::Debug for Hasher {
1991    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1992        f.debug_struct("Hasher").field("flags", &self.core.chunk_state.flags).field("platform", &self.core.chunk_state.platform).finish()
1993    }
1994}
1995
1996impl Default for Hasher {
1997    #[inline]
1998    fn default() -> Self {
1999        Self::new()
2000    }
2001}
2002
2003#[cfg(feature = "std")]
2004impl std::io::Write for Hasher {
2005    /// This is equivalent to [`update`](#method.update).
2006    #[inline]
2007    fn write(&mut self, input: &[u8]) -> std::io::Result<usize> {
2008        self.update(input);
2009        Ok(input.len())
2010    }
2011
2012    #[inline]
2013    fn flush(&mut self) -> std::io::Result<()> {
2014        Ok(())
2015    }
2016}
2017
2018#[cfg(feature = "zeroize")]
2019impl Zeroize for Hasher {
2020    fn zeroize(&mut self) {
2021        self.core.zeroize();
2022        self.stage.fill(core::mem::MaybeUninit::new(0));
2023        self.staged = 0;
2024    }
2025}
2026
2027#[cfg(feature = "zeroize")]
2028impl Zeroize for HasherCore {
2029    fn zeroize(&mut self) {
2030        // Destructuring to trigger compile error as a reminder to update this impl.
2031        let Self { key, chunk_state, initial_chunk_counter, cv_stack } = self;
2032
2033        key.zeroize();
2034        chunk_state.zeroize();
2035        initial_chunk_counter.zeroize();
2036        cv_stack.zeroize();
2037    }
2038}
2039
2040/// An incremental reader for extended output, returned by
2041/// [`Hasher::finalize_xof`](struct.Hasher.html#method.finalize_xof).
2042///
2043/// Shorter BLAKE3 outputs are prefixes of longer ones, and explicitly requesting a short output is
2044/// equivalent to truncating the default-length output. Note that this is a difference between
2045/// BLAKE2 and BLAKE3.
2046///
2047/// # Security notes
2048///
2049/// Outputs shorter than the default length of 32 bytes (256 bits) provide less security. An N-bit
2050/// BLAKE3 output is intended to provide N bits of first and second preimage resistance and N/2
2051/// bits of collision resistance, for any N up to 256. Longer outputs don't provide any additional
2052/// security.
2053///
2054/// Avoid relying on the secrecy of the output offset, that is, the number of output bytes read or
2055/// the arguments to [`seek`](struct.OutputReader.html#method.seek) or
2056/// [`set_position`](struct.OutputReader.html#method.set_position). [_Block-Cipher-Based Tree
2057/// Hashing_ by Aldo Gunsing](https://eprint.iacr.org/2022/283) shows that an attacker who knows
2058/// both the message and the key (if any) can easily determine the offset of an extended output.
2059/// For comparison, AES-CTR has a similar property: if you know the key, you can decrypt a block
2060/// from an unknown position in the output stream to recover its block index. Callers with strong
2061/// secret keys aren't affected in practice, but secret offsets are a [design
2062/// smell](https://en.wikipedia.org/wiki/Design_smell) in any case.
2063#[derive(Clone)]
2064pub struct OutputReader {
2065    inner: Output,
2066    position_within_block: u8,
2067}
2068
2069impl OutputReader {
2070    fn new(inner: Output) -> Self {
2071        Self { inner, position_within_block: 0 }
2072    }
2073
2074    // This helper function handles both the case where the output buffer is
2075    // shorter than one block, and the case where our position_within_block is
2076    // non-zero.
2077    fn fill_one_block(&mut self, buf: &mut &mut [u8]) {
2078        let output_block: [u8; BLOCK_LEN] = self.inner.root_output_block();
2079        let output_bytes = &output_block[self.position_within_block as usize..];
2080        let take = cmp::min(buf.len(), output_bytes.len());
2081        buf[..take].copy_from_slice(&output_bytes[..take]);
2082        self.position_within_block += take as u8;
2083        if self.position_within_block == BLOCK_LEN as u8 {
2084            self.inner.counter += 1;
2085            self.position_within_block = 0;
2086        }
2087        // Advance the dest buffer. mem::take() is a borrowck workaround.
2088        *buf = &mut core::mem::take(buf)[take..];
2089    }
2090
2091    /// Fill a buffer with output bytes and advance the position of the
2092    /// `OutputReader`. This is equivalent to [`Read::read`], except that it
2093    /// doesn't return a `Result`. Both methods always fill the entire buffer.
2094    ///
2095    /// Note that `OutputReader` doesn't buffer output bytes internally, so
2096    /// calling `fill` repeatedly with a short-length or odd-length slice will
2097    /// end up performing the same compression multiple times. If you're
2098    /// reading output in a loop, prefer a slice length that's a multiple of
2099    /// [`BLOCK_LEN`] (64 bytes).
2100    ///
2101    /// The maximum output size of BLAKE3 is 2<sup>64</sup>-1 bytes. If you try
2102    /// to extract more than that, for example by seeking near the end and
2103    /// reading further, the behavior is unspecified.
2104    ///
2105    /// [`Read::read`]: #method.read
2106    pub fn fill(&mut self, mut buf: &mut [u8]) {
2107        if buf.is_empty() {
2108            return;
2109        }
2110
2111        // If we're partway through a block, try to get to a block boundary.
2112        if self.position_within_block != 0 {
2113            self.fill_one_block(&mut buf);
2114        }
2115
2116        let full_blocks = buf.len() / BLOCK_LEN;
2117        let full_blocks_len = full_blocks * BLOCK_LEN;
2118        if full_blocks > 0 {
2119            debug_assert_eq!(0, self.position_within_block);
2120            self.inner.platform.xof_many(
2121                &self.inner.input_chaining_value,
2122                &self.inner.block,
2123                self.inner.block_len,
2124                self.inner.counter,
2125                self.inner.flags | ROOT,
2126                &mut buf[..full_blocks_len],
2127            );
2128            self.inner.counter += full_blocks as u64;
2129            buf = &mut buf[full_blocks * BLOCK_LEN..];
2130        }
2131
2132        if !buf.is_empty() {
2133            debug_assert!(buf.len() < BLOCK_LEN);
2134            self.fill_one_block(&mut buf);
2135            debug_assert!(buf.is_empty());
2136        }
2137    }
2138
2139    /// Return the current read position in the output stream. This is
2140    /// equivalent to [`Seek::stream_position`], except that it doesn't return
2141    /// a `Result`. The position of a new `OutputReader` starts at 0, and each
2142    /// call to [`fill`] or [`Read::read`] moves the position forward by the
2143    /// number of bytes read.
2144    ///
2145    /// [`Seek::stream_position`]: #method.stream_position
2146    /// [`fill`]: #method.fill
2147    /// [`Read::read`]: #method.read
2148    pub fn position(&self) -> u64 {
2149        self.inner.counter * BLOCK_LEN as u64 + self.position_within_block as u64
2150    }
2151
2152    /// Seek to a new read position in the output stream. This is equivalent to
2153    /// calling [`Seek::seek`] with [`SeekFrom::Start`], except that it doesn't
2154    /// return a `Result`.
2155    ///
2156    /// [`Seek::seek`]: #method.seek
2157    /// [`SeekFrom::Start`]: https://doc.rust-lang.org/std/io/enum.SeekFrom.html
2158    pub fn set_position(&mut self, position: u64) {
2159        self.position_within_block = (position % BLOCK_LEN as u64) as u8;
2160        self.inner.counter = position / BLOCK_LEN as u64;
2161    }
2162}
2163
2164// Don't derive(Debug), because the state may be secret.
2165impl fmt::Debug for OutputReader {
2166    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2167        f.debug_struct("OutputReader").field("position", &self.position()).finish()
2168    }
2169}
2170
2171#[cfg(feature = "std")]
2172impl std::io::Read for OutputReader {
2173    #[inline]
2174    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
2175        self.fill(buf);
2176        Ok(buf.len())
2177    }
2178}
2179
2180#[cfg(feature = "std")]
2181impl std::io::Seek for OutputReader {
2182    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
2183        let max_position = u64::MAX as i128;
2184        let target_position: i128 = match pos {
2185            std::io::SeekFrom::Start(x) => x as i128,
2186            std::io::SeekFrom::Current(x) => self.position() as i128 + x as i128,
2187            std::io::SeekFrom::End(_) => {
2188                return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "seek from end not supported"));
2189            }
2190        };
2191        if target_position < 0 {
2192            return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "seek before start"));
2193        }
2194        self.set_position(cmp::min(target_position, max_position) as u64);
2195        Ok(self.position())
2196    }
2197}
2198
2199#[cfg(feature = "zeroize")]
2200impl Zeroize for OutputReader {
2201    fn zeroize(&mut self) {
2202        // Destructuring to trigger compile error as a reminder to update this impl.
2203        let Self { inner, position_within_block } = self;
2204
2205        inner.zeroize();
2206        position_within_block.zeroize();
2207    }
2208}