blake2s_simd/
lib.rs

1//! [![GitHub](https://img.shields.io/github/tag/oconnor663/blake2_simd.svg?label=GitHub)](https://github.com/oconnor663/blake2_simd) [![crates.io](https://img.shields.io/crates/v/blake2s_simd.svg)](https://crates.io/crates/blake2s_simd) [![Actions Status](https://github.com/oconnor663/blake2_simd/workflows/tests/badge.svg)](https://github.com/oconnor663/blake2_simd/actions)
2//!
3//! An implementation of the BLAKE2s and BLAKE2sp hash functions. See also
4//! [`blake2b_simd`](https://docs.rs/blake2b_simd).
5//!
6//! This crate includes:
7//!
8//! - 100% stable Rust.
9//! - SIMD implementations based on Samuel Neves' [`blake2-avx2`](https://github.com/sneves/blake2-avx2).
10//!   These are very fast. For benchmarks, see [the Performance section of the
11//!   README](https://github.com/oconnor663/blake2_simd#performance).
12//! - Portable, safe implementations for other platforms.
13//! - Dynamic CPU feature detection. Binaries include multiple implementations by default and
14//!   choose the fastest one the processor supports at runtime.
15//! - All the features from the [the BLAKE2 spec](https://blake2.net/blake2.pdf), like adjustable
16//!   length, keying, and associated data for tree hashing.
17//! - `no_std` support. The `std` Cargo feature is on by default, for CPU feature detection and
18//!   for implementing `std::io::Write`.
19//! - Support for computing multiple BLAKE2s hashes in parallel, matching the efficiency of
20//!   BLAKE2sp. See the [`many`](many/index.html) module.
21//!
22//! # Example
23//!
24//! ```
25//! use blake2s_simd::{blake2s, Params};
26//!
27//! let expected = "08d6cad88075de8f192db097573d0e829411cd91eb6ec65e8fc16c017edfdb74";
28//! let hash = blake2s(b"foo");
29//! assert_eq!(expected, &hash.to_hex());
30//!
31//! let hash = Params::new()
32//!     .hash_length(16)
33//!     .key(b"Squeamish Ossifrage")
34//!     .personal(b"Shaftoe")
35//!     .to_state()
36//!     .update(b"foo")
37//!     .update(b"bar")
38//!     .update(b"baz")
39//!     .finalize();
40//! assert_eq!("28325512782cbf5019424fa65da9a6c7", &hash.to_hex());
41//! ```
42
43#![cfg_attr(not(feature = "std"), no_std)]
44
45use arrayref::{array_refs, mut_array_refs};
46use core::cmp;
47use core::fmt;
48use core::mem::size_of;
49
50#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
51mod avx2;
52mod portable;
53#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
54mod sse41;
55
56pub mod blake2sp;
57mod guts;
58pub mod many;
59
60#[cfg(test)]
61mod test;
62
63type Word = u32;
64type Count = u64;
65
66/// The max hash length.
67pub const OUTBYTES: usize = 8 * size_of::<Word>();
68/// The max key length.
69pub const KEYBYTES: usize = 8 * size_of::<Word>();
70/// The max salt length.
71pub const SALTBYTES: usize = 2 * size_of::<Word>();
72/// The max personalization length.
73pub const PERSONALBYTES: usize = 2 * size_of::<Word>();
74/// The number input bytes passed to each call to the compression function. Small benchmarks need
75/// to use an even multiple of `BLOCKBYTES`, or else their apparent throughput will be low.
76pub const BLOCKBYTES: usize = 16 * size_of::<Word>();
77
78const IV: [Word; 8] = [
79    0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
80];
81
82const SIGMA: [[u8; 16]; 10] = [
83    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
84    [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
85    [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
86    [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
87    [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
88    [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
89    [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
90    [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
91    [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
92    [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
93];
94
95/// Compute the BLAKE2s hash of a slice of bytes all at once, using default
96/// parameters.
97///
98/// # Example
99///
100/// ```
101/// # use blake2s_simd::{blake2s, Params};
102/// let expected = "08d6cad88075de8f192db097573d0e829411cd91eb6ec65e8fc16c017edfdb74";
103/// let hash = blake2s(b"foo");
104/// assert_eq!(expected, &hash.to_hex());
105/// ```
106pub fn blake2s(input: &[u8]) -> Hash {
107    Params::new().hash(input)
108}
109
110/// A parameter builder that exposes all the non-default BLAKE2 features.
111///
112/// Apart from `hash_length`, which controls the length of the final `Hash`,
113/// all of these parameters are just associated data that gets mixed with the
114/// input. For more details, see [the BLAKE2 spec](https://blake2.net/blake2.pdf).
115///
116/// Several of the parameters have a valid range defined in the spec and
117/// documented below. Trying to set an invalid parameter will panic.
118///
119/// # Example
120///
121/// ```
122/// # use blake2s_simd::Params;
123/// // Create a Params object with a secret key and a non-default length.
124/// let mut params = Params::new();
125/// params.key(b"my secret key");
126/// params.hash_length(16);
127///
128/// // Use those params to hash an input all at once.
129/// let hash = params.hash(b"my input");
130///
131/// // Or use those params to build an incremental State.
132/// let mut state = params.to_state();
133/// ```
134#[derive(Clone)]
135pub struct Params {
136    hash_length: u8,
137    key_length: u8,
138    key_block: [u8; BLOCKBYTES],
139    salt: [u8; SALTBYTES],
140    personal: [u8; PERSONALBYTES],
141    fanout: u8,
142    max_depth: u8,
143    max_leaf_length: u32,
144    node_offset: u64,
145    node_depth: u8,
146    inner_hash_length: u8,
147    last_node: guts::LastNode,
148    implementation: guts::Implementation,
149}
150
151impl Params {
152    /// Equivalent to `Params::default()`.
153    #[inline]
154    pub fn new() -> Self {
155        Self {
156            hash_length: OUTBYTES as u8,
157            key_length: 0,
158            key_block: [0; BLOCKBYTES],
159            salt: [0; SALTBYTES],
160            personal: [0; PERSONALBYTES],
161            // NOTE: fanout and max_depth don't default to zero!
162            fanout: 1,
163            max_depth: 1,
164            max_leaf_length: 0,
165            node_offset: 0,
166            node_depth: 0,
167            inner_hash_length: 0,
168            last_node: guts::LastNode::No,
169            implementation: guts::Implementation::detect(),
170        }
171    }
172
173    #[inline(always)]
174    fn to_words(&self) -> [Word; 8] {
175        let (salt_left, salt_right) = array_refs!(&self.salt, SALTBYTES / 2, SALTBYTES / 2);
176        let (personal_left, personal_right) =
177            array_refs!(&self.personal, PERSONALBYTES / 2, PERSONALBYTES / 2);
178        [
179            IV[0]
180                ^ self.hash_length as u32
181                ^ (self.key_length as u32) << 8
182                ^ (self.fanout as u32) << 16
183                ^ (self.max_depth as u32) << 24,
184            IV[1] ^ self.max_leaf_length,
185            IV[2] ^ self.node_offset as u32,
186            IV[3]
187                ^ (self.node_offset >> 32) as u32
188                ^ (self.node_depth as u32) << 16
189                ^ (self.inner_hash_length as u32) << 24,
190            IV[4] ^ Word::from_le_bytes(*salt_left),
191            IV[5] ^ Word::from_le_bytes(*salt_right),
192            IV[6] ^ Word::from_le_bytes(*personal_left),
193            IV[7] ^ Word::from_le_bytes(*personal_right),
194        ]
195    }
196
197    /// Hash an input all at once with these parameters.
198    #[inline]
199    pub fn hash(&self, input: &[u8]) -> Hash {
200        // If there's a key, just fall back to using the State.
201        if self.key_length > 0 {
202            return self.to_state().update(input).finalize();
203        }
204        let mut words = self.to_words();
205        self.implementation.compress1_loop(
206            input,
207            &mut words,
208            0,
209            self.last_node,
210            guts::Finalize::Yes,
211            guts::Stride::Serial,
212        );
213        Hash {
214            bytes: state_words_to_bytes(&words),
215            len: self.hash_length,
216        }
217    }
218
219    /// Construct a `State` object based on these parameters, for hashing input
220    /// incrementally.
221    pub fn to_state(&self) -> State {
222        State::with_params(self)
223    }
224
225    /// Set the length of the final hash in bytes, from 1 to `OUTBYTES` (32). Apart from
226    /// controlling the length of the final `Hash`, this is also associated data, and changing it
227    /// will result in a totally different hash.
228    #[inline]
229    pub fn hash_length(&mut self, length: usize) -> &mut Self {
230        assert!(
231            1 <= length && length <= OUTBYTES,
232            "Bad hash length: {}",
233            length
234        );
235        self.hash_length = length as u8;
236        self
237    }
238
239    /// Use a secret key, so that BLAKE2 acts as a MAC. The maximum key length is `KEYBYTES` (32).
240    /// An empty key is equivalent to having no key at all.
241    #[inline]
242    pub fn key(&mut self, key: &[u8]) -> &mut Self {
243        assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len());
244        self.key_length = key.len() as u8;
245        self.key_block = [0; BLOCKBYTES];
246        self.key_block[..key.len()].copy_from_slice(key);
247        self
248    }
249
250    /// At most `SALTBYTES` (8). Shorter salts are padded with null bytes. An empty salt is
251    /// equivalent to having no salt at all.
252    #[inline]
253    pub fn salt(&mut self, salt: &[u8]) -> &mut Self {
254        assert!(salt.len() <= SALTBYTES, "Bad salt length: {}", salt.len());
255        self.salt = [0; SALTBYTES];
256        self.salt[..salt.len()].copy_from_slice(salt);
257        self
258    }
259
260    /// At most `PERSONALBYTES` (8). Shorter personalizations are padded with null bytes. An empty
261    /// personalization is equivalent to having no personalization at all.
262    #[inline]
263    pub fn personal(&mut self, personalization: &[u8]) -> &mut Self {
264        assert!(
265            personalization.len() <= PERSONALBYTES,
266            "Bad personalization length: {}",
267            personalization.len()
268        );
269        self.personal = [0; PERSONALBYTES];
270        self.personal[..personalization.len()].copy_from_slice(personalization);
271        self
272    }
273
274    /// From 0 (meaning unlimited) to 255. The default is 1 (meaning sequential).
275    #[inline]
276    pub fn fanout(&mut self, fanout: u8) -> &mut Self {
277        self.fanout = fanout;
278        self
279    }
280
281    /// From 0 (meaning BLAKE2X B2 hashes), through 1 (the default, meaning sequential) to 255 (meaning unlimited).
282    #[inline]
283    pub fn max_depth(&mut self, depth: u8) -> &mut Self {
284        self.max_depth = depth;
285        self
286    }
287
288    /// From 0 (the default, meaning unlimited or sequential) to `2^32 - 1`.
289    #[inline]
290    pub fn max_leaf_length(&mut self, length: u32) -> &mut Self {
291        self.max_leaf_length = length;
292        self
293    }
294
295    /// From 0 (the default, meaning first, leftmost, leaf, or sequential) to `2^48 - 1`.
296    #[inline]
297    pub fn node_offset(&mut self, offset: u64) -> &mut Self {
298        assert!(offset < (1 << 48), "Bad node offset: {}", offset);
299        self.node_offset = offset;
300        self
301    }
302
303    /// From 0 (the default, meaning leaf or sequential) to 255.
304    #[inline]
305    pub fn node_depth(&mut self, depth: u8) -> &mut Self {
306        self.node_depth = depth;
307        self
308    }
309
310    /// From 0 (the default, meaning sequential) to `OUTBYTES` (32).
311    #[inline]
312    pub fn inner_hash_length(&mut self, length: usize) -> &mut Self {
313        assert!(length <= OUTBYTES, "Bad inner hash length: {}", length);
314        self.inner_hash_length = length as u8;
315        self
316    }
317
318    /// Indicates the rightmost node in a row. This can also be changed on the
319    /// `State` object, potentially after hashing has begun. See
320    /// [`State::set_last_node`].
321    ///
322    /// [`State::set_last_node`]: struct.State.html#method.set_last_node
323    #[inline]
324    pub fn last_node(&mut self, last_node: bool) -> &mut Self {
325        self.last_node = if last_node {
326            guts::LastNode::Yes
327        } else {
328            guts::LastNode::No
329        };
330        self
331    }
332}
333
334impl Default for Params {
335    fn default() -> Self {
336        Self::new()
337    }
338}
339
340impl fmt::Debug for Params {
341    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
342        write!(
343            f,
344            "Params {{ hash_length: {}, key_length: {}, salt: {:?}, personal: {:?}, fanout: {}, \
345             max_depth: {}, max_leaf_length: {}, node_offset: {}, node_depth: {}, \
346             inner_hash_length: {}, last_node: {} }}",
347            self.hash_length,
348            // NB: Don't print the key itself. Debug shouldn't leak secrets.
349            self.key_length,
350            &self.salt,
351            &self.personal,
352            self.fanout,
353            self.max_depth,
354            self.max_leaf_length,
355            self.node_offset,
356            self.node_depth,
357            self.inner_hash_length,
358            self.last_node.yes(),
359        )
360    }
361}
362
363/// An incremental hasher for BLAKE2s.
364///
365/// To construct a `State` with non-default parameters, see `Params::to_state`.
366///
367/// # Example
368///
369/// ```
370/// use blake2s_simd::{State, blake2s};
371///
372/// let mut state = blake2s_simd::State::new();
373///
374/// state.update(b"foo");
375/// assert_eq!(blake2s(b"foo"), state.finalize());
376///
377/// state.update(b"bar");
378/// assert_eq!(blake2s(b"foobar"), state.finalize());
379/// ```
380#[derive(Clone)]
381pub struct State {
382    words: [Word; 8],
383    count: Count,
384    buf: [u8; BLOCKBYTES],
385    buflen: u8,
386    last_node: guts::LastNode,
387    hash_length: u8,
388    implementation: guts::Implementation,
389    is_keyed: bool,
390}
391
392impl State {
393    /// Equivalent to `State::default()` or `Params::default().to_state()`.
394    pub fn new() -> Self {
395        Self::with_params(&Params::default())
396    }
397
398    fn with_params(params: &Params) -> Self {
399        let mut state = Self {
400            words: params.to_words(),
401            count: 0,
402            buf: [0; BLOCKBYTES],
403            buflen: 0,
404            last_node: params.last_node,
405            hash_length: params.hash_length,
406            implementation: params.implementation,
407            is_keyed: params.key_length > 0,
408        };
409        if state.is_keyed {
410            state.buf = params.key_block;
411            state.buflen = state.buf.len() as u8;
412        }
413        state
414    }
415
416    fn fill_buf(&mut self, input: &mut &[u8]) {
417        let take = cmp::min(BLOCKBYTES - self.buflen as usize, input.len());
418        self.buf[self.buflen as usize..self.buflen as usize + take].copy_from_slice(&input[..take]);
419        self.buflen += take as u8;
420        *input = &input[take..];
421    }
422
423    // If the state already has some input in its buffer, try to fill the buffer and perform a
424    // compression. However, only do the compression if there's more input coming, otherwise it
425    // will give the wrong hash it the caller finalizes immediately after.
426    fn compress_buffer_if_possible(&mut self, input: &mut &[u8]) {
427        if self.buflen > 0 {
428            self.fill_buf(input);
429            if !input.is_empty() {
430                self.implementation.compress1_loop(
431                    &self.buf,
432                    &mut self.words,
433                    self.count,
434                    self.last_node,
435                    guts::Finalize::No,
436                    guts::Stride::Serial,
437                );
438                self.count = self.count.wrapping_add(BLOCKBYTES as Count);
439                self.buflen = 0;
440            }
441        }
442    }
443
444    /// Add input to the hash. You can call `update` any number of times.
445    pub fn update(&mut self, mut input: &[u8]) -> &mut Self {
446        // If we have a partial buffer, try to complete it.
447        self.compress_buffer_if_possible(&mut input);
448        // While there's more than a block of input left (which also means we cleared the buffer
449        // above), compress blocks directly without copying.
450        let mut end = input.len().saturating_sub(1);
451        end -= end % BLOCKBYTES;
452        if end > 0 {
453            self.implementation.compress1_loop(
454                &input[..end],
455                &mut self.words,
456                self.count,
457                self.last_node,
458                guts::Finalize::No,
459                guts::Stride::Serial,
460            );
461            self.count = self.count.wrapping_add(end as Count);
462            input = &input[end..];
463        }
464        // Buffer any remaining input, to be either compressed or finalized in a subsequent call.
465        // Note that this represents some copying overhead, which in theory we could avoid in
466        // all-at-once setting. A function hardcoded for exactly BLOCKSIZE input bytes is about 10%
467        // faster than using this implementation for the same input.
468        self.fill_buf(&mut input);
469        self
470    }
471
472    /// Finalize the state and return a `Hash`. This method is idempotent, and calling it multiple
473    /// times will give the same result. It's also possible to `update` with more input in between.
474    pub fn finalize(&self) -> Hash {
475        let mut words_copy = self.words;
476        self.implementation.compress1_loop(
477            &self.buf[..self.buflen as usize],
478            &mut words_copy,
479            self.count,
480            self.last_node,
481            guts::Finalize::Yes,
482            guts::Stride::Serial,
483        );
484        Hash {
485            bytes: state_words_to_bytes(&words_copy),
486            len: self.hash_length,
487        }
488    }
489
490    /// Set a flag indicating that this is the last node of its level in a tree hash. This is
491    /// equivalent to [`Params::last_node`], except that it can be set at any time before calling
492    /// `finalize`. That allows callers to begin hashing a node without knowing ahead of time
493    /// whether it's the last in its level. For more details about the intended use of this flag
494    /// [the BLAKE2 spec].
495    ///
496    /// [`Params::last_node`]: struct.Params.html#method.last_node
497    /// [the BLAKE2 spec]: https://blake2.net/blake2.pdf
498    pub fn set_last_node(&mut self, last_node: bool) -> &mut Self {
499        self.last_node = if last_node {
500            guts::LastNode::Yes
501        } else {
502            guts::LastNode::No
503        };
504        self
505    }
506
507    /// Return the total number of bytes input so far.
508    ///
509    /// Note that `count` doesn't include the bytes of the key block, if any.
510    /// It's exactly the total number of input bytes fed to `update`.
511    pub fn count(&self) -> Count {
512        let mut ret = self.count.wrapping_add(self.buflen as Count);
513        if self.is_keyed {
514            ret -= BLOCKBYTES as Count;
515        }
516        ret
517    }
518}
519
520#[inline(always)]
521fn state_words_to_bytes(state_words: &[Word; 8]) -> [u8; OUTBYTES] {
522    let mut bytes = [0; OUTBYTES];
523    {
524        const W: usize = size_of::<Word>();
525        let refs = mut_array_refs!(&mut bytes, W, W, W, W, W, W, W, W);
526        *refs.0 = state_words[0].to_le_bytes();
527        *refs.1 = state_words[1].to_le_bytes();
528        *refs.2 = state_words[2].to_le_bytes();
529        *refs.3 = state_words[3].to_le_bytes();
530        *refs.4 = state_words[4].to_le_bytes();
531        *refs.5 = state_words[5].to_le_bytes();
532        *refs.6 = state_words[6].to_le_bytes();
533        *refs.7 = state_words[7].to_le_bytes();
534    }
535    bytes
536}
537
538#[cfg(feature = "std")]
539impl std::io::Write for State {
540    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
541        self.update(buf);
542        Ok(buf.len())
543    }
544
545    fn flush(&mut self) -> std::io::Result<()> {
546        Ok(())
547    }
548}
549
550impl fmt::Debug for State {
551    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
552        // NB: Don't print the words. Leaking them would allow length extension.
553        write!(
554            f,
555            "State {{ count: {}, hash_length: {}, last_node: {} }}",
556            self.count(),
557            self.hash_length,
558            self.last_node.yes(),
559        )
560    }
561}
562
563impl Default for State {
564    fn default() -> Self {
565        Self::with_params(&Params::default())
566    }
567}
568
569type HexString = arrayvec::ArrayString<{ 2 * OUTBYTES }>;
570
571/// A finalized BLAKE2 hash, with constant-time equality.
572#[derive(Clone, Copy)]
573pub struct Hash {
574    bytes: [u8; OUTBYTES],
575    len: u8,
576}
577
578impl Hash {
579    /// Convert the hash to a byte slice. Note that if you're using BLAKE2 as a MAC, you need
580    /// constant time equality, which `&[u8]` doesn't provide.
581    pub fn as_bytes(&self) -> &[u8] {
582        &self.bytes[..self.len as usize]
583    }
584
585    /// Convert the hash to a byte array. Note that if you're using BLAKE2 as a
586    /// MAC, you need constant time equality, which arrays don't provide. This
587    /// panics in debug mode if the length of the hash isn't `OUTBYTES`.
588    #[inline]
589    pub fn as_array(&self) -> &[u8; OUTBYTES] {
590        debug_assert_eq!(self.len as usize, OUTBYTES);
591        &self.bytes
592    }
593
594    /// Convert the hash to a lowercase hexadecimal
595    /// [`ArrayString`](https://docs.rs/arrayvec/0.7/arrayvec/struct.ArrayString.html).
596    pub fn to_hex(&self) -> HexString {
597        bytes_to_hex(self.as_bytes())
598    }
599}
600
601fn bytes_to_hex(bytes: &[u8]) -> HexString {
602    let mut s = arrayvec::ArrayString::new();
603    let table = b"0123456789abcdef";
604    for &b in bytes {
605        s.push(table[(b >> 4) as usize] as char);
606        s.push(table[(b & 0xf) as usize] as char);
607    }
608    s
609}
610
611impl From<[u8; OUTBYTES]> for Hash {
612    fn from(bytes: [u8; OUTBYTES]) -> Self {
613        Self {
614            bytes,
615            len: OUTBYTES as u8,
616        }
617    }
618}
619
620impl From<&[u8; OUTBYTES]> for Hash {
621    fn from(bytes: &[u8; OUTBYTES]) -> Self {
622        Self::from(*bytes)
623    }
624}
625
626/// This implementation is constant time, if the two hashes are the same length.
627impl PartialEq for Hash {
628    fn eq(&self, other: &Hash) -> bool {
629        constant_time_eq::constant_time_eq(&self.as_bytes(), &other.as_bytes())
630    }
631}
632
633/// This implementation is constant time, if the slice is the same length as the hash.
634impl PartialEq<[u8]> for Hash {
635    fn eq(&self, other: &[u8]) -> bool {
636        constant_time_eq::constant_time_eq(&self.as_bytes(), other)
637    }
638}
639
640impl Eq for Hash {}
641
642impl AsRef<[u8]> for Hash {
643    fn as_ref(&self) -> &[u8] {
644        self.as_bytes()
645    }
646}
647
648impl fmt::Debug for Hash {
649    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
650        write!(f, "Hash(0x{})", self.to_hex())
651    }
652}
653
654// Paint a byte pattern that won't repeat, so that we don't accidentally miss
655// buffer offset bugs. This is the same as what Bao uses in its tests.
656#[cfg(test)]
657fn paint_test_input(buf: &mut [u8]) {
658    let mut offset = 0;
659    let mut counter: u32 = 1;
660    while offset < buf.len() {
661        let bytes = counter.to_le_bytes();
662        let take = cmp::min(bytes.len(), buf.len() - offset);
663        buf[offset..][..take].copy_from_slice(&bytes[..take]);
664        counter += 1;
665        offset += take;
666    }
667}
668
669// This module is pub for internal benchmarks only. Please don't use it.
670#[doc(hidden)]
671pub mod benchmarks {
672    use super::*;
673
674    pub fn force_portable(params: &mut Params) {
675        params.implementation = guts::Implementation::portable();
676    }
677
678    pub fn force_portable_blake2sp(params: &mut blake2sp::Params) {
679        blake2sp::force_portable(params);
680    }
681}