#![no_std]
const RHO: [u32; 24] = [
1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44
];
const PI: [usize; 24] = [
10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2,
20, 14, 22, 9, 6, 1
];
const RC: [u64; 24] = [
1u64, 0x8082u64, 0x800000000000808au64, 0x8000000080008000u64,
0x808bu64, 0x80000001u64, 0x8000000080008081u64, 0x8000000000008009u64,
0x8au64, 0x88u64, 0x80008009u64, 0x8000000au64,
0x8000808bu64, 0x800000000000008bu64, 0x8000000000008089u64, 0x8000000000008003u64,
0x8000000000008002u64, 0x8000000000000080u64, 0x800au64, 0x800000008000000au64,
0x8000000080008081u64, 0x8000000000008080u64, 0x80000001u64, 0x8000000080008008u64
];
macro_rules! REPEAT4 {
($e: expr) => ( $e; $e; $e; $e; )
}
macro_rules! REPEAT5 {
($e: expr) => ( $e; $e; $e; $e; $e; )
}
macro_rules! REPEAT6 {
($e: expr) => ( $e; $e; $e; $e; $e; $e; )
}
macro_rules! REPEAT24 {
($e: expr, $s: expr) => (
REPEAT6!({ $e; $s; });
REPEAT6!({ $e; $s; });
REPEAT6!({ $e; $s; });
REPEAT5!({ $e; $s; });
$e;
)
}
macro_rules! FOR5 {
($v: expr, $s: expr, $e: expr) => {
$v = 0;
REPEAT4!({
$e;
$v += $s;
});
$e;
}
}
pub fn keccakf(a: &mut [u64]) {
unsafe {
let mut b: [u64; 5] = [0; 5];
let mut t: u64;
let mut x: usize;
let mut y: usize;
for i in 0..24 {
FOR5!(x, 1, {
*b.get_unchecked_mut(x) = 0;
FOR5!(y, 5, {
*b.get_unchecked_mut(x) ^= *a.get_unchecked(x + y);
});
});
FOR5!(x, 1, {
FOR5!(y, 5, {
*a.get_unchecked_mut(y + x) ^= *b.get_unchecked((x + 4) % 5) ^ b.get_unchecked((x + 1) % 5).rotate_left(1);
});
});
t = *a.get_unchecked(1);
x = 0;
REPEAT24!({
*b.get_unchecked_mut(0) = *a.get_unchecked(*PI.get_unchecked(x));
*a.get_unchecked_mut(*PI.get_unchecked(x)) = t.rotate_left(*RHO.get_unchecked(x));
}, {
t = *b.get_unchecked(0);
x += 1;
});
FOR5!(y, 5, {
FOR5!(x, 1, {
*b.get_unchecked_mut(x) = *a.get_unchecked(y + x);
});
FOR5!(x, 1, {
*a.get_unchecked_mut(y + x) = *b.get_unchecked(x) ^ ((!b.get_unchecked((x + 1) % 5)) & b.get_unchecked((x + 2) % 5));
});
});
*a.get_unchecked_mut(0) ^= *RC.get_unchecked(i);
}
}
}
fn xorin(dst: &mut [u8], src: &[u8], len: usize) {
unsafe {
for i in 0..len {
*dst.get_unchecked_mut(i) ^= *src.get_unchecked(i);
}
}
}
fn setout(src: &[u8], dst: &mut [u8], len: usize) {
dst[..len].copy_from_slice(&src[..len]);
}
const PLEN: usize = 25;
fn as_bytes_slice<'a, 'b>(ints: &'a [u64]) -> &'b [u8] {
unsafe {
::core::slice::from_raw_parts(ints.as_ptr() as *mut u8, ints.len() * 8)
}
}
fn as_mut_bytes_slice<'a, 'b>(ints: &'a mut [u64]) -> &'b mut [u8] {
unsafe {
::core::slice::from_raw_parts_mut(ints.as_mut_ptr() as *mut u8, ints.len() * 8)
}
}
pub struct Keccak {
a: [u64; PLEN],
offset: usize,
rate: usize,
delim: u8
}
impl Clone for Keccak {
fn clone(&self) -> Self {
let mut res = Keccak::new(self.rate, self.delim);
res.a.copy_from_slice(&self.a);
res.offset = self.offset;
res
}
}
macro_rules! impl_constructor {
($name: ident, $bits: expr, $delim: expr) => {
pub fn $name() -> Keccak {
Keccak::new(200 - $bits/4, $delim)
}
}
}
impl Keccak {
fn new(rate: usize, delim: u8) -> Keccak {
Keccak {
a: [0; PLEN],
offset: 0,
rate: rate,
delim: delim
}
}
impl_constructor!(new_shake128, 128, 0x1f);
impl_constructor!(new_shake256, 256, 0x1f);
impl_constructor!(new_keccak224, 224, 0x01);
impl_constructor!(new_keccak256, 256, 0x01);
impl_constructor!(new_keccak384, 384, 0x01);
impl_constructor!(new_keccak512, 512, 0x01);
impl_constructor!(new_sha3_224, 224, 0x06);
impl_constructor!(new_sha3_256, 256, 0x06);
impl_constructor!(new_sha3_384, 384, 0x06);
impl_constructor!(new_sha3_512, 512, 0x06);
pub fn update(&mut self, input: &[u8]) {
self.absorb(input);
}
#[inline]
pub fn keccakf(&mut self) {
keccakf(&mut self.a);
}
pub fn finalize(mut self, output: &mut [u8]) {
self.pad();
keccakf(&mut self.a);
self.squeeze(output);
}
pub fn absorb(&mut self, input: &[u8]) {
let mut a = as_mut_bytes_slice(&mut self.a);
let inlen = input.len();
let mut rate = self.rate - self.offset;
let mut ip = 0;
let mut l = inlen;
while l >= rate {
xorin(&mut a[self.offset..], &input[ip..], rate);
keccakf(&mut self.a);
ip += rate;
l -= rate;
rate = self.rate;
self.offset = 0;
}
xorin(&mut a[self.offset..], &input[ip..], l);
self.offset += l;
}
pub fn pad(&mut self) {
let mut a = as_mut_bytes_slice(&mut self.a);
let offset = self.offset;
let rate = self.rate;
unsafe {
*a.get_unchecked_mut(offset) ^= self.delim;
*a.get_unchecked_mut(rate - 1) ^= 0x80;
}
}
pub fn squeeze(&mut self, output: &mut [u8]) {
let a = as_bytes_slice(&mut self.a);
let outlen = output.len();
let rate = self.rate;
let mut op = 0;
let mut l = outlen;
while l >= rate {
setout(&a, &mut output[op..], rate);
keccakf(&mut self.a);
op += rate;
l -= rate;
}
setout(&a, &mut output[op..], l);
}
}