use quickcheck::{Gen, QuickCheck};
use sha1::Digest as _;
use sha1dc::{Collision, Digest, Hasher};
const LONG: usize = 4 * 1024;
const CHUNKED: usize = 64;
fn hash_in_parts<'a>(parts: impl IntoIterator<Item = &'a [u8]>) -> Result<Digest, Collision> {
let mut hasher = Hasher::new();
for part in parts {
hasher.update(part);
}
hasher.finalize()
}
#[test]
fn backends_agree_on_any_message() {
fn prop(data: Vec<u8>) -> bool {
let mut auto = Hasher::new();
auto.update(&data);
let mut scalar = Hasher::builder().internal_scalar_backend().build();
scalar.update(&data);
auto.finalize() == scalar.finalize()
}
QuickCheck::new()
.rng(Gen::new(LONG))
.tests(1_000)
.quickcheck(prop as fn(Vec<u8>) -> bool);
}
#[test]
fn the_ubc_filter_does_not_change_the_digest() {
fn prop(data: Vec<u8>) -> bool {
let mut filtered = Hasher::builder().internal_use_ubc(true).build();
filtered.update(&data);
let mut unfiltered = Hasher::builder().internal_use_ubc(false).build();
unfiltered.update(&data);
filtered.finalize() == unfiltered.finalize()
}
QuickCheck::new()
.rng(Gen::new(LONG))
.tests(200)
.quickcheck(prop as fn(Vec<u8>) -> bool);
}
#[test]
fn chunked_updates_match_one_shot() {
fn prop(chunks: Vec<Vec<u8>>) -> bool {
hash_in_parts(chunks.iter().map(Vec::as_slice)) == sha1dc::digest(&chunks.concat())
}
QuickCheck::new()
.rng(Gen::new(CHUNKED))
.tests(2_000)
.quickcheck(prop as fn(Vec<Vec<u8>>) -> bool);
}
#[test]
fn fixed_size_chunks_match_one_shot() {
fn prop(data: Vec<u8>, chunk: usize) -> bool {
hash_in_parts(data.chunks(1 + chunk % 1024)) == sha1dc::digest(&data)
}
QuickCheck::new()
.rng(Gen::new(LONG))
.tests(1_000)
.quickcheck(prop as fn(Vec<u8>, usize) -> bool);
}
#[test]
fn clean_messages_match_the_sha1_crate() {
fn prop(data: Vec<u8>) -> bool {
let want = sha1::Sha1::digest(&data);
match sha1dc::digest(&data) {
Ok(got) => got.as_bytes() == &want[..],
Err(_) => false,
}
}
QuickCheck::new()
.rng(Gen::new(LONG))
.tests(1_000)
.quickcheck(prop as fn(Vec<u8>) -> bool);
}
#[test]
fn mitigation_leaves_clean_messages_alone() {
fn prop(data: Vec<u8>) -> bool {
match (sha1dc::digest(&data), sha1dc::mitigate::digest(&data)) {
(Ok(plain), Ok(mitigating)) => plain == mitigating,
_ => false,
}
}
QuickCheck::new()
.rng(Gen::new(LONG))
.tests(1_000)
.quickcheck(prop as fn(Vec<u8>) -> bool);
}
#[test]
fn reset_matches_a_fresh_hasher() {
fn prop(used: Vec<u8>, then: Vec<u8>) -> bool {
let mut recycled = Hasher::new();
recycled.update(&used);
recycled.reset();
recycled.update(&then);
recycled.finalize() == sha1dc::digest(&then)
}
QuickCheck::new()
.rng(Gen::new(LONG))
.tests(1_000)
.quickcheck(prop as fn(Vec<u8>, Vec<u8>) -> bool);
}