use clock_hash::{clockhash256_domain, clockhash256_with_domain, clockhash256, DomainTag, tags};
use std::collections::HashSet;
#[test]
fn test_empty_domain_separation() {
let data = b"test data";
let empty_domain_hash = clockhash256_domain(b"", data);
let plain_hash = clockhash256(data);
assert_ne!(empty_domain_hash, plain_hash, "Empty domain should differ from no domain");
let empty_domain_hash2 = clockhash256_domain(b"", data);
assert_eq!(empty_domain_hash, empty_domain_hash2, "Empty domain should be deterministic");
}
#[test]
fn test_long_domain_separation() {
let data = b"test data";
let domain_lengths = [1, 10, 100, 1000, 10000];
let mut hashes = HashSet::new();
for &len in &domain_lengths {
let domain: Vec<u8> = (0..len).map(|i| (i % 256) as u8).collect();
let hash = clockhash256_domain(&domain, data);
assert!(hashes.insert(hash), "Domain of length {} should produce unique hash", len);
}
let plain_hash = clockhash256(data);
for &len in &domain_lengths {
let domain: Vec<u8> = (0..len).map(|i| (i % 256) as u8).collect();
let domain_hash = clockhash256_domain(&domain, data);
assert_ne!(domain_hash, plain_hash, "Domain of length {} should differ from plain hash", len);
}
}
#[test]
fn test_special_byte_domains() {
let data = b"test data";
let special_domains = vec![
vec![0x00], vec![0xFF], vec![0x00, 0x00, 0x00], vec![0xFF, 0xFF, 0xFF], vec![0x00, 0x01, 0x02, 0x03], vec![0x80, 0x81, 0x82], vec![0xAA, 0x55, 0xAA, 0x55], ];
let mut hashes = HashSet::new();
for (i, domain) in special_domains.iter().enumerate() {
let hash = clockhash256_domain(domain, data);
assert!(hashes.insert(hash), "Special domain {} should produce unique hash", i);
let plain_hash = clockhash256(data);
assert_ne!(hash, plain_hash, "Special domain {} should differ from plain hash", i);
}
}
#[test]
fn test_domain_with_separator() {
let data = b"test data";
let domains_with_separator = vec![
vec![0x00], vec![0x42, 0x00, 0x43], vec![0x00, 0x00], vec![0xFF, 0x00, 0x01], ];
let mut hashes = HashSet::new();
for (i, domain) in domains_with_separator.iter().enumerate() {
let hash = clockhash256_domain(domain, data);
assert!(hashes.insert(hash), "Domain with separator {} should produce unique hash", i);
let plain_hash = clockhash256(data);
assert_ne!(hash, plain_hash, "Domain with separator {} should differ from plain hash", i);
}
}
#[test]
fn test_standard_domain_uniqueness() {
let data = b"standard domain test data";
let standard_domains = vec![
tags::CLK_BLOCK,
tags::CLK_TX,
tags::CLK_MERKLE,
tags::CLK_NONCE,
tags::CLK_RNG,
];
let mut hashes = HashSet::new();
for domain in &standard_domains {
let hash = clockhash256_domain(domain, data);
assert!(hashes.insert(hash), "Standard domain {:?} should produce unique hash", std::str::from_utf8(domain));
let plain_hash = clockhash256(data);
assert_ne!(hash, plain_hash, "Standard domain {:?} should differ from plain hash", std::str::from_utf8(domain));
}
}
#[test]
fn test_data_looking_like_domains() {
let test_cases = vec![
(tags::CLK_BLOCK, &b"block data"[..]),
(tags::CLK_TX, &b"tx data"[..]),
(tags::CLK_MERKLE, &b"merkle data"[..]),
(tags::CLK_NONCE, &b"nonce data"[..]),
(tags::CLK_RNG, &b"rng data"[..]),
];
let mut all_hashes = HashSet::new();
for (domain, data) in test_cases {
let hash = clockhash256_domain(domain, data);
assert!(all_hashes.insert(hash), "Domain should produce unique hash");
}
}
#[test]
fn test_domain_boundary_conditions() {
let data = b"boundary test";
let boundary_lengths = [0, 1, 254, 255, 256, 257, 511, 512, 513];
let mut hashes = HashSet::new();
for &len in &boundary_lengths {
let domain: Vec<u8> = (0..len).map(|i| (i % 256) as u8).collect();
let hash = clockhash256_domain(&domain, data);
assert!(hashes.insert(hash), "Domain length {} should produce unique hash", len);
let plain_hash = clockhash256(data);
assert_ne!(hash, plain_hash, "Domain length {} should differ from plain hash", len);
}
}
#[test]
fn test_domain_separation_incremental() {
use clock_hash::ClockHasher;
let domain = b"INCREMENTAL_DOMAIN";
let data = b"test data for incremental domain hashing";
let reference_hash = clockhash256_domain(domain, data);
let mut hasher = ClockHasher::new();
hasher.update(domain);
hasher.update(&[0x00]); hasher.update(data);
let incremental_hash = hasher.finalize();
assert_eq!(reference_hash, incremental_hash,
"Domain separation should work identically with incremental hasher");
}
#[test]
fn test_domain_separation_empty_data() {
let domains = vec![
&b""[..],
&b"DOMAIN1"[..],
&b"DOMAIN2"[..],
tags::CLK_BLOCK,
tags::CLK_TX,
];
let empty_data = b"";
let mut hashes = HashSet::new();
for domain in &domains {
let hash = clockhash256_domain(domain, empty_data);
assert!(hashes.insert(hash), "Domain {:?} with empty data should produce unique hash",
std::str::from_utf8(domain));
}
let plain_empty_hash = clockhash256(empty_data);
for domain in &domains {
let domain_hash = clockhash256_domain(domain, empty_data);
assert_ne!(domain_hash, plain_empty_hash,
"Domain {:?} with empty data should differ from plain empty hash",
std::str::from_utf8(domain));
}
}
#[test]
fn test_domain_tag_enum_completeness() {
let data = b"enum completeness test";
let enum_domains = vec![
(DomainTag::Block, "Block"),
(DomainTag::Transaction, "Transaction"),
(DomainTag::Merkle, "Merkle"),
(DomainTag::Nonce, "Nonce"),
(DomainTag::Rng, "Rng"),
];
let mut enum_hashes = HashSet::new();
let mut tag_hashes = HashSet::new();
for (enum_domain, name) in &enum_domains {
let enum_hash = clockhash256_with_domain(*enum_domain, data);
let tag_hash = clockhash256_domain(enum_domain.as_bytes(), data);
assert_eq!(enum_hash, tag_hash,
"Enum domain {} should match tag-based domain", name);
assert!(enum_hashes.insert(enum_hash),
"Enum domain {} should produce unique hash", name);
assert!(tag_hashes.insert(tag_hash),
"Tag domain {} should produce unique hash", name);
}
}
#[test]
fn test_domain_separation_collision_resistance() {
let data = b"collision resistance test";
let mut hashes = HashSet::new();
for i in 0..1000 {
let domain = format!("DOMAIN_{:04x}", i);
let hash = clockhash256_domain(domain.as_bytes(), data);
assert!(hashes.insert(hash), "Domain {} should produce unique hash", i);
}
let plain_hash = clockhash256(data);
for i in 0..100 {
let domain = format!("DOMAIN_{:04x}", i);
let domain_hash = clockhash256_domain(domain.as_bytes(), data);
assert_ne!(domain_hash, plain_hash, "Domain {} should differ from plain hash", i);
}
}
#[test]
fn test_binary_domain_separation() {
let data = b"binary domain test";
let binary_domains = vec![
vec![0x00, 0x01, 0x02, 0xFF],
vec![0x80, 0x81, 0x82, 0x83],
vec![0x00, 0xFF, 0x00, 0xFF],
(0..16).map(|i| i as u8).collect::<Vec<_>>(),
(0..16).map(|i| (255 - i) as u8).collect::<Vec<_>>(),
];
let mut hashes = HashSet::new();
for (i, domain) in binary_domains.iter().enumerate() {
let hash = clockhash256_domain(domain, data);
assert!(hashes.insert(hash), "Binary domain {} should produce unique hash", i);
let plain_hash = clockhash256(data);
assert_ne!(hash, plain_hash, "Binary domain {} should differ from plain hash", i);
}
}
#[test]
fn test_domain_separation_preimage_resistance() {
let target_data = b"target data";
let target_domain = b"TARGET_DOMAIN";
let target_hash = clockhash256_domain(target_domain, target_data);
let test_domains = [&b"DIFF_DOMAIN"[..], &b"OTHER_DOMAIN"[..], &b"RANDOM_DOMAIN"[..]];
for domain in &test_domains {
for i in 0..100 {
let candidate_data = format!("candidate_data_{}", i);
let candidate_hash = clockhash256_domain(domain, candidate_data.as_bytes());
assert_ne!(candidate_hash, target_hash,
"Should not find preimage in different domain {} with candidate {}",
std::str::from_utf8(domain).unwrap_or("<?>"), i);
}
}
}