use core::mem;
pub const fn v256(data: &[u8]) -> [u8; 32] {
V256::new().absorb(data).squeeze()
}
const fn keccakf(mut a: [u64; 25]) -> [u64; 25] {
let mut b = [0; 25];
let mut c = [0; 5];
let mut d = [0; 5];
let mut i = 0;
while i < RC.len() {
let rc = RC[i];
i += 1;
c[0] = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20];
c[1] = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21];
c[2] = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22];
c[3] = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23];
c[4] = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24];
d[0] = c[4] ^ c[1].rotate_left(1);
d[1] = c[0] ^ c[2].rotate_left(1);
d[2] = c[1] ^ c[3].rotate_left(1);
d[3] = c[2] ^ c[4].rotate_left(1);
d[4] = c[3] ^ c[0].rotate_left(1);
b[0] = a[0] ^ d[0];
b[1] = (a[6] ^ d[1]).rotate_left(44);
b[2] = (a[12] ^ d[2]).rotate_left(43);
b[3] = (a[18] ^ d[3]).rotate_left(21);
b[4] = (a[24] ^ d[4]).rotate_left(14);
b[5] = (a[3] ^ d[3]).rotate_left(28);
b[6] = (a[9] ^ d[4]).rotate_left(20);
b[7] = (a[10] ^ d[0]).rotate_left(3);
b[8] = (a[16] ^ d[1]).rotate_left(45);
b[9] = (a[22] ^ d[2]).rotate_left(61);
b[10] = (a[1] ^ d[1]).rotate_left(1);
b[11] = (a[7] ^ d[2]).rotate_left(6);
b[12] = (a[13] ^ d[3]).rotate_left(25);
b[13] = (a[19] ^ d[4]).rotate_left(8);
b[14] = (a[20] ^ d[0]).rotate_left(18);
b[15] = (a[4] ^ d[4]).rotate_left(27);
b[16] = (a[5] ^ d[0]).rotate_left(36);
b[17] = (a[11] ^ d[1]).rotate_left(10);
b[18] = (a[17] ^ d[2]).rotate_left(15);
b[19] = (a[23] ^ d[3]).rotate_left(56);
b[20] = (a[2] ^ d[2]).rotate_left(62);
b[21] = (a[8] ^ d[3]).rotate_left(55);
b[22] = (a[14] ^ d[4]).rotate_left(39);
b[23] = (a[15] ^ d[0]).rotate_left(41);
b[24] = (a[21] ^ d[1]).rotate_left(2);
a[0] = b[0] ^ (!b[1] & b[2]) ^ rc;
a[1] = b[1] ^ (!b[2] & b[3]);
a[2] = b[2] ^ (!b[3] & b[4]);
a[3] = b[3] ^ (!b[4] & b[0]);
a[4] = b[4] ^ (!b[0] & b[1]);
a[5] = b[5] ^ (!b[6] & b[7]);
a[6] = b[6] ^ (!b[7] & b[8]);
a[7] = b[7] ^ (!b[8] & b[9]);
a[8] = b[8] ^ (!b[9] & b[5]);
a[9] = b[9] ^ (!b[5] & b[6]);
a[10] = b[10] ^ (!b[11] & b[12]);
a[11] = b[11] ^ (!b[12] & b[13]);
a[12] = b[12] ^ (!b[13] & b[14]);
a[13] = b[13] ^ (!b[14] & b[10]);
a[14] = b[14] ^ (!b[10] & b[11]);
a[15] = b[15] ^ (!b[16] & b[17]);
a[16] = b[16] ^ (!b[17] & b[18]);
a[17] = b[17] ^ (!b[18] & b[19]);
a[18] = b[18] ^ (!b[19] & b[15]);
a[19] = b[19] ^ (!b[15] & b[16]);
a[20] = b[20] ^ (!b[21] & b[22]);
a[21] = b[21] ^ (!b[22] & b[23]);
a[22] = b[22] ^ (!b[23] & b[24]);
a[23] = b[23] ^ (!b[24] & b[20]);
a[24] = b[24] ^ (!b[20] & b[21]);
}
a
}
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,
];
#[derive(Clone, Copy, Default)]
pub struct V256 {
s: [u64; 25],
pos: usize,
}
impl V256 {
const RATE: usize = 136;
const DS: u8 = 0x01;
pub const fn new() -> Self {
Self { s: [0; 25], pos: 0 }
}
pub const fn absorb(mut self, data: &[u8]) -> Self {
const N: usize = mem::size_of::<u64>();
let mut remaining = data.len();
let mut ptr = data.as_ptr();
unsafe {
while remaining > 0 {
debug_assert!(self.pos < Self::RATE);
let n = if self.pos % N == 0 && remaining >= N {
self.s[self.pos / N] ^= ptr.cast::<u64>().read_unaligned().to_le();
N
} else {
let mut buf = [0; N];
let o = self.pos % N;
let n = N - o;
let n = if n < remaining { n } else { remaining };
let mut i = 0;
while i < n {
buf[o + i] = ptr.add(i).read();
i += 1;
}
self.s[self.pos / N] ^= u64::from_le_bytes(buf);
n
};
self.pos += n;
if self.pos == Self::RATE {
self.s = keccakf(self.s);
self.pos = 0;
}
remaining -= n;
ptr = ptr.add(n);
}
}
self
}
pub const fn squeeze(mut self) -> [u8; 32] {
const N: usize = mem::size_of::<u64>();
macro_rules! xor_byte {
($i:expr, $b:expr) => {{
let (i, b) = ($i, $b);
let mut buf = [0; N];
buf[i % N] = b;
self.s[i / N] ^= u64::from_le_bytes(buf);
}};
}
xor_byte!(self.pos, Self::DS);
xor_byte!(Self::RATE - 1, 0x80);
self.s = keccakf(self.s);
unsafe {
mem::transmute([
self.s[0].to_le(),
self.s[1].to_le(),
self.s[2].to_le(),
self.s[3].to_le(),
])
}
}
}