use core::mem::size_of;
use sha2::Digest as Sha2Digest;
use super::{
Felt, HasherExt,
digest::{DIGEST256_BYTES, DIGEST512_BYTES, Digest256, Digest512},
};
use crate::field::BasedVectorSpace;
#[cfg(test)]
mod tests;
pub type Sha256Digest = Digest256;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Sha256;
impl HasherExt for Sha256 {
type Digest = Sha256Digest;
fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
let mut hasher = sha2::Sha256::new();
for slice in slices {
hasher.update(slice);
}
Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
}
}
impl Sha256 {
pub const COLLISION_RESISTANCE: u32 = 128;
pub fn hash(bytes: &[u8]) -> Sha256Digest {
let mut hasher = sha2::Sha256::new();
hasher.update(bytes);
Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
}
pub fn merge(values: &[Sha256Digest; 2]) -> Sha256Digest {
Self::hash(Sha256Digest::digests_as_bytes(values))
}
pub fn merge_many(values: &[Sha256Digest]) -> Sha256Digest {
let data = Sha256Digest::digests_as_bytes(values);
let mut hasher = sha2::Sha256::new();
hasher.update(data);
Sha256Digest::from(<[u8; DIGEST256_BYTES]>::from(hasher.finalize()))
}
#[inline(always)]
pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Sha256Digest {
Sha256Digest::from(hash_elements_256(elements))
}
#[inline(always)]
pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha256Digest {
<Self as HasherExt>::hash_iter(slices)
}
}
pub type Sha512Digest = Digest512;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Sha512;
impl HasherExt for Sha512 {
type Digest = Sha512Digest;
fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
let mut hasher = sha2::Sha512::new();
for slice in slices {
hasher.update(slice);
}
Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
}
}
impl Sha512 {
#[inline(always)]
pub fn hash(bytes: &[u8]) -> Sha512Digest {
let mut hasher = sha2::Sha512::new();
hasher.update(bytes);
Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
}
#[inline(always)]
pub fn merge(values: &[Sha512Digest; 2]) -> Sha512Digest {
Self::hash(Sha512Digest::digests_as_bytes(values))
}
#[inline(always)]
pub fn merge_many(values: &[Sha512Digest]) -> Sha512Digest {
let data = Sha512Digest::digests_as_bytes(values);
let mut hasher = sha2::Sha512::new();
hasher.update(data);
Sha512Digest::from(<[u8; DIGEST512_BYTES]>::from(hasher.finalize()))
}
#[inline(always)]
pub fn hash_elements<E>(elements: &[E]) -> Sha512Digest
where
E: BasedVectorSpace<Felt>,
{
Sha512Digest::from(hash_elements_512(elements))
}
#[inline(always)]
pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Sha512Digest {
<Self as HasherExt>::hash_iter(slices)
}
}
fn hash_elements_256<E>(elements: &[E]) -> [u8; DIGEST256_BYTES]
where
E: BasedVectorSpace<Felt>,
{
let digest = {
const FELT_BYTES: usize = size_of::<u64>();
const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
let mut hasher = sha2::Sha256::new();
for elem in elements.iter() {
for &felt in E::as_basis_coefficients_slice(elem) {
let felt_bytes = felt.as_canonical_u64().to_le_bytes();
hasher.update(felt_bytes);
}
}
hasher.finalize()
};
digest.into()
}
fn hash_elements_512<E>(elements: &[E]) -> [u8; DIGEST512_BYTES]
where
E: BasedVectorSpace<Felt>,
{
let digest = {
const FELT_BYTES: usize = size_of::<u64>();
const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
let mut hasher = sha2::Sha512::new();
for elem in elements.iter() {
for &felt in E::as_basis_coefficients_slice(elem) {
let felt_bytes = felt.as_canonical_u64().to_le_bytes();
hasher.update(felt_bytes);
}
}
hasher.finalize()
};
digest.into()
}