turboshake/
turboshake128.rs

1use crate::{branch_opt_util, error::TurboShakeError, keccak, sponge};
2
3/// TurboSHAKE128 Extendable Output Function (XOF)
4///
5/// Given any arbitrary length input, in incremental form or in one-shot form,
6/// it can produce an arbitrary long pseudo-random, deterministic output, offering
7/// at max 128-bits of security.
8///
9/// See section 1 of TurboSHAKE specification https://ia.cr/2023/342.
10#[derive(Clone)]
11pub struct TurboShake128 {
12    state: [u64; keccak::LANE_CNT],
13    offset: usize,
14    is_ready_to_squeeze: usize,
15    squeezable: usize,
16}
17
18impl Default for TurboShake128 {
19    /// Create a default instance of TurboSHAKE128 Extendable Output Function (XOF).
20    ///
21    /// # Inputs
22    ///
23    /// None
24    ///
25    /// # Returns
26    ///
27    /// A default `TurboShake128` object.
28    ///
29    /// # Example
30    ///
31    /// ```
32    /// use turboshake::TurboShake128;
33    ///
34    /// let mut ts = TurboShake128::default();
35    /// ```
36    fn default() -> Self {
37        Self {
38            state: [0u64; keccak::LANE_CNT],
39            offset: 0,
40            is_ready_to_squeeze: usize::MIN,
41            squeezable: 0,
42        }
43    }
44}
45
46impl TurboShake128 {
47    /// If you don't need multiple instances of TurboSHAKE128, feel free to pass this as domain seperator constant, during finalization.
48    pub const DEFAULT_DOMAIN_SEPARATOR: u8 = 0x1f;
49
50    const BIT_LENGTH_OF_KECCAK_PERMUTATION_STATE: usize = keccak::W * keccak::LANE_CNT;
51    const TARGET_BIT_SECURITY_LEVEL: usize = 128;
52    const CAPACITY_BITS: usize = 2 * Self::TARGET_BIT_SECURITY_LEVEL;
53    const RATE_BITS: usize = Self::BIT_LENGTH_OF_KECCAK_PERMUTATION_STATE - Self::CAPACITY_BITS;
54    const RATE_BYTES: usize = Self::RATE_BITS / u8::BITS as usize;
55
56    /// Absorbs arbitrary many input bytes into the TurboSHAKE128 sponge state.
57    /// It can be called as many times needed, as long as `finalize` has not been called.
58    ///
59    /// # Inputs
60    ///
61    /// * `msg`: An arbitrary length (including empty) slice of bytes to be absorbed.
62    ///
63    /// # Returns
64    ///
65    /// * `Result<(), TurboShakeError>`: `Ok(())` if the absorption was successful.
66    /// Returns `Err(TurboShakeError::DataAbsorptionPhaseAlreadyFinalized)` if the instance has already been finalized.
67    ///
68    /// # Example
69    ///
70    /// ```
71    /// use turboshake::TurboShake128;
72    ///
73    /// let mut ts = TurboShake128::default();
74    /// let message = b"This is a test message";
75    /// assert_eq!(ts.absorb(message), Ok(()));
76    /// ```
77    pub fn absorb(&mut self, msg: &[u8]) -> Result<(), TurboShakeError> {
78        if branch_opt_util::unlikely(self.is_ready_to_squeeze == usize::MAX) {
79            return Err(TurboShakeError::DataAbsorptionPhaseAlreadyFinalized);
80        }
81
82        sponge::absorb::<{ Self::RATE_BYTES }>(&mut self.state, &mut self.offset, msg);
83        Ok(())
84    }
85
86    /// Finalizes the TurboSHAKE128 sponge state. After all input bytes are absorbed,
87    /// the sponge can be finalized, then it can only be used for squeezing output.
88    ///
89    /// # Inputs
90    ///
91    /// * `D`: A domain separator byte.  Consider using `TurboShake128::DEFAULT_DOMAIN_SEPARATOR` if you don't need multiple instances of TurboSHAKE128.
92    ///
93    /// # Returns
94    ///
95    /// * `Result<(), TurboShakeError>`: `Ok(())` if the finalization was successful.
96    /// Returns `Err(TurboShakeError::DataAbsorptionPhaseAlreadyFinalized)` if the instance has already been finalized.
97    ///
98    /// # Example
99    ///
100    /// ```
101    /// use turboshake::TurboShake128;
102    ///
103    /// let mut ts = TurboShake128::default();
104    /// let message = b"This is a test message";
105    ///
106    /// assert_eq!(ts.absorb(message), Ok(()));
107    /// assert_eq!(ts.finalize::<{TurboShake128::DEFAULT_DOMAIN_SEPARATOR}>(), Ok(()));
108    /// ```
109    pub fn finalize<const D: u8>(&mut self) -> Result<(), TurboShakeError> {
110        // See top of page 2 of https://ia.cr/2023/342
111        const { assert!(D >= 0x01 && D <= 0x7f) };
112
113        if branch_opt_util::unlikely(self.is_ready_to_squeeze == usize::MAX) {
114            return Err(TurboShakeError::DataAbsorptionPhaseAlreadyFinalized);
115        }
116
117        sponge::finalize::<{ Self::RATE_BYTES }, { D }>(&mut self.state, &mut self.offset);
118
119        self.is_ready_to_squeeze = usize::MAX;
120        self.squeezable = Self::RATE_BYTES;
121        Ok(())
122    }
123
124    /// Squeezes arbitrary many output bytes from the TurboSHAKE128 sponge state.
125    /// Only after the sponge state is finalized, it can be squeezed from.
126    ///
127    /// # Inputs
128    ///
129    /// * `out`: An arbitrary length (including empty) mutable slice of bytes to be filled with squeezed output.
130    ///
131    /// # Outputs
132    ///
133    /// * `Result<(), TurboShakeError>`: `Ok(())` if the squeezing was successful.
134    /// Returns `Err(TurboShakeError::StillInDataAbsorptionPhase)` if the instance has not yet been finalized.
135    ///
136    /// # Example
137    ///
138    /// ```
139    /// use turboshake::TurboShake128;
140    ///
141    /// let mut ts = TurboShake128::default();
142    /// let message = b"This is a test message";
143    ///
144    /// assert_eq!(ts.absorb(message), Ok(()));
145    /// assert_eq!(ts.finalize::<{TurboShake128::DEFAULT_DOMAIN_SEPARATOR}>(), Ok(()));
146    ///
147    /// let mut output = [0u8; 32];
148    /// assert_eq!(ts.squeeze(&mut output), Ok(()));
149    /// ```
150    pub fn squeeze(&mut self, out: &mut [u8]) -> Result<(), TurboShakeError> {
151        if branch_opt_util::unlikely(self.is_ready_to_squeeze != usize::MAX) {
152            return Err(TurboShakeError::StillInDataAbsorptionPhase);
153        }
154
155        sponge::squeeze::<{ Self::RATE_BYTES }>(&mut self.state, &mut self.squeezable, out);
156        Ok(())
157    }
158}