use blake2::digest::consts::U16;
use blake2::{Blake2b, Digest};
use proptest::prelude::*;
use proptest_derive::Arbitrary;
const MAX_COMPLEXITY: u8 = 32;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Arbitrary)]
pub struct OneWayFn {
#[proptest(strategy = "0..MAX_COMPLEXITY")]
complexity: u8,
}
fn hash_once(input: [u8; 16]) -> [u8; 16] {
let mut hasher = Blake2b::<U16>::new();
hasher.update(input);
hasher.finalize().into()
}
impl OneWayFn {
pub fn call(&self, input: u128) -> u128 {
u128::from_be_bytes((0..self.complexity).fold(input.to_be_bytes(), |acc, _| hash_once(acc)))
}
}
proptest! {
#[test]
fn one_way_fn_of_0_complexity_is_identity(input: u128) {
let output = OneWayFn { complexity: 0 }.call(input);
prop_assert_eq!(input, output);
}
#[test]
fn one_way_fn_complexity_changes_output_inductively(input: u128, hypothesis_complexity in 0..MAX_COMPLEXITY - 1) {
let hypothesis_one_way_fn = OneWayFn { complexity: hypothesis_complexity };
let step_one_way_fn = OneWayFn { complexity: hypothesis_complexity + 1 };
prop_assert_ne!(hypothesis_one_way_fn.call(input), step_one_way_fn.call(input));
}
}