use crate::repr::{BinaryHashRepr, MemWrite};
use const_hex::ToHexExt;
use fake::Dummy;
#[cfg(feature = "proptest")]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};
use serialize::{Deserializable, Serializable, Tagged, tag_enforcement_test};
use sha2::{Digest, Sha256};
use std::fmt::{self, Debug, Display, Formatter};
use std::io;
use zeroize::Zeroize;
pub const PERSISTENT_HASH_BYTES: usize = 32;
#[derive(
Copy,
Clone,
Default,
PartialOrd,
Ord,
Hash,
BinaryHashRepr,
Serializable,
Serialize,
Deserialize,
Dummy,
Zeroize,
)]
#[cfg_attr(feature = "proptest", derive(Arbitrary))]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct HashOutput(pub [u8; PERSISTENT_HASH_BYTES]);
tag_enforcement_test!(HashOutput);
impl PartialEq for HashOutput {
fn eq(&self, other: &Self) -> bool {
subtle::ConstantTimeEq::ct_eq(&self.0[..], &other.0[..]).into()
}
}
impl Eq for HashOutput {}
impl Tagged for HashOutput {
fn tag() -> std::borrow::Cow<'static, str> {
<[u8; PERSISTENT_HASH_BYTES]>::tag()
}
fn tag_unique_factor() -> String {
<[u8; PERSISTENT_HASH_BYTES]>::tag_unique_factor()
}
}
#[cfg(feature = "proptest")]
serialize::randomised_serialization_test!(HashOutput);
pub const BLANK_HASH: HashOutput = HashOutput([0u8; PERSISTENT_HASH_BYTES]);
impl rand::distributions::Distribution<HashOutput> for rand::distributions::Standard {
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> HashOutput {
HashOutput(rng.r#gen())
}
}
impl Debug for HashOutput {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "{}", self.0.encode_hex())
}
}
impl Display for HashOutput {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "{}", &self.0.encode_hex()[..10])
}
}
pub fn persistent_hash(a: &[u8]) -> HashOutput {
HashOutput(Sha256::digest(a).into())
}
pub fn persistent_commit<T: BinaryHashRepr + ?Sized>(value: &T, opening: HashOutput) -> HashOutput {
let mut writer = PersistentHashWriter::new();
opening.binary_repr(&mut writer);
value.binary_repr(&mut writer);
writer.finalize()
}
pub struct PersistentHashWriter(Sha256);
impl MemWrite<u8> for PersistentHashWriter {
fn write(&mut self, buf: &[u8]) {
self.0.update(buf);
}
}
impl io::Write for PersistentHashWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.update(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Default for PersistentHashWriter {
fn default() -> Self {
PersistentHashWriter(Sha256::new())
}
}
impl PersistentHashWriter {
pub fn new() -> Self {
Default::default()
}
pub fn finalize(self) -> HashOutput {
HashOutput(self.0.finalize().into())
}
}