#![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/groestl/0.10.1"
)]
#![forbid(unsafe_code)]
#![warn(rust_2018_idioms)]
pub use digest::{self, Digest};
use core::fmt;
use digest::{
block_buffer::Eager,
core_api::{
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper,
CtVariableCoreWrapper, OutputSizeUser, RtVariableCoreWrapper, TruncSide, UpdateCore,
VariableOutputCore,
},
typenum::{Unsigned, U128, U28, U32, U48, U64},
HashMarker, InvalidOutputSize, Output,
};
mod compress1024;
mod compress512;
mod table;
#[derive(Clone)]
pub struct GroestlShortVarCore {
state: [u64; compress512::COLS],
blocks_len: u64,
}
impl HashMarker for GroestlShortVarCore {}
impl BlockSizeUser for GroestlShortVarCore {
type BlockSize = U64;
}
impl BufferKindUser for GroestlShortVarCore {
type BufferKind = Eager;
}
impl UpdateCore for GroestlShortVarCore {
#[inline]
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
self.blocks_len += blocks.len() as u64;
for block in blocks {
compress512::compress(&mut self.state, block.as_ref());
}
}
}
impl OutputSizeUser for GroestlShortVarCore {
type OutputSize = U32;
}
impl VariableOutputCore for GroestlShortVarCore {
const TRUNC_SIDE: TruncSide = TruncSide::Right;
#[inline]
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
if output_size > Self::OutputSize::USIZE {
return Err(InvalidOutputSize);
}
let mut state = [0; compress512::COLS];
state[compress512::COLS - 1] = 8 * output_size as u64;
let blocks_len = 0;
Ok(Self { state, blocks_len })
}
#[inline]
fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
let blocks_len = if buffer.remaining() <= 8 {
self.blocks_len + 2
} else {
self.blocks_len + 1
};
buffer.len64_padding_be(blocks_len, |block| {
compress512::compress(&mut self.state, block.as_ref())
});
let res = compress512::p(&self.state);
let n = compress512::COLS / 2;
for (chunk, v) in out.chunks_exact_mut(8).zip(res[n..].iter()) {
chunk.copy_from_slice(&v.to_be_bytes());
}
}
}
impl AlgorithmName for GroestlShortVarCore {
#[inline]
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("GroestlShort")
}
}
impl fmt::Debug for GroestlShortVarCore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("GroestlShortVarCore { ... }")
}
}
pub type GroestlShortVar = RtVariableCoreWrapper<GroestlShortVarCore>;
pub type GroestlShortCore<OutSize> = CtVariableCoreWrapper<GroestlShortVarCore, OutSize>;
pub type GroestlShort<OutSize> = CoreWrapper<GroestlShortCore<OutSize>>;
pub type Groestl224 = CoreWrapper<GroestlShortCore<U28>>;
pub type Groestl256 = CoreWrapper<GroestlShortCore<U32>>;
#[derive(Clone)]
pub struct GroestlLongVarCore {
state: [u64; compress1024::COLS],
blocks_len: u64,
}
impl HashMarker for GroestlLongVarCore {}
impl BlockSizeUser for GroestlLongVarCore {
type BlockSize = U128;
}
impl BufferKindUser for GroestlLongVarCore {
type BufferKind = Eager;
}
impl UpdateCore for GroestlLongVarCore {
#[inline]
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
self.blocks_len += blocks.len() as u64;
for block in blocks {
compress1024::compress(&mut self.state, block.as_ref());
}
}
}
impl OutputSizeUser for GroestlLongVarCore {
type OutputSize = U64;
}
impl VariableOutputCore for GroestlLongVarCore {
const TRUNC_SIDE: TruncSide = TruncSide::Right;
#[inline]
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
if output_size > Self::OutputSize::USIZE {
return Err(InvalidOutputSize);
}
let mut state = [0; compress1024::COLS];
state[compress1024::COLS - 1] = 8 * output_size as u64;
let blocks_len = 0;
Ok(Self { state, blocks_len })
}
#[inline]
fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
let blocks_len = if buffer.remaining() <= 8 {
self.blocks_len + 2
} else {
self.blocks_len + 1
};
buffer.len64_padding_be(blocks_len, |block| {
compress1024::compress(&mut self.state, block.as_ref())
});
let res = compress1024::p(&self.state);
let n = compress1024::COLS / 2;
for (chunk, v) in out.chunks_exact_mut(8).zip(res[n..].iter()) {
chunk.copy_from_slice(&v.to_be_bytes());
}
}
}
impl AlgorithmName for GroestlLongVarCore {
#[inline]
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("GroestlLong")
}
}
impl fmt::Debug for GroestlLongVarCore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("GroestlLongVarCore { ... }")
}
}
pub type GroestlLongVar = RtVariableCoreWrapper<GroestlLongVarCore>;
pub type GroestlLongCore<OutSize> = CtVariableCoreWrapper<GroestlLongVarCore, OutSize>;
pub type GroestlLong<OutSize> = CoreWrapper<GroestlLongCore<OutSize>>;
pub type Groestl384 = CoreWrapper<GroestlLongCore<U48>>;
pub type Groestl512 = CoreWrapper<GroestlLongCore<U64>>;