Skip to main content

lib_q_hash/
kmac.rs

1//! KMAC (KECCAK Message Authentication Code) implementation
2//!
3//! This module provides KMAC128 and KMAC256 implementations as specified in SP800-185.
4//! KMAC is a PRF and keyed hash function based on cSHAKE.
5//!
6//! # Security note
7//!
8//! KMAC initialization absorbs `bytepad(encode_string(K), rate)` directly into the sponge
9//! without heap-backed temporary buffers containing key material. This reduces key exposure
10//! in freed/reallocated heap regions and aligns with audit expectations for secret handling.
11//!
12//! For MAC equality checks, use [`Kmac128::verify`](Kmac128::verify) /
13//! [`Kmac256::verify`](Kmac256::verify) instead of comparing `finalize` output with `==`,
14//! which is not constant-time.
15//!
16//! Fixed-length outputs from [`Kmac128::finalize`], [`Kmac128::finalize_with_length`], and peers
17//! are capped by [`crate::MAX_SP800185_FIXED_OUTPUT_BYTES`]; use [`Kmac128::xof`] for longer
18//! squeeze output.
19
20use alloc::vec;
21use alloc::vec::Vec;
22use core::fmt;
23
24use digest::block_api::{
25    AlgorithmName,
26    Block,
27    BlockSizeUser,
28    BufferKindUser,
29    Eager,
30    UpdateCore,
31};
32use digest::common::hazmat::{
33    DeserializeStateError,
34    SerializableState,
35    SerializedState,
36};
37use digest::consts::{
38    U16,
39    U32,
40    U136,
41    U168,
42    U400,
43};
44use digest::{
45    CollisionResistance,
46    ExtendableOutput,
47    HashMarker,
48    Reset,
49    Update,
50    XofReader,
51};
52use subtle::{
53    Choice,
54    ConstantTimeEq,
55};
56use zeroize::Zeroize;
57
58use crate::cshake::{
59    CShake128,
60    CShake128Reader,
61    CShake256,
62    CShake256Reader,
63};
64use crate::utils::{
65    MAX_SP800185_FIXED_OUTPUT_BYTES,
66    left_encode,
67    right_encode,
68};
69
70/// KMAC128 implementation
71#[derive(Clone)]
72pub struct Kmac128 {
73    inner: CShake128,
74}
75
76/// KMAC256 implementation
77#[derive(Clone)]
78pub struct Kmac256 {
79    inner: CShake256,
80}
81
82/// KMAC128 XOF reader
83#[derive(Clone)]
84pub struct Kmac128Reader {
85    inner: CShake128Reader,
86}
87
88/// KMAC256 XOF reader
89#[derive(Clone)]
90pub struct Kmac256Reader {
91    inner: CShake256Reader,
92}
93
94macro_rules! impl_kmac {
95    (
96        $name:ident, $inner_type:ident, $reader_name:ident, $inner_reader_type:ident, $rate:ident, $rate_expr:expr, $alg_name:expr
97    ) => {
98        impl $name {
99            /// Creates a new KMAC instance with the given key and customization string
100            pub fn new(key: &[u8], custom: &[u8]) -> Self {
101                let mut kmac = Self {
102                    inner: $inner_type::new_with_function_name(b"KMAC", custom),
103                };
104                kmac.init(key, $rate_expr);
105                kmac
106            }
107
108            fn init(&mut self, key: &[u8], rate: usize) {
109                // Stream bytepad(encode_string(K), rate) directly into the
110                // sponge so key material never lands in heap-allocated
111                // temporaries.
112                let mut enc_buf = [0u8; 9];
113                let mut total = 0usize;
114
115                // bytepad outer: left_encode(rate)
116                let le = left_encode(rate as u64, &mut enc_buf);
117                Update::update(&mut self.inner, le);
118                total += le.len();
119
120                // encode_string(K) = left_encode(len(K)*8) || K
121                let le = left_encode((key.len() * 8) as u64, &mut enc_buf);
122                Update::update(&mut self.inner, le);
123                total += le.len();
124
125                Update::update(&mut self.inner, key);
126                total += key.len();
127
128                // Zero-pad to a multiple of `rate` with stack memory.
129                let padding = (rate - (total % rate)) % rate;
130                if padding > 0 {
131                    const ZEROS: [u8; 168] = [0u8; 168];
132                    Update::update(&mut self.inner, &ZEROS[..padding]);
133                }
134            }
135
136            /// Update with data
137            pub fn update(&mut self, data: &[u8]) {
138                Update::update(&mut self.inner, data);
139            }
140
141            /// Finalize with specified output length.
142            ///
143            /// `output.len()` must not exceed [`MAX_SP800185_FIXED_OUTPUT_BYTES`]. For longer
144            /// output, use [`Self::xof`].
145            ///
146            /// Returns [`None`] if `output.len()` is greater than
147            /// [`MAX_SP800185_FIXED_OUTPUT_BYTES`].
148            pub fn finalize(mut self, output: &mut [u8]) -> Option<()> {
149                if output.len() > MAX_SP800185_FIXED_OUTPUT_BYTES {
150                    return None;
151                }
152                self.with_bitlength((output.len() * 8) as u64);
153                ExtendableOutput::finalize_xof_into(self.inner, output);
154                Some(())
155            }
156
157            /// Finalize and compare the MAC to `expected` in constant time.
158            ///
159            /// The MAC output length is `expected.len()` (same encoding as [`Self::finalize`]
160            /// with an output buffer of that length). The computed MAC is zeroized before
161            /// returning.
162            ///
163            /// If `expected.len()` is greater than [`MAX_SP800185_FIXED_OUTPUT_BYTES`], this
164            /// returns a failed comparison without allocating (or finalizing with that length), so
165            /// attacker-controlled lengths cannot force large allocations.
166            ///
167            /// Combine or inspect the result with `subtle` APIs before branching on validity if
168            /// control-flow timing is a concern.
169            pub fn verify(mut self, expected: &[u8]) -> Choice {
170                if expected.len() > MAX_SP800185_FIXED_OUTPUT_BYTES {
171                    return Choice::from(0u8);
172                }
173                let mut mac = vec![0u8; expected.len()];
174                self.with_bitlength((mac.len() * 8) as u64);
175                ExtendableOutput::finalize_xof_into(self.inner, &mut mac);
176                let ok = mac.ct_eq(expected);
177                mac.zeroize();
178                ok
179            }
180
181            /// Finalize with specified output length and return as [`Vec`].
182            ///
183            /// Returns [`None`] if `output_len` is greater than [`MAX_SP800185_FIXED_OUTPUT_BYTES`]
184            /// (no allocation). For longer output, use [`Self::xof`].
185            pub fn finalize_with_length(mut self, output_len: usize) -> Option<Vec<u8>> {
186                if output_len > MAX_SP800185_FIXED_OUTPUT_BYTES {
187                    return None;
188                }
189                let mut output = vec![0u8; output_len];
190                self.with_bitlength((output_len * 8) as u64);
191                ExtendableOutput::finalize_xof_into(self.inner, &mut output);
192                Some(output)
193            }
194
195            /// Returns an XOF reader for variable-length output.
196            ///
197            /// SP 800-185 encodes XOF mode with `right_encode(0)` (output bit length zero) before
198            /// squeezing.
199            ///
200            /// This consumes `self` and finalizes the sponge; you cannot call [`Self::update`]
201            /// afterward on this value.
202            pub fn xof(mut self) -> $reader_name {
203                self.with_bitlength(0);
204                $reader_name {
205                    inner: ExtendableOutput::finalize_xof(self.inner),
206                }
207            }
208
209            fn with_bitlength(&mut self, bitlength: u64) {
210                let mut enc_buf = [0u8; 9];
211                let length_encoded = right_encode(bitlength, &mut enc_buf);
212                Update::update(&mut self.inner, length_encoded);
213            }
214        }
215
216        // Digest trait implementations
217        impl BlockSizeUser for $name {
218            type BlockSize = $rate;
219        }
220
221        impl BufferKindUser for $name {
222            type BufferKind = Eager;
223        }
224
225        impl HashMarker for $name {}
226
227        impl Update for $name {
228            #[inline]
229            fn update(&mut self, data: &[u8]) {
230                Update::update(&mut self.inner, data);
231            }
232        }
233
234        impl UpdateCore for $name {
235            #[inline]
236            fn update_blocks(&mut self, blocks: &[Block<Self>]) {
237                for block in blocks {
238                    self.inner.update(block);
239                }
240            }
241        }
242
243        impl Reset for $name {
244            #[inline]
245            fn reset(&mut self) {
246                self.inner.reset();
247            }
248        }
249
250        impl AlgorithmName for $name {
251            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
252                f.write_str($alg_name)
253            }
254        }
255
256        impl fmt::Debug for $name {
257            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258                f.write_str(concat!(stringify!($name), " { ... }"))
259            }
260        }
261
262        #[cfg(feature = "zeroize")]
263        impl digest::zeroize::ZeroizeOnDrop for $name {}
264
265        // Implement Default trait
266        impl Default for $name {
267            fn default() -> Self {
268                Self::new(b"", b"")
269            }
270        }
271
272        // Implement XofReader for the reader type
273        impl XofReader for $reader_name {
274            fn read(&mut self, buf: &mut [u8]) {
275                self.inner.read(buf);
276            }
277        }
278
279        impl fmt::Debug for $reader_name {
280            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281                f.write_str(concat!(stringify!($reader_name), " { ... }"))
282            }
283        }
284    };
285}
286
287impl_kmac!(
288    Kmac128,
289    CShake128,
290    Kmac128Reader,
291    CShake128Reader,
292    U168,
293    168usize,
294    "KMAC128"
295);
296impl_kmac!(
297    Kmac256,
298    CShake256,
299    Kmac256Reader,
300    CShake256Reader,
301    U136,
302    136usize,
303    "KMAC256"
304);
305
306impl CollisionResistance for Kmac128 {
307    type CollisionResistance = U16;
308}
309
310impl CollisionResistance for Kmac256 {
311    type CollisionResistance = U32;
312}
313
314// Add SerializableState for KMAC types
315impl SerializableState for Kmac128 {
316    type SerializedStateSize = U400;
317
318    fn serialize(&self) -> SerializedState<Self> {
319        self.inner.serialize()
320    }
321
322    fn deserialize(
323        serialized_state: &SerializedState<Self>,
324    ) -> Result<Self, DeserializeStateError> {
325        let inner = CShake128::deserialize(serialized_state)?;
326        Ok(Self { inner })
327    }
328}
329
330impl SerializableState for Kmac256 {
331    type SerializedStateSize = U400;
332
333    fn serialize(&self) -> SerializedState<Self> {
334        self.inner.serialize()
335    }
336
337    fn deserialize(
338        serialized_state: &SerializedState<Self>,
339    ) -> Result<Self, DeserializeStateError> {
340        let inner = CShake256::deserialize(serialized_state)?;
341        Ok(Self { inner })
342    }
343}
344
345#[cfg(test)]
346mod tests {
347    use hex_literal::hex;
348
349    use super::*;
350
351    fn nist_kmac_key() -> [u8; 32] {
352        let mut key = [0u8; 32];
353        for (idx, b) in key.iter_mut().enumerate() {
354            *b = 0x40 + (idx as u8);
355        }
356        key
357    }
358
359    fn nist_kmac_short_data() -> [u8; 4] {
360        [0x00, 0x01, 0x02, 0x03]
361    }
362
363    fn nist_kmac_long_data() -> Vec<u8> {
364        (0x00..=0xC7).collect()
365    }
366
367    fn kmac128_reference(key: &[u8], custom: &[u8], data: &[u8], out_len: usize) -> Vec<u8> {
368        let mut inner = CShake128::new_with_function_name(b"KMAC", custom);
369        let mut enc_buf = [0u8; 9];
370        let mut total = 0usize;
371
372        let le = left_encode(168, &mut enc_buf);
373        inner.update(le);
374        total += le.len();
375
376        let le = left_encode((key.len() * 8) as u64, &mut enc_buf);
377        inner.update(le);
378        total += le.len();
379
380        inner.update(key);
381        total += key.len();
382
383        let padding = (168 - (total % 168)) % 168;
384        if padding > 0 {
385            const ZEROS: [u8; 168] = [0u8; 168];
386            inner.update(&ZEROS[..padding]);
387        }
388
389        inner.update(data);
390        inner.update(right_encode((out_len * 8) as u64, &mut enc_buf));
391
392        let mut out = vec![0u8; out_len];
393        inner.finalize_xof_into(&mut out);
394        out
395    }
396
397    fn kmac256_reference(key: &[u8], custom: &[u8], data: &[u8], out_len: usize) -> Vec<u8> {
398        let mut inner = CShake256::new_with_function_name(b"KMAC", custom);
399        let mut enc_buf = [0u8; 9];
400        let mut total = 0usize;
401
402        let le = left_encode(136, &mut enc_buf);
403        inner.update(le);
404        total += le.len();
405
406        let le = left_encode((key.len() * 8) as u64, &mut enc_buf);
407        inner.update(le);
408        total += le.len();
409
410        inner.update(key);
411        total += key.len();
412
413        let padding = (136 - (total % 136)) % 136;
414        if padding > 0 {
415            const ZEROS: [u8; 136] = [0u8; 136];
416            inner.update(&ZEROS[..padding]);
417        }
418
419        inner.update(data);
420        inner.update(right_encode((out_len * 8) as u64, &mut enc_buf));
421
422        let mut out = vec![0u8; out_len];
423        inner.finalize_xof_into(&mut out);
424        out
425    }
426
427    #[test]
428    fn test_kmac128_basic() {
429        let key = b"key";
430        let custom = b"custom";
431        let data = b"test data";
432
433        let mut kmac = Kmac128::new(key, custom);
434        kmac.update(data);
435
436        let mut output = [0u8; 32];
437        kmac.finalize(&mut output).unwrap();
438        assert_ne!(output, [0u8; 32]);
439    }
440
441    #[test]
442    fn test_kmac256_basic() {
443        let key = b"key";
444        let custom = b"custom";
445        let data = b"test data";
446
447        let mut kmac = Kmac256::new(key, custom);
448        kmac.update(data);
449
450        let mut output = [0u8; 64];
451        kmac.finalize(&mut output).unwrap();
452        assert_ne!(output, [0u8; 64]);
453    }
454
455    #[test]
456    fn test_kmac_xof() {
457        let key = b"key";
458        let custom = b"custom";
459        let data = b"test data";
460
461        let mut kmac = Kmac128::new(key, custom);
462        kmac.update(data);
463
464        let mut reader = kmac.xof();
465        let mut output = [0u8; 100];
466        reader.read(&mut output);
467        assert_ne!(output, [0u8; 100]);
468    }
469
470    #[test]
471    fn test_kmac_different_keys() {
472        let custom = b"custom";
473        let data = b"test data";
474
475        let mut kmac1 = Kmac128::new(b"key1", custom);
476        kmac1.update(data);
477        let mut output1 = [0u8; 32];
478        kmac1.finalize(&mut output1).unwrap();
479
480        let mut kmac2 = Kmac128::new(b"key2", custom);
481        kmac2.update(data);
482        let mut output2 = [0u8; 32];
483        kmac2.finalize(&mut output2).unwrap();
484
485        assert_ne!(output1, output2);
486    }
487
488    #[test]
489    fn test_kmac_different_customs() {
490        let key = b"key";
491        let data = b"test data";
492
493        let mut kmac1 = Kmac128::new(key, b"custom1");
494        kmac1.update(data);
495        let mut output1 = [0u8; 32];
496        kmac1.finalize(&mut output1).unwrap();
497
498        let mut kmac2 = Kmac128::new(key, b"custom2");
499        kmac2.update(data);
500        let mut output2 = [0u8; 32];
501        kmac2.finalize(&mut output2).unwrap();
502
503        assert_ne!(output1, output2);
504    }
505
506    #[test]
507    fn test_kmac_reset() {
508        let key = b"key";
509        let custom = b"custom";
510        let data = b"test data";
511
512        let mut kmac = Kmac128::new(key, custom);
513        kmac.update(data);
514
515        // Reset and test again
516        kmac.reset();
517        kmac.update(data);
518
519        let mut output = [0u8; 32];
520        kmac.finalize(&mut output).unwrap();
521        assert_ne!(output, [0u8; 32]);
522    }
523
524    #[test]
525    fn test_kmac_default() {
526        let kmac = Kmac128::default();
527        let data = b"test data";
528
529        let mut hasher = kmac;
530        hasher.update(data);
531        let result = hasher.finalize_with_length(32).unwrap();
532        assert_eq!(result.len(), 32);
533    }
534
535    #[test]
536    fn test_kmac_serialization() {
537        let key = b"key";
538        let custom = b"custom";
539        let data = b"test data";
540
541        let mut kmac = Kmac128::new(key, custom);
542        kmac.update(data);
543
544        // Serialize the state
545        let serialized = kmac.serialize();
546
547        // Deserialize and continue
548        let mut kmac2 = Kmac128::deserialize(&serialized).unwrap();
549        kmac2.update(b"more data");
550
551        let mut output = [0u8; 32];
552        kmac2.finalize(&mut output).unwrap();
553        assert_ne!(output, [0u8; 32]);
554    }
555
556    #[test]
557    fn test_kmac128_matches_reference_construction() {
558        let key = b"auditor-sensitive-key-material";
559        let custom = b"lib-q kmac reference";
560        let data = b"input message for kmac128";
561
562        let mut kmac = Kmac128::new(key, custom);
563        kmac.update(data);
564        let mut got = [0u8; 32];
565        kmac.finalize(&mut got).unwrap();
566
567        let expected = kmac128_reference(key, custom, data, 32);
568        assert_eq!(got.as_slice(), expected.as_slice());
569    }
570
571    #[test]
572    fn test_kmac256_matches_reference_construction() {
573        let key = b"auditor-sensitive-key-material";
574        let custom = b"lib-q kmac reference";
575        let data = b"input message for kmac256";
576
577        let mut kmac = Kmac256::new(key, custom);
578        kmac.update(data);
579        let mut got = [0u8; 64];
580        kmac.finalize(&mut got).unwrap();
581
582        let expected = kmac256_reference(key, custom, data, 64);
583        assert_eq!(got.as_slice(), expected.as_slice());
584    }
585
586    #[test]
587    fn test_kmac128_nist_sample_1() {
588        let key = nist_kmac_key();
589        let data = nist_kmac_short_data();
590        let custom = b"";
591        let expected = hex!(
592            "E5780B0D3EA6F7D3A429C5706AA43A00
593             FADBD7D49628839E3187243F456EE14E"
594        );
595
596        let mut kmac = Kmac128::new(&key, custom);
597        kmac.update(&data);
598        let mut out = [0u8; 32];
599        kmac.finalize(&mut out).unwrap();
600        assert_eq!(out, expected);
601    }
602
603    #[test]
604    fn test_kmac128_nist_sample_2() {
605        let key = nist_kmac_key();
606        let data = nist_kmac_short_data();
607        let custom = b"My Tagged Application";
608        let expected = hex!(
609            "3B1FBA963CD8B0B59E8C1A6D71888B71
610             43651AF8BA0A7070C0979E2811324AA5"
611        );
612
613        let mut kmac = Kmac128::new(&key, custom);
614        kmac.update(&data);
615        let mut out = [0u8; 32];
616        kmac.finalize(&mut out).unwrap();
617        assert_eq!(out, expected);
618    }
619
620    #[test]
621    fn test_kmac128_nist_sample_3() {
622        let key = nist_kmac_key();
623        let data = nist_kmac_long_data();
624        let custom = b"My Tagged Application";
625        let expected = hex!(
626            "1F5B4E6CCA02209E0DCB5CA635B89A15
627             E271ECC760071DFD805FAA38F9729230"
628        );
629
630        let mut kmac = Kmac128::new(&key, custom);
631        kmac.update(&data);
632        let mut out = [0u8; 32];
633        kmac.finalize(&mut out).unwrap();
634        assert_eq!(out, expected);
635    }
636
637    #[test]
638    fn test_kmac256_nist_sample_4() {
639        let key = nist_kmac_key();
640        let data = nist_kmac_short_data();
641        let custom = b"My Tagged Application";
642        let expected = hex!(
643            "20C570C31346F703C9AC36C61C03CB64
644             C3970D0CFC787E9B79599D273A68D2F7
645             F69D4CC3DE9D104A351689F27CF6F595
646             1F0103F33F4F24871024D9C27773A8DD"
647        );
648
649        let mut kmac = Kmac256::new(&key, custom);
650        kmac.update(&data);
651        let mut out = [0u8; 64];
652        kmac.finalize(&mut out).unwrap();
653        assert_eq!(out, expected);
654    }
655
656    #[test]
657    fn test_kmac256_nist_sample_5() {
658        let key = nist_kmac_key();
659        let data = nist_kmac_long_data();
660        let custom = b"";
661        let expected = hex!(
662            "75358CF39E41494E949707927CEE0AF2
663             0A3FF553904C86B08F21CC414BCFD691
664             589D27CF5E15369CBBFF8B9A4C2EB178
665             00855D0235FF635DA82533EC6B759B69"
666        );
667
668        let mut kmac = Kmac256::new(&key, custom);
669        kmac.update(&data);
670        let mut out = [0u8; 64];
671        kmac.finalize(&mut out).unwrap();
672        assert_eq!(out, expected);
673    }
674
675    #[test]
676    fn test_kmac256_nist_sample_6() {
677        let key = nist_kmac_key();
678        let data = nist_kmac_long_data();
679        let custom = b"My Tagged Application";
680        let expected = hex!(
681            "B58618F71F92E1D56C1B8C55DDD7CD18
682             8B97B4CA4D99831EB2699A837DA2E4D9
683             70FBACFDE50033AEA585F1A2708510C3
684             2D07880801BD182898FE476876FC8965"
685        );
686
687        let mut kmac = Kmac256::new(&key, custom);
688        kmac.update(&data);
689        let mut out = [0u8; 64];
690        kmac.finalize(&mut out).unwrap();
691        assert_eq!(out, expected);
692    }
693
694    #[test]
695    fn test_kmac128_verify_matches_finalize() {
696        let key = nist_kmac_key();
697        let data = nist_kmac_short_data();
698        let custom = b"My Tagged Application";
699        let expected = hex!(
700            "3B1FBA963CD8B0B59E8C1A6D71888B71
701             43651AF8BA0A7070C0979E2811324AA5"
702        );
703
704        let mut kmac = Kmac128::new(&key, custom);
705        kmac.update(&data);
706        let mut finalized = [0u8; 32];
707        kmac.finalize(&mut finalized).unwrap();
708        assert_eq!(finalized.as_slice(), expected.as_slice());
709
710        let mut kmac2 = Kmac128::new(&key, custom);
711        kmac2.update(&data);
712        assert!(bool::from(kmac2.verify(&expected)));
713
714        let mut wrong = expected;
715        wrong[0] ^= 0x01;
716        let mut kmac3 = Kmac128::new(&key, custom);
717        kmac3.update(&data);
718        assert!(!bool::from(kmac3.verify(&wrong)));
719    }
720
721    #[test]
722    fn test_kmac256_verify_nist() {
723        let key = nist_kmac_key();
724        let data = nist_kmac_short_data();
725        let custom = b"My Tagged Application";
726        let expected = hex!(
727            "20C570C31346F703C9AC36C61C03CB64
728             C3970D0CFC787E9B79599D273A68D2F7
729             F69D4CC3DE9D104A351689F27CF6F595
730             1F0103F33F4F24871024D9C27773A8DD"
731        );
732
733        let mut kmac = Kmac256::new(&key, custom);
734        kmac.update(&data);
735        assert!(bool::from(kmac.verify(&expected)));
736
737        let mut wrong = expected;
738        wrong[31] ^= 0x80;
739        let mut kmac2 = Kmac256::new(&key, custom);
740        kmac2.update(&data);
741        assert!(!bool::from(kmac2.verify(&wrong)));
742    }
743
744    #[test]
745    fn test_kmac_verify_rejects_oversized_expected_without_large_alloc() {
746        let key = b"k";
747        let data = b"d";
748        let oversized = vec![0u8; MAX_SP800185_FIXED_OUTPUT_BYTES + 1];
749        let mut kmac = Kmac128::new(key, b"");
750        kmac.update(data);
751        assert!(!bool::from(kmac.verify(&oversized)));
752    }
753
754    #[test]
755    fn test_kmac_finalize_with_length_rejects_over_cap() {
756        let mut kmac = Kmac128::new(b"k", b"");
757        kmac.update(b"x");
758        assert!(
759            kmac.finalize_with_length(MAX_SP800185_FIXED_OUTPUT_BYTES + 1)
760                .is_none()
761        );
762    }
763
764    #[test]
765    fn test_kmac_finalize_rejects_over_cap_output_buffer() {
766        let mut kmac = Kmac128::new(b"k", b"");
767        kmac.update(b"x");
768        let mut out = vec![0u8; MAX_SP800185_FIXED_OUTPUT_BYTES + 1];
769        assert!(kmac.finalize(&mut out).is_none());
770    }
771
772    /// Structural (non-timing) pin on `Kmac128::verify`'s `ct_eq`-based comparison
773    /// (`kmac.rs`, `verify`). Does NOT measure wall-clock timing -- that is unmeasurable
774    /// in a unit test and out of scope per card t_043571b4. What this pins is the code
775    /// shape: `verify` must reject a mismatch regardless of which byte differs, exhaustively
776    /// over every position in a short tag, which a comparison that scans only a prefix (the
777    /// class of bug this test is designed to catch) would fail partway through.
778    #[test]
779    fn test_kmac128_verify_rejects_mismatch_at_every_byte_position() {
780        let key = b"key";
781        let data = b"data";
782        let mut kmac = Kmac128::new(key, b"custom");
783        kmac.update(data);
784        let mut good = [0u8; 32];
785        kmac.finalize(&mut good).unwrap();
786
787        for i in 0..good.len() {
788            let mut bad = good;
789            bad[i] ^= 0x01;
790            let mut kmac2 = Kmac128::new(key, b"custom");
791            kmac2.update(data);
792            assert!(
793                !bool::from(kmac2.verify(&bad)),
794                "mismatch at byte {i} was not rejected"
795            );
796        }
797    }
798
799    /// A truncated or over-long `expected` must be rejected outright, never compared
800    /// prefix-wise -- this is the length pre-check at the top of `verify`.
801    #[test]
802    fn test_kmac128_verify_rejects_wrong_length_expected() {
803        let key = b"key";
804        let data = b"data";
805        let mut kmac = Kmac128::new(key, b"custom");
806        kmac.update(data);
807        let mut good = [0u8; 32];
808        kmac.finalize(&mut good).unwrap();
809
810        let mut kmac2 = Kmac128::new(key, b"custom");
811        kmac2.update(data);
812        assert!(!bool::from(kmac2.verify(&good[..16])));
813
814        let mut over_long = good.to_vec();
815        over_long.push(0);
816        let mut kmac3 = Kmac128::new(key, b"custom");
817        kmac3.update(data);
818        assert!(!bool::from(kmac3.verify(&over_long)));
819    }
820}