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}