use crate::keccak::keccak_f1600;
use zeroize::Zeroize;
const RATE: usize = 136;
#[derive(Clone)]
pub struct Sponge {
state: [u64; 25],
offset: usize,
squeezing: bool,
}
impl Sponge {
pub fn new() -> Self {
Self {
state: [0; 25],
offset: 0,
squeezing: false,
}
}
pub fn absorb(&mut self, input: &[u8]) {
if self.squeezing {
self.squeezing = false;
}
for &byte in input {
if self.offset >= RATE {
keccak_f1600(&mut self.state);
self.offset = 0;
}
let state_idx = self.offset / 8;
let byte_shift = (self.offset % 8) * 8;
self.state[state_idx] ^= (byte as u64) << byte_shift;
self.offset += 1;
}
}
pub fn squeeze(&mut self, out_len: usize) -> Vec<u8> {
if !self.squeezing {
let state_idx = self.offset / 8;
let byte_shift = (self.offset % 8) * 8;
self.state[state_idx] ^= (0x01 as u64) << byte_shift;
let last_byte_idx = (RATE - 1) / 8;
let last_byte_shift = ((RATE - 1) % 8) * 8;
self.state[last_byte_idx] ^= (0x80 as u64) << last_byte_shift;
keccak_f1600(&mut self.state);
self.offset = 0;
self.squeezing = true;
}
let mut out = vec![0u8; out_len];
for i in 0..out_len {
if self.offset >= RATE {
keccak_f1600(&mut self.state);
self.offset = 0;
}
let state_idx = self.offset / 8;
let byte_shift = (self.offset % 8) * 8;
out[i] = (self.state[state_idx] >> byte_shift) as u8;
self.offset += 1;
}
out
}
pub fn fork(&self) -> Self {
self.clone()
}
}
impl Zeroize for Sponge {
fn zeroize(&mut self) {
self.state.zeroize();
self.offset = 0;
self.squeezing = false;
}
}