#[cfg(feature = "std")]
use bitrep::DotF64;
use bitrep::{SumF32, SumF64};
use sha2::{Digest, Sha256};
struct Rng(u64);
impl Rng {
fn next(&mut self) -> u64 {
self.0 ^= self.0 << 13;
self.0 ^= self.0 >> 7;
self.0 ^= self.0 << 17;
self.0
}
fn f64(&mut self) -> f64 {
loop {
let x = f64::from_bits(self.next());
if x.is_finite() {
return x;
}
}
}
}
fn golden_data() -> Vec<f64> {
let mut r = Rng(0x9E3779B97F4A7C15); let mut v: Vec<f64> = (0..10_000).map(|_| r.f64()).collect();
for i in 0..500 {
let x = f64::from_bits(r.next() & 0x7FEF_FFFF_FFFF_FFFF); v.insert((r.next() % v.len() as u64) as usize, x);
v.insert((r.next() % v.len() as u64) as usize, -x);
let _ = i;
}
v.extend_from_slice(&[
f64::MAX,
-f64::MAX,
f64::MIN_POSITIVE,
f64::from_bits(1), -f64::from_bits(1),
0.0,
-0.0,
]);
v
}
fn hex(b: &[u8]) -> String {
b.iter().map(|x| format!("{x:02x}")).collect()
}
const SUM_DIGEST: &str = "54f3ce5fbbd6130d70db87dffe73c26160b0d99a6f92f9dd3b276a99bb9f8441";
const F32_DIGEST: &str = "825e3c7a6a43bd9870c00c222850dbbcf5eb529a63c748064832cc9f7eeeea26";
#[cfg(feature = "std")]
const DOT_DIGEST: &str = "e0e967014704730292e6f8679b745f7284d3077fd59c01bfbe37523f32e61a5a";
#[test]
fn golden_sum_digest_is_architecture_independent() {
let data = golden_data();
let seq: SumF64 = data.iter().copied().collect();
let mut rev = SumF64::new();
for x in data.iter().rev() {
rev.add(*x);
}
assert_eq!(seq.to_bytes(), rev.to_bytes());
let shards: Vec<SumF64> = data
.chunks(data.len() / 13 + 1)
.map(|c| c.iter().copied().collect())
.collect();
let mut merged = SumF64::new();
for s in shards.iter().rev() {
merged.merge(s);
}
assert_eq!(seq.to_bytes(), merged.to_bytes());
let digest = hex(&Sha256::digest(seq.to_bytes()));
assert_eq!(digest, SUM_DIGEST, "SumF64 golden digest changed — cross-arch bit-identity broken (or an intentional format change: bump major)");
}
#[test]
fn golden_f32_digest_is_architecture_independent() {
let mut r = Rng(0xD1B54A32D192ED03);
let mut acc = SumF32::new();
for _ in 0..20_000 {
loop {
let x = f32::from_bits(r.next() as u32);
if x.is_finite() {
acc.add(x);
break;
}
}
}
let digest = hex(&Sha256::digest(acc.to_bytes()));
assert_eq!(digest, F32_DIGEST);
}
#[cfg(feature = "std")]
#[test]
fn golden_dot_digest_is_architecture_independent() {
let mut r = Rng(0xA0761D6478BD642F);
let mut d = DotF64::new();
for _ in 0..10_000 {
let a = (r.next() >> 11) as f64 / (1u64 << 53) as f64 * 2e10 - 1e10;
let b = (r.next() >> 11) as f64 / (1u64 << 53) as f64 * 2e-10 - 1e-10;
d.push(a, b);
}
assert!(d.is_exact());
let digest = hex(&Sha256::digest(d.to_bytes()));
assert_eq!(digest, DOT_DIGEST);
}