dcrypt_algorithms/xof/shake/
mod.rs1#[cfg(not(feature = "std"))]
11use alloc::vec::Vec;
12use zeroize::{Zeroize, ZeroizeOnDrop};
13
14use super::ExtendableOutputFunction;
15use crate::error::{validate, Error, Result};
16
17use dcrypt_common::security::{barrier, EphemeralSecret, SecretBuffer, SecureZeroingType};
19
20const KECCAK_ROUNDS: usize = 24;
22const KECCAK_STATE_SIZE: usize = 25; const SHAKE128_RATE: usize = 168; const SHAKE256_RATE: usize = 136; const RC: [u64; KECCAK_ROUNDS] = [
30 0x0000000000000001,
31 0x0000000000008082,
32 0x800000000000808A,
33 0x8000000080008000,
34 0x000000000000808B,
35 0x0000000080000001,
36 0x8000000080008081,
37 0x8000000000008009,
38 0x000000000000008A,
39 0x0000000000000088,
40 0x0000000080008009,
41 0x000000008000000A,
42 0x000000008000808B,
43 0x800000000000008B,
44 0x8000000000008089,
45 0x8000000000008003,
46 0x8000000000008002,
47 0x8000000000000080,
48 0x000000000000800A,
49 0x800000008000000A,
50 0x8000000080008081,
51 0x8000000000008080,
52 0x0000000080000001,
53 0x8000000080008008,
54];
55
56const RHO: [u32; 24] = [
58 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
59];
60
61const PI: [usize; 24] = [
63 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
64];
65
66#[derive(Clone, Zeroize)]
68struct SecureKeccakState {
69 state: SecretBuffer<200>, }
71
72impl SecureKeccakState {
73 fn new() -> Self {
74 Self {
75 state: SecretBuffer::zeroed(),
76 }
77 }
78
79 fn from_u64_array(array: [u64; KECCAK_STATE_SIZE]) -> Self {
80 let mut bytes = [0u8; 200];
81 for (i, &word) in array.iter().enumerate() {
82 let word_bytes = word.to_le_bytes();
83 bytes[i * 8..(i + 1) * 8].copy_from_slice(&word_bytes);
84 }
85 Self {
86 state: SecretBuffer::new(bytes),
87 }
88 }
89
90 fn to_u64_array(&self) -> [u64; KECCAK_STATE_SIZE] {
91 let mut array = [0u64; KECCAK_STATE_SIZE];
92 let bytes = self.state.as_ref();
93 for (i, word) in array.iter_mut().enumerate() {
94 let start = i * 8;
95 *word = u64::from_le_bytes([
96 bytes[start],
97 bytes[start + 1],
98 bytes[start + 2],
99 bytes[start + 3],
100 bytes[start + 4],
101 bytes[start + 5],
102 bytes[start + 6],
103 bytes[start + 7],
104 ]);
105 }
106 array
107 }
108
109 fn apply_permutation(&mut self) {
110 let mut state_array = self.to_u64_array();
111 keccak_f1600(&mut state_array);
112 *self = Self::from_u64_array(state_array);
113 }
114}
115
116impl SecureZeroingType for SecureKeccakState {
117 fn zeroed() -> Self {
118 Self::new()
119 }
120
121 fn secure_clone(&self) -> Self {
122 Self {
123 state: self.state.secure_clone(),
124 }
125 }
126}
127
128#[derive(Clone, ZeroizeOnDrop)]
130pub struct ShakeXof128 {
131 state: SecureKeccakState,
132 buffer: SecretBuffer<SHAKE128_RATE>,
133 buffer_idx: usize,
134 is_finalized: bool,
135 squeezing: bool,
136}
137
138impl Zeroize for ShakeXof128 {
139 fn zeroize(&mut self) {
140 self.state.zeroize();
141 self.buffer.zeroize();
142 self.buffer_idx.zeroize();
143 self.is_finalized = false;
144 self.squeezing = false;
145 }
146}
147
148#[derive(Clone, ZeroizeOnDrop)]
150pub struct ShakeXof256 {
151 state: SecureKeccakState,
152 buffer: SecretBuffer<SHAKE256_RATE>,
153 buffer_idx: usize,
154 is_finalized: bool,
155 squeezing: bool,
156}
157
158impl Zeroize for ShakeXof256 {
159 fn zeroize(&mut self) {
160 self.state.zeroize();
161 self.buffer.zeroize();
162 self.buffer_idx.zeroize();
163 self.is_finalized = false;
164 self.squeezing = false;
165 }
166}
167
168fn keccak_f1600(state: &mut [u64; KECCAK_STATE_SIZE]) {
172 for (_round, &rc) in RC.iter().enumerate().take(KECCAK_ROUNDS) {
174 let mut c = EphemeralSecret::new([0u64; 5]);
176 for x in 0..5 {
177 c.as_mut()[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ state[x + 20];
178 }
179
180 let mut d = EphemeralSecret::new([0u64; 5]);
181 for x in 0..5 {
182 d.as_mut()[x] = c.as_ref()[(x + 4) % 5] ^ c.as_ref()[(x + 1) % 5].rotate_left(1);
183 }
184
185 for y in 0..5 {
186 for x in 0..5 {
187 state[x + 5 * y] ^= d.as_ref()[x];
188 }
189 }
190
191 let mut b = EphemeralSecret::new([0u64; KECCAK_STATE_SIZE]);
193 let mut x = 1;
194 let mut y = 0;
195 b.as_mut()[0] = state[0];
196
197 for i in 0..24 {
198 let idx = x + 5 * y;
199 b.as_mut()[PI[i]] = state[idx].rotate_left(RHO[i]);
200 let temp = y;
201 y = (2 * x + 3 * y) % 5;
202 x = temp;
203 }
204
205 for y in 0..5 {
207 for x in 0..5 {
208 let idx = x + 5 * y;
209 state[idx] = b.as_ref()[idx]
210 ^ ((!b.as_ref()[(x + 1) % 5 + 5 * y]) & b.as_ref()[(x + 2) % 5 + 5 * y]);
211 }
212 }
213
214 state[0] ^= rc;
216 }
217
218 barrier::compiler_fence_seq_cst();
220}
221
222fn keccak_absorb(state: &mut SecureKeccakState, data: &[u8], rate: usize) {
224 let mut state_array = state.to_u64_array();
226
227 for (i, &byte) in data.iter().enumerate() {
228 let pos = i % rate;
229 let byte_idx = pos % 8;
230 let word_idx = pos / 8;
231 state_array[word_idx] ^= (byte as u64) << (8 * byte_idx);
232 }
233
234 if !data.is_empty() && data.len() % rate == 0 {
235 keccak_f1600(&mut state_array);
236 }
237
238 *state = SecureKeccakState::from_u64_array(state_array);
240}
241
242impl ShakeXof128 {
243 fn init() -> Self {
244 ShakeXof128 {
245 state: SecureKeccakState::new(),
246 buffer: SecretBuffer::zeroed(),
247 buffer_idx: 0,
248 is_finalized: false,
249 squeezing: false,
250 }
251 }
252}
253
254impl ExtendableOutputFunction for ShakeXof128 {
255 fn new() -> Self {
256 Self::init()
257 }
258
259 fn update(&mut self, data: &[u8]) -> Result<()> {
260 if self.is_finalized {
261 return Err(Error::xof_finalized());
262 }
263 if self.squeezing {
264 return Err(Error::xof_squeezing());
265 }
266
267 let mut idx = 0;
268 if self.buffer_idx > 0 {
269 let to_copy = (SHAKE128_RATE - self.buffer_idx).min(data.len());
270 let buffer_slice =
271 &mut self.buffer.as_mut()[self.buffer_idx..self.buffer_idx + to_copy];
272 buffer_slice.copy_from_slice(&data[..to_copy]);
273 self.buffer_idx += to_copy;
274 idx = to_copy;
275
276 if self.buffer_idx == SHAKE128_RATE {
277 keccak_absorb(&mut self.state, self.buffer.as_ref(), SHAKE128_RATE);
278 self.buffer_idx = 0;
279 }
280 }
281
282 let remaining = data.len() - idx;
283 let full_blocks = remaining / SHAKE128_RATE;
284 for i in 0..full_blocks {
285 let start = idx + i * SHAKE128_RATE;
286 let block = &data[start..start + SHAKE128_RATE];
287
288 keccak_absorb(&mut self.state, block, SHAKE128_RATE);
290 }
291 idx += full_blocks * SHAKE128_RATE;
292
293 if idx < data.len() {
294 let rem = data.len() - idx;
295 self.buffer.as_mut()[..rem].copy_from_slice(&data[idx..]);
296 self.buffer_idx = rem;
297 }
298
299 Ok(())
300 }
301
302 fn finalize(&mut self) -> Result<()> {
303 if self.is_finalized {
304 return Ok(());
305 }
306
307 let mut pad_block = SecretBuffer::<SHAKE128_RATE>::zeroed();
309 pad_block.as_mut()[..self.buffer_idx]
310 .copy_from_slice(&self.buffer.as_ref()[..self.buffer_idx]);
311 pad_block.as_mut()[self.buffer_idx] ^= 0x1F;
312 pad_block.as_mut()[SHAKE128_RATE - 1] ^= 0x80;
313
314 keccak_absorb(&mut self.state, pad_block.as_ref(), SHAKE128_RATE);
315
316 self.is_finalized = true;
317 self.buffer_idx = 0;
318 Ok(())
319 }
320
321 fn squeeze(&mut self, output: &mut [u8]) -> Result<()> {
322 validate::parameter(
323 !output.is_empty(),
324 "output_length",
325 "Output buffer must not be empty",
326 )?;
327
328 if !self.is_finalized {
329 self.finalize()?;
330 }
331 self.squeezing = true;
332
333 let mut offset = 0;
334 let rate = SHAKE128_RATE;
335
336 while offset < output.len() {
337 if self.buffer_idx >= rate {
338 self.state.apply_permutation();
339 self.buffer_idx = 0;
340 }
341
342 if self.buffer_idx == 0 {
343 let state_array = self.state.to_u64_array();
345 let buffer_mut = self.buffer.as_mut();
346
347 for i in 0..(rate / 8) {
348 let lane = state_array[i];
349 for j in 0..8 {
350 if i * 8 + j < rate {
351 buffer_mut[i * 8 + j] = ((lane >> (8 * j)) & 0xFF) as u8;
352 }
353 }
354 }
355 }
356
357 let available = rate - self.buffer_idx;
358 let needed = output.len() - offset;
359 let to_copy = available.min(needed);
360
361 output[offset..offset + to_copy]
362 .copy_from_slice(&self.buffer.as_ref()[self.buffer_idx..self.buffer_idx + to_copy]);
363
364 offset += to_copy;
365 self.buffer_idx += to_copy;
366 }
367
368 barrier::compiler_fence_seq_cst();
370 Ok(())
371 }
372
373 fn squeeze_into_vec(&mut self, len: usize) -> Result<Vec<u8>> {
374 validate::parameter(
375 len > 0,
376 "output_length",
377 "Output length must be greater than 0",
378 )?;
379
380 let mut v = vec![0u8; len];
381 self.squeeze(&mut v)?;
382 Ok(v)
383 }
384
385 fn reset(&mut self) -> Result<()> {
386 *self = Self::new();
387 Ok(())
388 }
389
390 fn security_level() -> usize {
391 128
392 }
393}
394
395impl ShakeXof256 {
396 fn init() -> Self {
397 ShakeXof256 {
398 state: SecureKeccakState::new(),
399 buffer: SecretBuffer::zeroed(),
400 buffer_idx: 0,
401 is_finalized: false,
402 squeezing: false,
403 }
404 }
405}
406
407impl ExtendableOutputFunction for ShakeXof256 {
408 fn new() -> Self {
409 Self::init()
410 }
411
412 fn update(&mut self, data: &[u8]) -> Result<()> {
413 if self.is_finalized {
414 return Err(Error::xof_finalized());
415 }
416 if self.squeezing {
417 return Err(Error::xof_squeezing());
418 }
419
420 let mut idx = 0;
421 if self.buffer_idx > 0 {
422 let to_copy = (SHAKE256_RATE - self.buffer_idx).min(data.len());
423 let buffer_slice =
424 &mut self.buffer.as_mut()[self.buffer_idx..self.buffer_idx + to_copy];
425 buffer_slice.copy_from_slice(&data[..to_copy]);
426 self.buffer_idx += to_copy;
427 idx = to_copy;
428
429 if self.buffer_idx == SHAKE256_RATE {
430 keccak_absorb(&mut self.state, self.buffer.as_ref(), SHAKE256_RATE);
431 self.buffer_idx = 0;
432 }
433 }
434
435 let remaining = data.len() - idx;
436 let full_blocks = remaining / SHAKE256_RATE;
437 for i in 0..full_blocks {
438 let start = idx + i * SHAKE256_RATE;
439 let block = &data[start..start + SHAKE256_RATE];
440
441 keccak_absorb(&mut self.state, block, SHAKE256_RATE);
443 }
444 idx += full_blocks * SHAKE256_RATE;
445
446 if idx < data.len() {
447 let rem = data.len() - idx;
448 self.buffer.as_mut()[..rem].copy_from_slice(&data[idx..]);
449 self.buffer_idx = rem;
450 }
451
452 Ok(())
453 }
454
455 fn finalize(&mut self) -> Result<()> {
456 if self.is_finalized {
457 return Ok(());
458 }
459
460 let mut pad_block = SecretBuffer::<SHAKE256_RATE>::zeroed();
462 pad_block.as_mut()[..self.buffer_idx]
463 .copy_from_slice(&self.buffer.as_ref()[..self.buffer_idx]);
464 pad_block.as_mut()[self.buffer_idx] ^= 0x1F;
465 pad_block.as_mut()[SHAKE256_RATE - 1] ^= 0x80;
466
467 keccak_absorb(&mut self.state, pad_block.as_ref(), SHAKE256_RATE);
468
469 self.is_finalized = true;
470 self.buffer_idx = 0;
471 Ok(())
472 }
473
474 fn squeeze(&mut self, output: &mut [u8]) -> Result<()> {
475 validate::parameter(
476 !output.is_empty(),
477 "output_length",
478 "Output buffer must not be empty",
479 )?;
480
481 if !self.is_finalized {
482 self.finalize()?;
483 }
484 self.squeezing = true;
485
486 let mut offset = 0;
487 let rate = SHAKE256_RATE;
488
489 while offset < output.len() {
490 if self.buffer_idx >= rate {
491 self.state.apply_permutation();
492 self.buffer_idx = 0;
493 }
494
495 if self.buffer_idx == 0 {
496 let state_array = self.state.to_u64_array();
498 let buffer_mut = self.buffer.as_mut();
499
500 for i in 0..(rate / 8) {
501 let lane = state_array[i];
502 for j in 0..8 {
503 if i * 8 + j < rate {
504 buffer_mut[i * 8 + j] = ((lane >> (8 * j)) & 0xFF) as u8;
505 }
506 }
507 }
508 }
509
510 let available = rate - self.buffer_idx;
511 let needed = output.len() - offset;
512 let to_copy = available.min(needed);
513
514 output[offset..offset + to_copy]
515 .copy_from_slice(&self.buffer.as_ref()[self.buffer_idx..self.buffer_idx + to_copy]);
516
517 offset += to_copy;
518 self.buffer_idx += to_copy;
519 }
520
521 barrier::compiler_fence_seq_cst();
523 Ok(())
524 }
525
526 fn squeeze_into_vec(&mut self, len: usize) -> Result<Vec<u8>> {
527 validate::parameter(
528 len > 0,
529 "output_length",
530 "Output length must be greater than 0",
531 )?;
532
533 let mut v = vec![0u8; len];
534 self.squeeze(&mut v)?;
535 Ok(v)
536 }
537
538 fn reset(&mut self) -> Result<()> {
539 *self = Self::new();
540 Ok(())
541 }
542
543 fn security_level() -> usize {
544 256
545 }
546}
547
548#[cfg(test)]
549mod tests;