pub mod crypto;
pub mod fast;
mod impls;
mod macros;
pub mod prelude;
pub mod utils;
mod verification;
use prelude::*;
pub trait StableHasher {
type Out;
type Addr: FieldAddress;
fn new() -> Self;
fn write(&mut self, field_address: Self::Addr, bytes: &[u8]);
fn mixin(&mut self, other: &Self);
fn unmix(&mut self, _other: &Self) {
unimplemented!()
}
fn finish(&self) -> Self::Out;
type Bytes: AsRef<[u8]>;
fn to_bytes(&self) -> Self::Bytes;
fn from_bytes(bytes: Self::Bytes) -> Self;
}
pub trait StableHash {
fn stable_hash<H: StableHasher>(&self, field_address: H::Addr, state: &mut H);
}
pub trait FieldAddress: Sized {
fn root() -> Self;
fn child(&self, number: u64) -> Self;
fn unordered(&self) -> (Self, Self);
}
pub fn fast_stable_hash<T: StableHash>(value: &T) -> u128 {
profile_fn!(fast_stable_hash);
generic_stable_hash::<T, crate::fast::FastStableHasher>(value)
}
pub fn crypto_stable_hash<T: StableHash>(value: &T) -> [u8; 32] {
profile_fn!(crypto_stable_hash);
generic_stable_hash::<T, crate::crypto::CryptoStableHasher>(value)
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use rand::thread_rng as rng;
use rand::Rng as _;
use crate::crypto::CryptoStableHasher;
use crate::fast::FastStableHasher;
use crate::StableHasher;
#[test]
fn unmix_fast() {
unmix_fuzz(1000, FastStableHasher::rand);
}
#[test]
fn unmix_crypto() {
unmix_fuzz(30, CryptoStableHasher::rand);
}
fn unmix_fuzz<T, F>(count: u32, f: F)
where
F: Fn() -> T,
T: StableHasher + Eq + Debug + Clone,
{
let rand_vec = || {
let mut v = Vec::new();
for _ in 0..rng().gen_range(0..15) {
v.push(f());
}
v
};
let take_rand = |v: &mut Vec<T>| {
if v.len() == 0 {
return None;
}
let i = rng().gen_range(0..v.len());
Some(v.swap_remove(i))
};
for _ in 0..count {
let mut mixins = rand_vec();
let mut mixouts = Vec::<T>::new();
let mut mixin_only = T::new();
let mut complete = T::new();
while mixins.len() + mixouts.len() > 0 {
if rng().gen() {
if let Some(mixin) = take_rand(&mut mixins) {
if rng().gen_range(0..5) == 0 {
mixins.push(mixin.clone());
}
complete.mixin(&mixin);
if rng().gen() {
mixin_only.mixin(&mixin);
} else {
mixouts.push(mixin);
}
}
} else {
if let Some(mixout) = take_rand(&mut mixouts) {
complete.unmix(&mixout);
}
}
}
assert_eq!(complete, mixin_only);
}
}
}