#![no_std]
const RC: [u64; 24] = [
0x0000000000000001,
0x0000000000008082,
0x800000000000808a,
0x8000000080008000,
0x000000000000808b,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008a,
0x0000000000000088,
0x0000000080008009,
0x000000008000000a,
0x000000008000808b,
0x800000000000008b,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800a,
0x800000008000000a,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008,
];
fn keccak_f1600(s: &mut [u64; 25]) {
s[1] = !s[1];
s[2] = !s[2];
s[8] = !s[8];
s[12] = !s[12];
s[17] = !s[17];
s[20] = !s[20];
macro_rules! round {
($rc:expr) => {{
let c0 = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20];
let c1 = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21];
let c2 = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22];
let c3 = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23];
let c4 = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24];
let d0 = c4 ^ c1.rotate_left(1);
let d1 = c0 ^ c2.rotate_left(1);
let d2 = c1 ^ c3.rotate_left(1);
let d3 = c2 ^ c4.rotate_left(1);
let d4 = c3 ^ c0.rotate_left(1);
let s3 = s[3];
let s1 = s[1];
let s4 = s[4];
let s2 = s[2];
{
let b0 = s[0] ^ d0;
let b1 = (s[6] ^ d1).rotate_left(44);
let b2 = (s[12] ^ d2).rotate_left(43);
let b3 = (s[18] ^ d3).rotate_left(21);
let b4 = (s[24] ^ d4).rotate_left(14);
s[0] = b0 ^ (b1 | b2) ^ $rc;
s[1] = b1 ^ ((!b2) | b3);
s[2] = b2 ^ (b3 & b4);
s[3] = b3 ^ (b4 | b0);
s[4] = b4 ^ (b0 & b1);
}
let s7 = s[7];
let s5 = s[5];
let s8 = s[8];
{
let b0 = (s3 ^ d3).rotate_left(28);
let b1 = (s[9] ^ d4).rotate_left(20);
let b2 = (s[10] ^ d0).rotate_left(3);
let b3 = (s[16] ^ d1).rotate_left(45);
let b4 = (s[22] ^ d2).rotate_left(61);
s[5] = b0 ^ (b1 | b2);
s[6] = b1 ^ (b2 & b3);
s[7] = (!b2) ^ b4 ^ (b3 & b4);
s[8] = b3 ^ (b4 | b0);
s[9] = b4 ^ (b0 & b1);
}
let s11 = s[11];
let s14 = s[14];
{
let b0 = (s1 ^ d1).rotate_left(1);
let b1 = (s7 ^ d2).rotate_left(6);
let b2 = (s[13] ^ d3).rotate_left(25);
let b3 = (s[19] ^ d4).rotate_left(8);
let b4 = (s[20] ^ d0).rotate_left(18);
s[10] = b0 ^ (b1 | b2);
s[11] = b1 ^ (b2 & b3);
s[12] = b2 ^ b4 ^ (b3 & b4);
s[13] = b3 ^ !(b4 | b0);
s[14] = b4 ^ (b0 & b1);
}
let s15 = s[15];
{
let b0 = (s4 ^ d4).rotate_left(27);
let b1 = (s5 ^ d0).rotate_left(36);
let b2 = (s11 ^ d1).rotate_left(10);
let b3 = (s[17] ^ d2).rotate_left(15);
let b4 = (s[23] ^ d3).rotate_left(56);
s[15] = b0 ^ (b1 & b2);
s[16] = b1 ^ (b2 | b3);
s[17] = b2 ^ ((!b3) | b4);
s[18] = (!b3) ^ (b4 & b0);
s[19] = b4 ^ (b0 | b1);
}
{
let b0 = (s2 ^ d2).rotate_left(62);
let b1 = (s8 ^ d3).rotate_left(55);
let b2 = (s14 ^ d4).rotate_left(39);
let b3 = (s15 ^ d0).rotate_left(41);
let b4 = (s[21] ^ d1).rotate_left(2);
s[20] = b0 ^ b2 ^ (b1 & b2);
s[21] = b1 ^ !(b2 | b3);
s[22] = b2 ^ (b3 & b4);
s[23] = b3 ^ (b4 | b0);
s[24] = b4 ^ (b0 & b1);
}
}};
}
round!(RC[0]);
round!(RC[1]);
round!(RC[2]);
round!(RC[3]);
round!(RC[4]);
round!(RC[5]);
round!(RC[6]);
round!(RC[7]);
round!(RC[8]);
round!(RC[9]);
round!(RC[10]);
round!(RC[11]);
round!(RC[12]);
round!(RC[13]);
round!(RC[14]);
round!(RC[15]);
round!(RC[16]);
round!(RC[17]);
round!(RC[18]);
round!(RC[19]);
round!(RC[20]);
round!(RC[21]);
round!(RC[22]);
round!(RC[23]);
s[1] = !s[1];
s[2] = !s[2];
s[8] = !s[8];
s[12] = !s[12];
s[17] = !s[17];
s[20] = !s[20];
}
pub const RATE: usize = 136;
pub struct Shake256 {
state: [u64; 25],
pos: usize,
}
impl Default for Shake256 {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Shake256 {
#[inline]
pub fn new() -> Self {
Self {
state: [0; 25],
pos: 0,
}
}
#[inline(always)]
pub fn absorb(&mut self, data: &[u8]) {
let mut i = 0;
let len = data.len();
while i < len && !self.pos.is_multiple_of(8) {
let lane = self.pos / 8;
let shift = 8 * (self.pos % 8);
self.state[lane] ^= (data[i] as u64) << shift;
self.pos += 1;
if self.pos == RATE {
keccak_f1600(&mut self.state);
self.pos = 0;
}
i += 1;
}
while i + 8 <= len {
unsafe { core::hint::assert_unchecked(self.pos / 8 < 17) };
let chunk_bytes: [u8; 8] = data[i..i + 8].try_into().unwrap();
let chunk = u64::from_le_bytes(chunk_bytes);
self.state[self.pos / 8] ^= chunk;
self.pos += 8;
i += 8;
if self.pos == RATE {
keccak_f1600(&mut self.state);
self.pos = 0;
}
}
while i < len {
let lane = self.pos / 8;
let shift = 8 * (self.pos % 8);
self.state[lane] ^= (data[i] as u64) << shift;
self.pos += 1;
if self.pos == RATE {
keccak_f1600(&mut self.state);
self.pos = 0;
}
i += 1;
}
}
#[inline(always)]
pub fn finalize(&mut self) {
let lane = self.pos / 8;
let shift = 8 * (self.pos % 8);
self.state[lane] ^= 0x1Fu64 << shift;
let last = RATE - 1;
self.state[last / 8] ^= 0x80u64 << (8 * (last % 8));
keccak_f1600(&mut self.state);
self.pos = 0;
}
#[inline]
pub fn rate_lanes(&self) -> &[u64] {
&self.state[..17]
}
#[inline]
pub fn permute(&mut self) {
keccak_f1600(&mut self.state);
}
#[inline]
pub fn squeeze<const LEN: usize>(&mut self, out: &mut [u8; LEN]) {
let len = LEN;
let mut i = 0;
while i < len && !self.pos.is_multiple_of(8) {
let lane = self.pos / 8;
let shift = 8 * (self.pos % 8);
out[i] = (self.state[lane] >> shift) as u8;
self.pos += 1;
i += 1;
if self.pos == RATE {
keccak_f1600(&mut self.state);
self.pos = 0;
}
}
while i + 8 <= len && self.pos + 8 <= RATE {
unsafe { core::hint::assert_unchecked(self.pos / 8 < 17) };
out[i..i + 8].copy_from_slice(&self.state[self.pos / 8].to_le_bytes());
self.pos += 8;
i += 8;
if self.pos == RATE {
keccak_f1600(&mut self.state);
self.pos = 0;
}
}
while i < len {
let lane = self.pos / 8;
let shift = 8 * (self.pos % 8);
out[i] = (self.state[lane] >> shift) as u8;
self.pos += 1;
i += 1;
if self.pos == RATE {
keccak_f1600(&mut self.state);
self.pos = 0;
}
}
}
}