#![no_std]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
html_root_url = "https://docs.rs/k12/0.2.1"
)]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms)]
#[macro_use]
extern crate alloc;
pub use digest;
#[macro_use]
mod lanes;
use alloc::vec::Vec;
use core::{cmp::min, convert::TryInto, mem};
use digest::{ExtendableOutput, ExtendableOutputReset, HashMarker, Reset, Update, XofReader};
#[derive(Debug, Default)]
pub struct KangarooTwelve {
buffer: Vec<u8>,
customization: Vec<u8>,
}
impl KangarooTwelve {
pub fn new() -> Self {
Self::default()
}
pub fn new_with_customization(customization: impl AsRef<[u8]>) -> Self {
Self {
buffer: Vec::new(),
customization: customization.as_ref().into(),
}
}
}
impl HashMarker for KangarooTwelve {}
impl Update for KangarooTwelve {
fn update(&mut self, bytes: &[u8]) {
self.buffer.extend_from_slice(bytes);
}
}
impl ExtendableOutput for KangarooTwelve {
type Reader = Reader;
fn finalize_xof(self) -> Self::Reader {
Reader {
buffer: self.buffer,
customization: self.customization,
finished: false,
}
}
}
impl ExtendableOutputReset for KangarooTwelve {
fn finalize_xof_reset(&mut self) -> Self::Reader {
let mut buffer = vec![];
let mut customization = vec![];
mem::swap(&mut self.buffer, &mut buffer);
mem::swap(&mut self.customization, &mut customization);
Reader {
buffer,
customization,
finished: false,
}
}
}
impl Reset for KangarooTwelve {
fn reset(&mut self) {
self.buffer.clear();
}
}
#[derive(Debug, Default)]
pub struct Reader {
buffer: Vec<u8>,
customization: Vec<u8>,
finished: bool,
}
impl XofReader for Reader {
fn read(&mut self, output: &mut [u8]) {
assert!(
!self.finished,
"not yet implemented: multiple XofReader::read invocations unsupported"
);
let b = 8192;
let c = 256;
let mut slice = Vec::new(); slice.extend_from_slice(&self.buffer);
slice.extend_from_slice(&self.customization);
slice.extend_from_slice(&right_encode(self.customization.len())[..]);
let n = (slice.len() + b - 1) / b;
let mut slices = Vec::with_capacity(n); for i in 0..n {
let ub = min((i + 1) * b, slice.len());
slices.push(&slice[i * b..ub]);
}
let tmp_buffer = if n == 1 {
f(slices[0], 0x07, output.len())
} else {
let mut intermediate = Vec::with_capacity(n - 1); for i in 0..n - 1 {
intermediate.push(f(slices[i + 1], 0x0B, c / 8));
}
let mut node_star = Vec::new();
node_star.extend_from_slice(slices[0]);
node_star.extend_from_slice(&[3, 0, 0, 0, 0, 0, 0, 0]);
#[allow(clippy::needless_range_loop)]
for i in 0..n - 1 {
node_star.extend_from_slice(&intermediate[i][..]);
}
node_star.extend_from_slice(&right_encode(n - 1));
node_star.extend_from_slice(b"\xFF\xFF");
f(&node_star[..], 0x06, output.len())
};
output.copy_from_slice(&tmp_buffer);
self.finished = true;
}
}
fn f(input: &[u8], suffix: u8, mut output_len: usize) -> Vec<u8> {
let mut state = [0u8; 200];
let max_block_size = 1344 / 8;
let mut block_size = min(input.len(), max_block_size);
state[0..block_size].copy_from_slice(&input[0..block_size]);
let mut offset = block_size;
while offset < input.len() {
keccak(&mut state);
block_size = min(input.len() - offset, max_block_size);
for i in 0..block_size {
state[i] ^= input[i + offset];
}
offset += block_size;
}
if block_size == max_block_size {
keccak(&mut state);
block_size = 0;
}
state[block_size] ^= suffix;
if ((suffix & 0x80) != 0) && (block_size == (max_block_size - 1)) {
keccak(&mut state);
}
state[max_block_size - 1] ^= 0x80;
keccak(&mut state);
let mut output = Vec::with_capacity(output_len);
while output_len > 0 {
block_size = min(output_len, max_block_size);
output.extend_from_slice(&state[0..block_size]);
output_len -= block_size;
if output_len > 0 {
keccak(&mut state);
}
}
output
}
fn keccak(state: &mut [u8; 200]) {
let mut lanes = [0u64; 25];
let mut y;
for x in 0..5 {
FOR5!(y, 5, {
let pos = 8 * (x + y);
lanes[x + y] = u64::from_le_bytes(state[pos..(pos + 8)].try_into().unwrap());
});
}
lanes::keccak(&mut lanes);
for x in 0..5 {
FOR5!(y, 5, {
let i = 8 * (x + y);
state[i..i + 8].copy_from_slice(&lanes[x + y].to_le_bytes());
});
}
}
fn right_encode(mut x: usize) -> Vec<u8> {
let mut slice = Vec::new();
while x > 0 {
slice.push((x % 256) as u8);
x /= 256;
}
slice.reverse();
let len = slice.len();
slice.push(len as u8);
slice
}