Skip to main content

lib_q_stark_shake256/
lib.rs

1//! SHAKE256 adapter for lib-Q STARK implementation.
2//!
3//! This module provides an implementation of the `CryptographicHasher` trait
4//! from `lib-q-stark-symmetric` using SHAKE256 from `lib-q-sha3`.
5//!
6//! # Security Considerations
7//!
8//! ## Constant-Time Guarantees
9//! SHAKE256 operations are constant-time, preventing timing attacks.
10//! The underlying SHAKE256 implementation from `lib-q-sha3` ensures that
11//! all hash operations execute in constant time regardless of input.
12//!
13//! ## Post-Quantum Security
14//! SHAKE256 is NIST-approved for post-quantum security (FIPS 202).
15//! It provides 256 bits of security against both classical and quantum attacks.
16//!
17//! ## Usage
18//! This adapter provides SHAKE256 for STARK proof generation and verification.
19//! All hash operations are suitable for use in zero-knowledge proof systems.
20
21#![no_std]
22
23extern crate alloc;
24
25use digest::{
26    ExtendableOutput,
27    Update,
28    XofReader,
29};
30use lib_q_sha3::Shake256;
31use lib_q_stark_symmetric::CryptographicHasher;
32
33/// Buffer size for streaming hash operations (4KB).
34/// This balances memory usage with update call frequency.
35const STREAM_BUFFER_SIZE: usize = 4096;
36
37/// SHAKE256 hash function adapter for STARK.
38///
39/// This implements the `CryptographicHasher` trait using SHAKE256,
40/// which is a NIST-approved post-quantum hash function.
41#[derive(Clone, Copy, Debug)]
42pub struct Shake256Hash;
43
44impl CryptographicHasher<u8, [u8; 32]> for Shake256Hash {
45    fn hash_iter<I>(&self, input: I) -> [u8; 32]
46    where
47        I: IntoIterator<Item = u8>,
48    {
49        let mut hasher = Shake256::default();
50        let mut buffer = [0u8; STREAM_BUFFER_SIZE];
51        let mut buffer_pos = 0;
52        let mut has_data = false;
53
54        // Stream input in fixed-size chunks to avoid collecting into Vec
55        for byte in input {
56            has_data = true;
57            buffer[buffer_pos] = byte;
58            buffer_pos += 1;
59
60            // When buffer is full, update hasher and reset buffer
61            if buffer_pos >= STREAM_BUFFER_SIZE {
62                hasher.update(&buffer);
63                buffer_pos = 0;
64            }
65        }
66
67        // Update with remaining data in buffer
68        if has_data && buffer_pos > 0 {
69            hasher.update(&buffer[..buffer_pos]);
70        }
71
72        let mut reader = hasher.finalize_xof();
73        let mut output = [0u8; 32];
74        reader.read(&mut output);
75        output
76    }
77
78    fn hash_iter_slices<'a, I>(&self, input: I) -> [u8; 32]
79    where
80        I: IntoIterator<Item = &'a [u8]>,
81        u8: 'a,
82    {
83        let mut hasher = Shake256::default();
84        for chunk in input {
85            hasher.update(chunk);
86        }
87
88        let mut reader = hasher.finalize_xof();
89        let mut output = [0u8; 32];
90        reader.read(&mut output);
91        output
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use alloc::vec::Vec;
98
99    use super::*;
100
101    #[test]
102    fn test_shake256_hash() {
103        let hasher = Shake256Hash;
104        let input = b"test input";
105        let output = hasher.hash_slice(input);
106
107        // Verify output is 32 bytes
108        assert_eq!(output.len(), 32);
109
110        // Verify deterministic
111        let output2 = hasher.hash_slice(input);
112        assert_eq!(output, output2);
113    }
114
115    #[test]
116    fn test_shake256_hash_iter() {
117        let hasher = Shake256Hash;
118        let input: Vec<u8> = (0..100).collect();
119        let output = hasher.hash_iter(input.iter().copied());
120
121        assert_eq!(output.len(), 32);
122    }
123}