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