commonware_cryptography/sha256/
mod.rsuse crate::{Array, Error, Hasher};
use commonware_utils::{hex, SizedSerialize};
use rand::{CryptoRng, Rng};
use sha2::{Digest as _, Sha256 as ISha256};
use std::{
fmt::{Debug, Display},
ops::Deref,
};
const DIGEST_LENGTH: usize = 32;
pub fn hash(message: &[u8]) -> Digest {
let array: [u8; DIGEST_LENGTH] = ISha256::digest(message).into();
Digest::from(array)
}
#[derive(Debug)]
pub struct Sha256 {
hasher: ISha256,
}
impl Default for Sha256 {
fn default() -> Self {
Self::new()
}
}
impl Clone for Sha256 {
fn clone(&self) -> Self {
Self::default()
}
}
impl Hasher for Sha256 {
type Digest = Digest;
fn new() -> Self {
Self {
hasher: ISha256::new(),
}
}
fn update(&mut self, message: &[u8]) {
self.hasher.update(message);
}
fn finalize(&mut self) -> Self::Digest {
let finalized = self.hasher.finalize_reset();
let array: [u8; DIGEST_LENGTH] = finalized.into();
Self::Digest::from(array)
}
fn reset(&mut self) {
self.hasher = ISha256::new();
}
fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self::Digest {
let mut digest = [0u8; DIGEST_LENGTH];
rng.fill_bytes(&mut digest);
Self::Digest::from(digest)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Digest([u8; DIGEST_LENGTH]);
impl Array for Digest {}
impl SizedSerialize for Digest {
const SERIALIZED_LEN: usize = DIGEST_LENGTH;
}
impl From<[u8; DIGEST_LENGTH]> for Digest {
fn from(value: [u8; DIGEST_LENGTH]) -> Self {
Self(value)
}
}
impl TryFrom<&[u8]> for Digest {
type Error = Error;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() != DIGEST_LENGTH {
return Err(Error::InvalidDigestLength);
}
let array: [u8; DIGEST_LENGTH] =
value.try_into().map_err(|_| Error::InvalidDigestLength)?;
Ok(Self(array))
}
}
impl TryFrom<&Vec<u8>> for Digest {
type Error = Error;
fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(value.as_slice())
}
}
impl TryFrom<Vec<u8>> for Digest {
type Error = Error;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
if value.len() != DIGEST_LENGTH {
return Err(Error::InvalidDigestLength);
}
let boxed_slice = value.into_boxed_slice();
let boxed_array: Box<[u8; DIGEST_LENGTH]> = boxed_slice
.try_into()
.map_err(|_| Error::InvalidDigestLength)?;
Ok(Self(*boxed_array))
}
}
impl AsRef<[u8]> for Digest {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Deref for Digest {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.0
}
}
impl Debug for Digest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", hex(&self.0))
}
}
impl Display for Digest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", hex(&self.0))
}
}
#[cfg(test)]
mod tests {
use super::*;
use commonware_utils::hex;
const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
#[test]
fn test_sha256() {
let msg = b"hello world";
let mut hasher = Sha256::new();
hasher.update(msg);
let digest = hasher.finalize();
assert!(Digest::try_from(digest.as_ref()).is_ok());
assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
hasher.update(msg);
let digest = hasher.finalize();
assert!(Digest::try_from(digest.as_ref()).is_ok());
assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
let hash = hash(msg);
assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
}
#[test]
fn test_sha256_len() {
assert_eq!(Digest::SERIALIZED_LEN, DIGEST_LENGTH);
}
}