use core::{fmt::Debug, slice};
use math::{FieldElement, StarkField};
use utils::{ByteReader, Deserializable, DeserializationError, Serializable};
mod blake;
pub use blake::{Blake3_192, Blake3_256};
mod sha;
pub use sha::Sha3_256;
mod mds;
mod rescue;
pub use rescue::{Rp62_248, Rp64_256, RpJive64_256};
pub trait Hasher {
type Digest: Digest;
const COLLISION_RESISTANCE: u32;
fn hash(bytes: &[u8]) -> Self::Digest;
fn merge(values: &[Self::Digest; 2]) -> Self::Digest;
fn merge_many(values: &[Self::Digest]) -> Self::Digest;
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest;
}
pub trait ElementHasher: Hasher {
type BaseField: StarkField;
fn hash_elements<E>(elements: &[E]) -> Self::Digest
where
E: FieldElement<BaseField = Self::BaseField>;
}
pub trait Digest:
Debug + Default + Copy + Clone + Eq + PartialEq + Send + Sync + Serializable + Deserializable
{
fn as_bytes(&self) -> [u8; 32];
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ByteDigest<const N: usize>([u8; N]);
impl<const N: usize> ByteDigest<N> {
pub fn new(value: [u8; N]) -> Self {
Self(value)
}
#[inline(always)]
pub fn bytes_as_digests(bytes: &[[u8; N]]) -> &[ByteDigest<N>] {
let p = bytes.as_ptr();
let len = bytes.len();
unsafe { slice::from_raw_parts(p as *const ByteDigest<N>, len) }
}
#[inline(always)]
pub fn digests_as_bytes(digests: &[ByteDigest<N>]) -> &[u8] {
let p = digests.as_ptr();
let len = digests.len() * N;
unsafe { slice::from_raw_parts(p as *const u8, len) }
}
}
impl<const N: usize> Digest for ByteDigest<N> {
fn as_bytes(&self) -> [u8; 32] {
let mut result = [0; 32];
result[..N].copy_from_slice(&self.0);
result
}
}
impl<const N: usize> Default for ByteDigest<N> {
fn default() -> Self {
ByteDigest([0; N])
}
}
impl<const N: usize> Serializable for ByteDigest<N> {
fn write_into<W: utils::ByteWriter>(&self, target: &mut W) {
target.write_bytes(&self.0);
}
}
impl<const N: usize> Deserializable for ByteDigest<N> {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
Ok(ByteDigest(source.read_array()?))
}
}
#[cfg(test)]
mod tests {
use super::{ByteDigest, Digest};
#[test]
fn byte_digest_as_bytes() {
let d = ByteDigest::new([255_u8; 32]);
assert_eq!([255_u8; 32], d.as_bytes());
let d = ByteDigest::new([255_u8; 31]);
let mut expected = [255_u8; 32];
expected[31] = 0;
assert_eq!(expected, d.as_bytes());
}
}