use std::{fmt, marker::PhantomData, mem::MaybeUninit};
#[cfg(test)]
mod test;
trait Sealed {}
#[allow(private_bounds)]
pub trait SecurityLevel: Sealed {
const BITS: usize;
const HASH_ARRAY_LENGTH: usize;
type Hash: Default
+ fmt::Debug
+ Eq
+ PartialEq
+ Into<Vec<u8>>
+ HashContainer;
}
pub struct KT128;
impl Sealed for KT128 {}
impl SecurityLevel for KT128 {
const BITS: usize = 128;
const HASH_ARRAY_LENGTH: usize = 32;
type Hash = Hash<32>;
}
pub struct KT256;
impl Sealed for KT256 {}
impl SecurityLevel for KT256 {
const BITS: usize = 256;
const HASH_ARRAY_LENGTH: usize = 64;
type Hash = Hash<64>;
}
trait HashContainer {
fn ptr(&mut self) -> *mut u8;
fn len() -> usize;
}
pub fn hash<N>(input: &[u8]) -> N::Hash
where
N: SecurityLevel,
{
let mut hasher = Hasher::<N>::new();
hasher.update(input);
hasher.finalize()
}
#[derive(Clone)]
pub struct Hasher<N>(marsupial_sys::KangarooTwelve_Instance, PhantomData<N>);
impl<N> Hasher<N>
where
N: SecurityLevel,
{
pub const RATE: usize = (1600 - (2 * N::BITS)) / 8;
pub fn new() -> Self {
let mut inner = MaybeUninit::uninit();
let inner = unsafe {
let ret = marsupial_sys::KangarooTwelve_Initialize(
inner.as_mut_ptr(),
N::BITS as i32,
0,
);
debug_assert_eq!(0, ret);
inner.assume_init()
};
debug_assert_eq!(inner.phase, 1);
Self(inner, PhantomData)
}
pub fn update(&mut self, input: &[u8]) {
unsafe {
let ret = marsupial_sys::KangarooTwelve_Update(
&mut self.0,
input.as_ptr(),
input.len(),
);
debug_assert_eq!(0, ret);
}
}
pub fn finalize(self) -> N::Hash {
self.finalize_custom(&[])
}
pub fn finalize_custom(mut self, customization: &[u8]) -> N::Hash {
let mut hash = N::Hash::default();
unsafe {
let ret = marsupial_sys::KangarooTwelve_Final(
&mut self.0,
std::ptr::null_mut(),
customization.as_ptr(),
customization.len(),
);
debug_assert_eq!(0, ret);
let ret = marsupial_sys::KangarooTwelve_Squeeze(
&mut self.0,
hash.ptr(),
N::Hash::len(),
);
debug_assert_eq!(0, ret);
}
hash
}
pub fn finalize_xof(self) -> OutputReader {
self.finalize_custom_xof(&[])
}
pub fn finalize_custom_xof(
mut self,
customization: &[u8],
) -> OutputReader {
unsafe {
let ret = marsupial_sys::KangarooTwelve_Final(
&mut self.0,
std::ptr::null_mut(),
customization.as_ptr(),
customization.len(),
);
debug_assert_eq!(0, ret);
}
OutputReader(self.0)
}
}
impl<N> Default for Hasher<N>
where
N: SecurityLevel,
{
fn default() -> Self {
Self::new()
}
}
impl<N> fmt::Debug for Hasher<N>
where
N: SecurityLevel,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Hasher").finish_non_exhaustive()
}
}
#[allow(clippy::derived_hash_with_manual_eq)]
#[derive(Clone, Copy, Hash)]
pub struct Hash<const N: usize>([u8; N]);
impl<const N: usize> Hash<N> {
#[inline]
pub fn as_bytes(&self) -> &[u8; N] {
&self.0
}
}
impl<const N: usize> From<[u8; N]> for Hash<N> {
#[inline]
fn from(bytes: [u8; N]) -> Self {
Self(bytes)
}
}
impl<const N: usize> From<Hash<N>> for Vec<u8> {
#[inline]
fn from(hash: Hash<N>) -> Self {
hash.0.into()
}
}
impl<const N: usize> From<Hash<N>> for [u8; N] {
#[inline]
fn from(hash: Hash<N>) -> Self {
hash.0
}
}
impl<const N: usize> PartialEq for Hash<N> {
#[inline]
fn eq(&self, other: &Hash<N>) -> bool {
constant_time_eq::constant_time_eq_n(&self.0, &other.0)
}
}
impl<const N: usize> PartialEq<[u8; N]> for Hash<N> {
#[inline]
fn eq(&self, other: &[u8; N]) -> bool {
constant_time_eq::constant_time_eq_n(&self.0, other)
}
}
impl<const N: usize> Eq for Hash<N> {}
impl<const N: usize> fmt::Debug for Hash<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Hash").finish()
}
}
impl<const N: usize> Default for Hash<N> {
fn default() -> Self {
Self([0; N])
}
}
impl<const N: usize> HashContainer for Hash<N> {
#[inline]
fn ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr()
}
#[inline]
fn len() -> usize {
N
}
}
#[derive(Clone)]
pub struct OutputReader(marsupial_sys::KangarooTwelve_Instance);
impl OutputReader {
pub fn squeeze(&mut self, buf: &mut [u8]) {
debug_assert_eq!(
self.0.phase, 3,
"this instance has not yet been finalized"
);
unsafe {
let ret = marsupial_sys::KangarooTwelve_Squeeze(
&mut self.0,
buf.as_mut_ptr(),
buf.len(),
);
debug_assert_eq!(0, ret);
}
}
}
impl fmt::Debug for OutputReader {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("OutputReader").finish_non_exhaustive()
}
}
impl std::io::Read for OutputReader {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.squeeze(buf);
Ok(buf.len())
}
}