use std::hash::{DefaultHasher, Hasher};
#[cfg(feature = "shake256")]
use sha3::Shake256;
#[cfg(feature = "shake256")]
use sha3::digest::{ExtendableOutput, Update as XofUpdate, XofReader};
pub mod english_word;
pub trait ByteReader {
fn read(&mut self, dest: &mut [u8]) -> usize;
fn remaining(&self) -> Option<usize>;
}
pub trait ReadableHasher: Default {
type Reader: ByteReader;
fn update(&mut self, data: &[u8]);
fn finalize(self) -> Self::Reader;
}
#[derive(Default)]
pub struct StdHasher<H: Hasher + Default = DefaultHasher> {
hasher: H,
}
impl<H: Hasher + Default> ReadableHasher for StdHasher<H> {
type Reader = StdHasherReader;
fn update(&mut self, data: &[u8]) {
self.hasher.write(data);
}
fn finalize(self) -> Self::Reader {
StdHasherReader {
bytes: self.hasher.finish().to_le_bytes(),
position: 0,
}
}
}
pub struct StdHasherReader {
bytes: [u8; 8],
position: usize,
}
impl ByteReader for StdHasherReader {
fn read(&mut self, dest: &mut [u8]) -> usize {
let available = 8 - self.position;
let bytes_to_read = dest.len().min(available);
dest[..bytes_to_read]
.copy_from_slice(&self.bytes[self.position..self.position + bytes_to_read]);
self.position += bytes_to_read;
bytes_to_read
}
fn remaining(&self) -> Option<usize> {
Some(8 - self.position)
}
}
#[cfg(feature = "shake256")]
#[derive(Default)]
pub struct Shake256Hasher {
hasher: Shake256,
}
#[cfg(feature = "shake256")]
impl ReadableHasher for Shake256Hasher {
type Reader = Shake256Reader;
fn update(&mut self, data: &[u8]) {
XofUpdate::update(&mut self.hasher, data);
}
fn finalize(self) -> Self::Reader {
Shake256Reader {
reader: self.hasher.finalize_xof(),
}
}
}
#[cfg(feature = "shake256")]
pub struct Shake256Reader {
reader: sha3::Shake256Reader,
}
#[cfg(feature = "shake256")]
impl ByteReader for Shake256Reader {
fn read(&mut self, dest: &mut [u8]) -> usize {
XofReader::read(&mut self.reader, dest);
dest.len()
}
fn remaining(&self) -> Option<usize> {
None
}
}
pub struct SliceReader<'a> {
data: &'a [u8],
position: usize,
}
impl<'a> SliceReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data, position: 0 }
}
}
impl<'a> ByteReader for SliceReader<'a> {
fn read(&mut self, dest: &mut [u8]) -> usize {
let available = self.data.len() - self.position;
let bytes_to_read = dest.len().min(available);
dest[..bytes_to_read]
.copy_from_slice(&self.data[self.position..self.position + bytes_to_read]);
self.position += bytes_to_read;
bytes_to_read
}
fn remaining(&self) -> Option<usize> {
Some(self.data.len() - self.position)
}
}
pub fn english_word_hash<H, T>(input: T) -> String
where
H: ReadableHasher,
T: AsRef<[u8]>,
{
let input_bytes = input.as_ref();
if input_bytes.is_empty() {
return String::new();
}
let input_len = input_bytes.len();
let mut hasher = H::default();
hasher.update(input_bytes);
let reader = hasher.finalize();
let bytes_limit = match reader.remaining() {
Some(_) => None, None => Some(input_len.max(8)), };
let mut limited_reader = LimitedByteReader::new(reader, bytes_limit);
english_word::generate_word_with_target_len(&mut limited_reader, input_len)
}
struct LimitedByteReader<R: ByteReader> {
inner: R,
remaining: Option<usize>,
}
impl<R: ByteReader> LimitedByteReader<R> {
fn new(inner: R, limit: Option<usize>) -> Self {
Self {
inner,
remaining: limit,
}
}
}
impl<R: ByteReader> ByteReader for LimitedByteReader<R> {
fn read(&mut self, dest: &mut [u8]) -> usize {
let max_read = match self.remaining {
Some(0) => return 0,
Some(remaining) => dest.len().min(remaining),
None => dest.len(),
};
let bytes_read = self.inner.read(&mut dest[..max_read]);
if let Some(ref mut remaining) = self.remaining {
*remaining = remaining.saturating_sub(bytes_read);
}
bytes_read
}
fn remaining(&self) -> Option<usize> {
match (self.remaining, self.inner.remaining()) {
(Some(limit), Some(inner_remaining)) => Some(limit.min(inner_remaining)),
(Some(limit), None) => Some(limit),
(None, inner_remaining) => inner_remaining,
}
}
}