use bash_prg_hash::{
BashPrgHash1281, BashPrgHash1282, BashPrgHash1921, BashPrgHash1922, BashPrgHash2561,
BashPrgHash2562,
};
use digest::{ExtendableOutput, TryCustomizedInit, Update};
use hex_literal::hex;
use std::fmt::Debug;
#[derive(Debug, Clone, Copy)]
struct TestVector {
customization: &'static [u8],
input: &'static [u8],
output: &'static [u8],
}
fn bash_prg_hash_test<D: TryCustomizedInit + ExtendableOutput + Clone>(
&TestVector {
customization,
input,
output,
}: &TestVector,
) -> Result<(), &'static str> {
let Ok(mut hasher) = D::try_new_customized(customization) else {
return Err("initialization error");
};
let mut buf = [0u8; 1024];
let buf = &mut buf[..output.len()];
hasher.update(input);
hasher.finalize_xof_into(buf);
if buf != output {
return Err("whole message");
}
buf.iter_mut().for_each(|b| *b = 0);
for n in 1..core::cmp::min(17, input.len()) {
let Ok(mut hasher) = D::try_new_customized(customization) else {
return Err("initialization error");
};
for chunk in input.chunks(n) {
hasher.update(chunk);
}
hasher.finalize_xof_into(buf);
if buf != output {
return Err("message in chunks");
}
buf.iter_mut().for_each(|b| *b = 0);
}
Ok(())
}
macro_rules! new_bash_prg_hash_test {
($name:ident, $hasher:ty $(,)?) => {
#[test]
fn $name() {
digest::dev::blobby::parse_into_structs!(
include_bytes!(concat!("data/", stringify!($name), ".blb"));
static TEST_VECTORS: &[TestVector { customization, input, output }];
);
for (i, tv) in TEST_VECTORS.iter().enumerate() {
if let Err(reason) = bash_prg_hash_test::<$hasher>(tv) {
panic!(
"\n\
Failed test #{i}\n\
reason:\t{reason}
test vector:\t{tv:?}\n"
);
}
}
}
};
}
new_bash_prg_hash_test!(bashprg_l128_d1, BashPrgHash1281);
new_bash_prg_hash_test!(bashprg_l128_d2, BashPrgHash1282);
new_bash_prg_hash_test!(bashprg_l192_d1, BashPrgHash1921);
new_bash_prg_hash_test!(bashprg_l192_d2, BashPrgHash1922);
new_bash_prg_hash_test!(bashprg_l256_d1, BashPrgHash2561);
new_bash_prg_hash_test!(bashprg_l256_d2, BashPrgHash2562);
macro_rules! test_bash_prg_rand {
($name:ident, $hasher:ty, $expected:expr) => {
#[test]
fn $name() {
let mut h = <$hasher>::default();
digest::dev::feed_rand_16mib(&mut h);
let mut output = [0u8; 64];
h.finalize_xof_into(&mut output);
assert_eq!(&output[..], $expected);
}
};
}
test_bash_prg_rand!(
bashprg1282_rand,
BashPrgHash1282,
hex!(
"BF15805CDEAE220A9DD50C325A4A0BDF326C6ED853CFA89592A9E2BEB4D0585C"
"891AF66C1CA514390311FDFB51D467FC11439AE4907863A5C3861CDCF7F360EC"
)
);
test_bash_prg_rand!(
bashprg1921_rand,
BashPrgHash1921,
hex!(
"82176D6DAF4F631E251CA41A7688FEB643B954383186C7902AB09D80EB5AB17C"
"BA286D16912EBBACEC3D8143966107F6DFB5F4AC4F88B64F20AB49CEAD817E45"
)
);
test_bash_prg_rand!(
bashprg2562_rand,
BashPrgHash2562,
hex!(
"AD07A8D61928296F4115F9E51AAA5FA986899BFDA8443F139D969600064EBCE2"
"D591F583FA27F6B0F7E73DA2B29AF382AC2374C04463B91A27F1C48FEE8AAB2C"
)
);
macro_rules! test_bash_prg_million {
($name:ident, $hasher:ty, $expected:expr) => {
#[test]
fn $name() {
let mut h = <$hasher>::default();
let block = [0x61u8; 1000];
for _ in 0..1000 {
h.update(&block);
}
let mut output = [0u8; 64];
h.finalize_xof_into(&mut output);
assert_eq!(&output[..$expected.len()], $expected);
}
};
}
test_bash_prg_million!(
bashprg1282_million,
BashPrgHash1282,
hex!("F84CA85F610711674BB8ADDB87B747C6000A6B6735664687854052C60CE0F7B0")
);
test_bash_prg_million!(
bashprg1922_million,
BashPrgHash1922,
hex!(
"C9B4ABF055F1A2ED025385AA5480BA9ADFB1608409D3102BCC557C41B22C2866"
"233212327DF735BE22D85DE44CB48C2E"
)
);
test_bash_prg_million!(
bashprg2562_million,
BashPrgHash2562,
hex!(
"45911D1B40F84E5D53C3B27FBB91D696E96924C5F3BD61CC589F26FA9502F3F5"
"847DF96A5D6B44D17388DFF413D0B8AE0D81073D010F1637A20892E06DAB1AF0"
)
);