Skip to main content

dcrypt_algorithms/hash/blake2/
mod.rs

1//! BLAKE2 hash function implementations
2//!
3//! This module implements the BLAKE2 family of hash functions as specified in
4//! RFC 7693 (<https://www.rfc-editor.org/rfc/rfc7693.html>). BLAKE2 is optimized
5//! for speed on 64-bit platforms while maintaining high security levels.
6//!
7//! Supported variants:
8//! - **BLAKE2b** – 64‑bit optimized, digest up to 64 bytes.
9//! - **BLAKE2s** – 32‑bit optimized, digest up to 32 bytes.
10
11#[cfg(feature = "alloc")]
12use crate::alloc_prelude::*;
13
14use core::cmp::min;
15
16use dcrypt_internal::zeroing::{Zeroize, Zeroizing};
17
18use crate::error::{validate, Error, Result};
19use crate::hash::{HashAlgorithm, HashFunction};
20use crate::types::Digest;
21use dcrypt_common::security::{SecretBuffer, SecureZeroingType};
22
23// ─────────────────────────────────────────────────────────────────────────────
24// Constants
25// ─────────────────────────────────────────────────────────────────────────────
26const BLAKE2B_BLOCK_SIZE: usize = 128;
27const BLAKE2B_MAX_OUTPUT_SIZE: usize = 64;
28const BLAKE2B_ROUNDS: usize = 12;
29const BLAKE2B_KEY_SIZE: usize = 64; // Maximum key size for keyed mode
30
31#[inline(always)]
32fn read_u64_le(bytes: &[u8]) -> u64 {
33    debug_assert!(bytes.len() >= 8);
34    let mut word = Zeroizing::new(0u64);
35    for (index, byte) in bytes[..8].iter().enumerate() {
36        *word |= u64::from(*byte) << (index * 8);
37    }
38    *word
39}
40
41#[inline(always)]
42fn read_u32_le(bytes: &[u8]) -> u32 {
43    debug_assert!(bytes.len() >= 4);
44    let mut word = Zeroizing::new(0u32);
45    for (index, byte) in bytes[..4].iter().enumerate() {
46        *word |= u32::from(*byte) << (index * 8);
47    }
48    *word
49}
50
51// Export constants for Argon2 module to use
52pub(crate) const BLAKE2B_IV: [u64; 8] = [
53    0x6A09_E667_F3BC_C908,
54    0xBB67_AE85_84CA_A73B,
55    0x3C6E_F372_FE94_F82B,
56    0xA54F_F53A_5F1D_36F1,
57    0x510E_527F_ADE6_82D1,
58    0x9B05_688C_2B3E_6C1F,
59    0x1F83_D9AB_FB41_BD6B,
60    0x5BE0_CD19_137E_2179,
61];
62
63/// Message‑word permutation schedule (σ) for each of the 12 rounds
64const BLAKE2B_SIGMA: [[usize; 16]; BLAKE2B_ROUNDS] = [
65    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
66    [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
67    [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
68    [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
69    [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
70    [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
71    [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
72    [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
73    [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
74    [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
75    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
76    [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
77];
78
79// ─────────────────────────────────────────────────────────────────────────────
80// Marker type implementing the HashAlgorithm trait
81// ─────────────────────────────────────────────────────────────────────────────
82#[allow(missing_docs)]
83pub enum Blake2bAlgorithm {}
84impl HashAlgorithm for Blake2bAlgorithm {
85    const OUTPUT_SIZE: usize = BLAKE2B_MAX_OUTPUT_SIZE;
86    const BLOCK_SIZE: usize = BLAKE2B_BLOCK_SIZE;
87    const ALGORITHM_ID: &'static str = "BLAKE2b";
88}
89
90// ─────────────────────────────────────────────────────────────────────────────
91// State structure
92// ─────────────────────────────────────────────────────────────────────────────
93#[allow(missing_docs)]
94#[derive(Clone)]
95pub struct Blake2b {
96    pub(crate) h: [u64; 8],
97    pub(crate) t: [u64; 2],
98    pub(crate) f: [u64; 2],
99    pub(crate) buf: [u8; BLAKE2B_BLOCK_SIZE],
100    pub(crate) buf_len: usize,
101    pub(crate) out_len: usize,
102    pub(crate) key: Option<SecretBuffer<BLAKE2B_KEY_SIZE>>, // present only in keyed mode
103    pub(crate) is_keyed: bool,
104}
105impl Zeroize for Blake2b {
106    fn zeroize(&mut self) {
107        self.h.zeroize();
108        self.t.zeroize();
109        self.f.zeroize();
110        self.buf.zeroize();
111        self.buf_len.zeroize();
112        self.out_len.zeroize();
113        self.key.zeroize();
114        self.is_keyed.zeroize();
115    }
116}
117impl Drop for Blake2b {
118    fn drop(&mut self) {
119        self.zeroize();
120    }
121}
122
123// ─────────────────────────────────────────────────────────────────────────────
124// Constructors
125// ─────────────────────────────────────────────────────────────────────────────
126impl Blake2b {
127    /// Generic constructor (non‑keyed) with configurable output length.
128    pub fn with_output_size(out_len: usize) -> Self {
129        if !(1..=BLAKE2B_MAX_OUTPUT_SIZE).contains(&out_len) {
130            panic!("Blake2b output size must be between 1 and 64 bytes");
131        }
132        let mut instance = Self {
133            h: BLAKE2B_IV,
134            t: [0; 2],
135            f: [0; 2],
136            buf: [0; BLAKE2B_BLOCK_SIZE],
137            buf_len: 0,
138            out_len,
139            key: None,
140            is_keyed: false,
141        };
142        instance.h[0] ^= 0x0101_0000u64 | out_len as u64;
143        instance
144    }
145
146    /// Generic constructor with a fully specified parameter block.
147    ///
148    /// The parameter block is a 64-byte array that controls the Blake2b configuration.
149    /// This is primarily used for specialized hash constructions.
150    ///
151    /// # Arguments
152    /// * `param` - The 64-byte parameter block
153    /// * `out_len` - The desired output length in bytes
154    pub fn with_parameter_block(param: [u8; 64], out_len: usize) -> Self {
155        if !(1..=BLAKE2B_MAX_OUTPUT_SIZE).contains(&out_len) {
156            panic!("Blake2b output size must be between 1 and 64 bytes");
157        }
158
159        let mut instance = Self {
160            h: BLAKE2B_IV,
161            t: [0; 2],
162            f: [0; 2],
163            buf: [0; BLAKE2B_BLOCK_SIZE],
164            buf_len: 0,
165            out_len,
166            key: None,
167            is_keyed: false,
168        };
169        for (i, chunk) in param.chunks_exact(8).enumerate() {
170            instance.h[i] ^= read_u64_le(chunk);
171        }
172        instance
173    }
174
175    /// Creates a new Blake2b instance with a key (keyed mode).
176    ///
177    /// # Arguments
178    ///
179    /// * `key` - The key bytes (must be between 1 and 64 bytes)
180    /// * `out_len` - The desired output size in bytes (must be between 1 and 64)
181    pub fn with_key(key: &[u8], out_len: usize) -> Result<Self> {
182        if !(1..=BLAKE2B_MAX_OUTPUT_SIZE).contains(&out_len) {
183            return Err(Error::param(
184                "out_len",
185                "BLAKE2b output size must be between 1 and 64 bytes",
186            ));
187        }
188        if key.is_empty() || key.len() > BLAKE2B_KEY_SIZE {
189            return Err(Error::param(
190                "key",
191                "Key length must be between 1 and 64 bytes",
192            ));
193        }
194
195        // Store the original key in SecretBuffer
196        let mut key_secret_buf = SecretBuffer::<BLAKE2B_KEY_SIZE>::zeroed();
197        key_secret_buf.as_mut()[..key.len()].copy_from_slice(key);
198
199        let param0 = (out_len as u64)               // digest_length (byte 0)
200                   | ((key.len() as u64) << 8)      // key_length (byte 1)
201                   | (1u64 << 16)                   // fanout = 1 (byte 2)
202                   | (1u64 << 24); // depth = 1 (byte 3)
203
204        let mut blake2b = Blake2b {
205            h: BLAKE2B_IV,
206            t: [0; 2],
207            f: [0; 2],
208            buf: [0; BLAKE2B_BLOCK_SIZE],
209            buf_len: 0,
210            out_len,
211            key: Some(key_secret_buf),
212            is_keyed: true,
213        };
214        blake2b.h[0] ^= param0;
215
216        // If keyed, process the key block first.
217        let mut key_block_padded = Zeroizing::new([0u8; BLAKE2B_BLOCK_SIZE]);
218        key_block_padded[..key.len()].copy_from_slice(key);
219        blake2b.update_internal(&*key_block_padded)?;
220
221        Ok(blake2b)
222    }
223
224    // --- internal functions ---
225    // -------------------------------------------------------------------------
226    //  Standard BLAKE2b quarter-round (RFC-7693, §3.2, Figure 3)
227    // -------------------------------------------------------------------------
228    #[inline(always)]
229    fn blake2b_g(v: &mut [u64; 16], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) {
230        v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
231        v[d] = (v[d] ^ v[a]).rotate_right(32);
232        v[c] = v[c].wrapping_add(v[d]);
233        v[b] = (v[b] ^ v[c]).rotate_right(24);
234        v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
235        v[d] = (v[d] ^ v[a]).rotate_right(16);
236        v[c] = v[c].wrapping_add(v[d]);
237        v[b] = (v[b] ^ v[c]).rotate_right(63);
238    }
239
240    fn compress(&mut self, last: bool) -> Result<()> {
241        let mut v = Zeroizing::new([0u64; 16]);
242        v[..8].copy_from_slice(&self.h);
243        v[8..].copy_from_slice(&BLAKE2B_IV);
244        v[12] ^= self.t[0];
245        v[13] ^= self.t[1];
246        if last {
247            v[14] ^= 0xFFFF_FFFF_FFFF_FFFF;
248        } // RFC 7693 §3.2, step 3
249
250        let mut m = Zeroizing::new([0u64; 16]);
251        for (i, elem) in m.iter_mut().enumerate().take(16) {
252            let idx = i * 8;
253            validate::max_length("BLAKE2b buffer slice", idx + 8, self.buf.len())?;
254            *elem = read_u64_le(&self.buf[idx..idx + 8]);
255        }
256        for s in BLAKE2B_SIGMA.iter().take(BLAKE2B_ROUNDS) {
257            Self::blake2b_g(&mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]);
258            Self::blake2b_g(&mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]);
259            Self::blake2b_g(&mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]);
260            Self::blake2b_g(&mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]);
261            Self::blake2b_g(&mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]);
262            Self::blake2b_g(&mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]);
263            Self::blake2b_g(&mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]);
264            Self::blake2b_g(&mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]);
265        }
266        for i in 0..8 {
267            self.h[i] ^= v[i] ^ v[i + 8];
268        }
269        Ok(())
270    }
271
272    fn update_internal(&mut self, mut input: &[u8]) -> Result<()> {
273        while !input.is_empty() {
274            let fill = min(input.len(), BLAKE2B_BLOCK_SIZE - self.buf_len);
275            self.buf[self.buf_len..self.buf_len + fill].copy_from_slice(&input[..fill]);
276            self.buf_len += fill;
277            input = &input[fill..];
278
279            if self.buf_len == BLAKE2B_BLOCK_SIZE {
280                if input.is_empty() {
281                    // Don't compress yet - keep the full block for finalization
282                    break;
283                }
284                // Not the last block -> normal, non-final compression
285                let inc = BLAKE2B_BLOCK_SIZE as u64;
286                self.t[0] = self.t[0].wrapping_add(inc);
287                if self.t[0] < inc {
288                    self.t[1] = self.t[1].wrapping_add(1);
289                }
290                self.compress(false)?;
291                self.buf.zeroize();
292                self.buf_len = 0;
293            }
294        }
295        Ok(())
296    }
297
298    fn finalize_internal(&mut self) -> Result<Zeroizing<[u8; BLAKE2B_MAX_OUTPUT_SIZE]>> {
299        // At this point, buffer always contains data (either partial or full block)
300        let inc = self.buf_len as u64;
301        self.t[0] = self.t[0].wrapping_add(inc);
302        if self.t[0] < inc {
303            self.t[1] = self.t[1].wrapping_add(1);
304        }
305
306        // Pad any remainder with zeros (does nothing if buf_len == BLAKE2B_BLOCK_SIZE)
307        for b in &mut self.buf[self.buf_len..] {
308            *b = 0;
309        }
310        self.compress(true)?;
311
312        // Produce the digest
313        let mut out = Zeroizing::new([0u8; BLAKE2B_MAX_OUTPUT_SIZE]);
314        for (word_index, &word) in self.h.iter().enumerate() {
315            for byte in 0..8 {
316                let output_index = word_index * 8 + byte;
317                if output_index < self.out_len {
318                    out[output_index] = (word >> (byte * 8)) as u8;
319                }
320            }
321        }
322        self.zeroize();
323        Ok(out)
324    }
325}
326
327impl HashFunction for Blake2b {
328    type Algorithm = Blake2bAlgorithm;
329    type Output = Digest<BLAKE2B_MAX_OUTPUT_SIZE>;
330
331    fn new() -> Self {
332        Blake2b::with_output_size(BLAKE2B_MAX_OUTPUT_SIZE)
333    }
334
335    fn update(&mut self, input: &[u8]) -> Result<&mut Self> {
336        self.update_internal(input)?;
337        Ok(self)
338    }
339
340    fn finalize(&mut self) -> Result<Self::Output> {
341        let out_len = self.out_len;
342        let hash = self.finalize_internal()?;
343        let mut digest = Digest::<BLAKE2B_MAX_OUTPUT_SIZE>::zeroed_with_len(out_len);
344        digest.as_mut().copy_from_slice(&hash[..out_len]);
345        Ok(digest)
346    }
347
348    fn output_size() -> usize {
349        Self::Algorithm::OUTPUT_SIZE
350    }
351    fn block_size() -> usize {
352        Self::Algorithm::BLOCK_SIZE
353    }
354    fn name() -> String {
355        Self::Algorithm::ALGORITHM_ID.to_string()
356    }
357}
358
359/// BLAKE2s constants
360const BLAKE2S_BLOCK_SIZE: usize = 64;
361const BLAKE2S_MAX_OUTPUT_SIZE: usize = 32;
362const BLAKE2S_ROUNDS: usize = 10;
363const BLAKE2S_KEY_SIZE: usize = 32; // Maximum key size for keyed mode
364const BLAKE2S_IV: [u32; 8] = [
365    0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
366];
367const BLAKE2S_SIGMA: [[usize; 16]; BLAKE2S_ROUNDS] = [
368    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
369    [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
370    [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
371    [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
372    [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
373    [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
374    [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
375    [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
376    [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
377    [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
378];
379
380/// Define Blake2s algorithm marker type
381pub enum Blake2sAlgorithm {}
382
383/// Implement HashAlgorithm for Blake2s
384impl HashAlgorithm for Blake2sAlgorithm {
385    const OUTPUT_SIZE: usize = BLAKE2S_MAX_OUTPUT_SIZE;
386    const BLOCK_SIZE: usize = BLAKE2S_BLOCK_SIZE;
387    const ALGORITHM_ID: &'static str = "BLAKE2s";
388}
389
390/// BLAKE2s state
391#[derive(Clone)]
392pub struct Blake2s {
393    h: [u32; 8],
394    t: [u32; 2],
395    f: [u32; 2],
396    buf: [u8; BLAKE2S_BLOCK_SIZE],
397    buf_len: usize,
398    out_len: usize,
399    key: Option<SecretBuffer<BLAKE2S_KEY_SIZE>>, // Optional key for keyed mode
400    is_keyed: bool,
401}
402
403impl Zeroize for Blake2s {
404    fn zeroize(&mut self) {
405        self.h.zeroize();
406        self.t.zeroize();
407        self.f.zeroize();
408        self.buf.zeroize();
409        self.buf_len.zeroize();
410        self.out_len.zeroize();
411        self.key.zeroize();
412        self.is_keyed.zeroize();
413    }
414}
415
416// Manually implement zeroize on drop for additional security
417impl Drop for Blake2s {
418    fn drop(&mut self) {
419        self.zeroize();
420    }
421}
422
423impl Blake2s {
424    /// Creates a new Blake2s instance with a custom output size.
425    ///
426    /// # Arguments
427    ///
428    /// * `out_len` - The desired output size in bytes (must be between 1 and 32)
429    ///
430    /// # Panics
431    ///
432    /// This function may panic if `out_len` is 0 or greater than 32.
433    pub fn with_output_size(out_len: usize) -> Self {
434        if out_len == 0 || out_len > BLAKE2S_MAX_OUTPUT_SIZE {
435            panic!("Blake2s output size must be between 1 and 32 bytes");
436        }
437        let param0 = (out_len as u32) | (1u32 << 16) | (1u32 << 24); // 0x01010000 | out_len
438        let mut instance = Blake2s {
439            h: BLAKE2S_IV,
440            t: [0; 2],
441            f: [0; 2],
442            buf: [0; BLAKE2S_BLOCK_SIZE],
443            buf_len: 0,
444            out_len,
445            key: None,
446            is_keyed: false,
447        };
448        instance.h[0] ^= param0;
449        instance
450    }
451
452    /// Creates a new Blake2s instance with a key (keyed mode).
453    ///
454    /// # Arguments
455    ///
456    /// * `key` - The key bytes (must be between 1 and 32 bytes)
457    /// * `out_len` - The desired output size in bytes (must be between 1 and 32)
458    pub fn with_key(key: &[u8], out_len: usize) -> Result<Self> {
459        if !(1..=BLAKE2S_MAX_OUTPUT_SIZE).contains(&out_len) {
460            return Err(Error::param(
461                "out_len",
462                "BLAKE2s output size must be between 1 and 32 bytes",
463            ));
464        }
465        if key.is_empty() || key.len() > BLAKE2S_KEY_SIZE {
466            return Err(Error::param(
467                "key",
468                "Key length must be between 1 and 32 bytes",
469            ));
470        }
471
472        // Store the original key in SecretBuffer
473        let mut key_secret_buf = SecretBuffer::<BLAKE2S_KEY_SIZE>::zeroed();
474        key_secret_buf.as_mut()[..key.len()].copy_from_slice(key);
475
476        // Use | for parameter construction instead of ^ to ensure correct parameter block
477        let param0 = (out_len as u32)             // digest_length (byte 0)
478                   | ((key.len() as u32) << 8)    // key_length (byte 1)
479                   | (1u32 << 16)                 // fanout = 1 (byte 2)
480                   | (1u32 << 24); // depth = 1 (byte 3)
481
482        let mut blake2s = Blake2s {
483            h: BLAKE2S_IV,
484            t: [0; 2],
485            f: [0; 2],
486            buf: [0; BLAKE2S_BLOCK_SIZE],
487            buf_len: 0,
488            out_len,
489            key: Some(key_secret_buf),
490            is_keyed: true,
491        };
492        blake2s.h[0] ^= param0;
493
494        // If keyed, process the key block first.
495        // The key K is padded with zero bytes to fill a full block (64 bytes for Blake2s).
496        let mut key_block_padded = Zeroizing::new([0u8; BLAKE2S_BLOCK_SIZE]);
497        key_block_padded[..key.len()].copy_from_slice(key);
498
499        blake2s.update_internal(&*key_block_padded)?;
500
501        Ok(blake2s)
502    }
503
504    fn g(v: &mut [u32; 16], a: usize, b: usize, c: usize, d: usize, x: u32, y: u32) {
505        v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
506        v[d] = (v[d] ^ v[a]).rotate_right(16);
507        v[c] = v[c].wrapping_add(v[d]);
508        v[b] = (v[b] ^ v[c]).rotate_right(12);
509        v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
510        v[d] = (v[d] ^ v[a]).rotate_right(8);
511        v[c] = v[c].wrapping_add(v[d]);
512        v[b] = (v[b] ^ v[c]).rotate_right(7);
513    }
514
515    fn compress(&mut self, last: bool) -> Result<()> {
516        let mut v = Zeroizing::new([0u32; 16]);
517        v[..8].copy_from_slice(&self.h);
518        v[8..].copy_from_slice(&BLAKE2S_IV);
519        v[12] ^= self.t[0];
520        v[13] ^= self.t[1];
521        if last {
522            v[14] = !v[14];
523        }
524
525        let mut m = Zeroizing::new([0u32; 16]);
526        for (i, elem) in m.iter_mut().enumerate().take(16) {
527            let idx = i * 4;
528            // Validate buffer bounds
529            validate::max_length("BLAKE2s buffer slice", idx + 4, self.buf.len())?;
530
531            *elem = read_u32_le(&self.buf[idx..idx + 4]);
532        }
533
534        // Use EphemeralSecret to ensure intermediate values are zeroized
535        for s in BLAKE2S_SIGMA.iter().take(BLAKE2S_ROUNDS) {
536            Self::g(&mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]);
537            Self::g(&mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]);
538            Self::g(&mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]);
539            Self::g(&mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]);
540            Self::g(&mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]);
541            Self::g(&mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]);
542            Self::g(&mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]);
543            Self::g(&mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]);
544        }
545
546        for i in 0..8 {
547            self.h[i] ^= v[i] ^ v[i + 8];
548        }
549
550        Ok(())
551    }
552
553    fn update_internal(&mut self, mut input: &[u8]) -> Result<()> {
554        while !input.is_empty() {
555            let fill = min(input.len(), BLAKE2S_BLOCK_SIZE - self.buf_len);
556            self.buf[self.buf_len..self.buf_len + fill].copy_from_slice(&input[..fill]);
557            self.buf_len += fill;
558            input = &input[fill..];
559
560            if self.buf_len == BLAKE2S_BLOCK_SIZE {
561                if input.is_empty() {
562                    // Don't compress yet - keep the full block for finalization
563                    break;
564                }
565                // Not the last block -> normal, non-final compression
566                let inc = BLAKE2S_BLOCK_SIZE as u32;
567                self.t[0] = self.t[0].wrapping_add(inc);
568                if self.t[0] < inc {
569                    self.t[1] = self.t[1].wrapping_add(1);
570                }
571                self.compress(false)?;
572                self.buf.zeroize();
573                self.buf_len = 0;
574            }
575        }
576        Ok(())
577    }
578
579    fn finalize_internal(&mut self) -> Result<Zeroizing<[u8; BLAKE2S_MAX_OUTPUT_SIZE]>> {
580        // At this point, buffer always contains data (either partial or full block)
581        let inc = self.buf_len as u32;
582        self.t[0] = self.t[0].wrapping_add(inc);
583        if self.t[0] < inc {
584            self.t[1] = self.t[1].wrapping_add(1);
585        }
586
587        // Pad any remainder with zeros (does nothing if buf_len == BLAKE2S_BLOCK_SIZE)
588        for b in &mut self.buf[self.buf_len..] {
589            *b = 0;
590        }
591        self.compress(true)?;
592
593        // Produce the digest
594        let mut out = Zeroizing::new([0u8; BLAKE2S_MAX_OUTPUT_SIZE]);
595        for (word_index, &word) in self.h.iter().enumerate() {
596            for byte in 0..4 {
597                let output_index = word_index * 4 + byte;
598                if output_index < self.out_len {
599                    out[output_index] = (word >> (byte * 8)) as u8;
600                }
601            }
602        }
603        self.zeroize();
604        Ok(out)
605    }
606}
607
608impl HashFunction for Blake2s {
609    type Algorithm = Blake2sAlgorithm;
610    type Output = Digest<BLAKE2S_MAX_OUTPUT_SIZE>;
611
612    fn new() -> Self {
613        Blake2s::with_output_size(BLAKE2S_MAX_OUTPUT_SIZE)
614    }
615
616    fn update(&mut self, input: &[u8]) -> Result<&mut Self> {
617        self.update_internal(input)?;
618        Ok(self)
619    }
620
621    fn finalize(&mut self) -> Result<Self::Output> {
622        let out_len = self.out_len;
623        let hash = self.finalize_internal()?;
624        let mut digest = Digest::<BLAKE2S_MAX_OUTPUT_SIZE>::zeroed_with_len(out_len);
625        digest.as_mut().copy_from_slice(&hash[..out_len]);
626        Ok(digest)
627    }
628
629    fn output_size() -> usize {
630        Self::Algorithm::OUTPUT_SIZE
631    }
632
633    fn block_size() -> usize {
634        Self::Algorithm::BLOCK_SIZE
635    }
636
637    fn name() -> String {
638        Self::Algorithm::ALGORITHM_ID.to_string()
639    }
640}
641
642// Implement SecureZeroingType for Blake2b and Blake2s
643impl SecureZeroingType for Blake2b {
644    fn zeroed() -> Self {
645        Blake2b::with_output_size(BLAKE2B_MAX_OUTPUT_SIZE)
646    }
647
648    fn secure_clone(&self) -> Self {
649        self.clone()
650    }
651}
652
653impl SecureZeroingType for Blake2s {
654    fn zeroed() -> Self {
655        Blake2s::with_output_size(BLAKE2S_MAX_OUTPUT_SIZE)
656    }
657
658    fn secure_clone(&self) -> Self {
659        self.clone()
660    }
661}
662
663#[cfg(test)]
664mod tests;