mirror of
https://github.com/BLAKE3-team/BLAKE3
synced 2024-05-28 05:26:04 +02:00
move universal_hash tests
This commit is contained in:
parent
2c62c3ba6c
commit
8d63b946eb
|
@ -720,7 +720,7 @@ unsafe fn universal_hash_using_compress(
|
|||
let mut block_output = [0u8; 32];
|
||||
compress(
|
||||
&block,
|
||||
BLOCK_LEN as u32,
|
||||
block_len as u32,
|
||||
key,
|
||||
counter,
|
||||
flags,
|
||||
|
@ -733,9 +733,7 @@ unsafe fn universal_hash_using_compress(
|
|||
input_len -= block_len;
|
||||
counter += 1;
|
||||
}
|
||||
for i in 0..4 {
|
||||
(*out)[WORD_LEN * i..][..WORD_LEN].copy_from_slice(&result[i].to_le_bytes());
|
||||
}
|
||||
*out = result;
|
||||
}
|
||||
|
||||
// this is in units of *words*, for pointer operations on *const/*mut u32
|
||||
|
|
|
@ -244,4 +244,15 @@ mod test {
|
|||
fn test_xof_vs_reference() {
|
||||
crate::test::test_xof_vs_reference(&implementation());
|
||||
}
|
||||
|
||||
// This is circular but do it anyway.
|
||||
#[test]
|
||||
fn test_universal_hash_vs_portable() {
|
||||
crate::test::test_universal_hash_vs_portable(&implementation());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_universal_hash_vs_reference() {
|
||||
crate::test::test_universal_hash_vs_reference(&implementation());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -413,3 +413,77 @@ pub fn test_xof_vs_reference(test_impl: &Implementation) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_universal_hash_vs_portable(test_impl: &Implementation) {
|
||||
const MAX_INPUT_LEN: usize = 2 * MAX_SIMD_DEGREE * BLOCK_LEN;
|
||||
let mut input_buf = [0; MAX_INPUT_LEN];
|
||||
paint_test_input(&mut input_buf);
|
||||
// Try equal to and partway through every whole number of input blocks.
|
||||
let mut input_lengths = vec![0, 1, 31];
|
||||
let mut next_len = BLOCK_LEN;
|
||||
loop {
|
||||
input_lengths.push(next_len);
|
||||
if next_len == MAX_INPUT_LEN {
|
||||
break;
|
||||
}
|
||||
input_lengths.push(next_len + 31);
|
||||
next_len += BLOCK_LEN;
|
||||
}
|
||||
for input_len in input_lengths {
|
||||
dbg!(input_len);
|
||||
for counter in INITIAL_COUNTERS {
|
||||
dbg!(counter);
|
||||
let portable_output = portable::implementation().universal_hash(
|
||||
&input_buf[..input_len],
|
||||
&TEST_KEY,
|
||||
counter,
|
||||
);
|
||||
let test_output = test_impl.universal_hash(&input_buf[..input_len], &TEST_KEY, counter);
|
||||
assert_eq!(portable_output, test_output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reference_impl_universal_hash(input: &[u8], key: &CVBytes) -> [u8; UNIVERSAL_HASH_LEN] {
|
||||
// The reference_impl doesn't support XOF seeking, so we have to materialize an entire extended
|
||||
// output to seek to a block.
|
||||
const MAX_BLOCKS: usize = 2 * MAX_SIMD_DEGREE;
|
||||
assert!(input.len() / BLOCK_LEN <= MAX_BLOCKS);
|
||||
let mut output_buffer: [u8; BLOCK_LEN * MAX_BLOCKS] = [0u8; BLOCK_LEN * MAX_BLOCKS];
|
||||
let mut result = [0u8; UNIVERSAL_HASH_LEN];
|
||||
let mut block_start = 0;
|
||||
while block_start < input.len() {
|
||||
let block_len = cmp::min(input.len() - block_start, BLOCK_LEN);
|
||||
let mut ref_hasher = reference_impl::Hasher::new_keyed(key);
|
||||
ref_hasher.update(&input[block_start..block_start + block_len]);
|
||||
ref_hasher.finalize(&mut output_buffer[..block_start + UNIVERSAL_HASH_LEN]);
|
||||
for byte_index in 0..UNIVERSAL_HASH_LEN {
|
||||
result[byte_index] ^= output_buffer[block_start + byte_index];
|
||||
}
|
||||
block_start += BLOCK_LEN;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn test_universal_hash_vs_reference(test_impl: &Implementation) {
|
||||
const MAX_INPUT_LEN: usize = 2 * MAX_SIMD_DEGREE * BLOCK_LEN;
|
||||
let mut input_buf = [0; MAX_INPUT_LEN];
|
||||
paint_test_input(&mut input_buf);
|
||||
// Try equal to and partway through every whole number of input blocks.
|
||||
let mut input_lengths = vec![0, 1, 31];
|
||||
let mut next_len = BLOCK_LEN;
|
||||
loop {
|
||||
input_lengths.push(next_len);
|
||||
if next_len == MAX_INPUT_LEN {
|
||||
break;
|
||||
}
|
||||
input_lengths.push(next_len + 31);
|
||||
next_len += BLOCK_LEN;
|
||||
}
|
||||
for input_len in input_lengths {
|
||||
dbg!(input_len);
|
||||
let ref_output = reference_impl_universal_hash(&input_buf[..input_len], &TEST_KEY);
|
||||
let test_output = test_impl.universal_hash(&input_buf[..input_len], &TEST_KEY, 0);
|
||||
assert_eq!(ref_output, test_output);
|
||||
}
|
||||
}
|
||||
|
|
61
src/test.rs
61
src/test.rs
|
@ -51,67 +51,6 @@ pub const TEST_CASES_MAX: usize = 100 * CHUNK_LEN;
|
|||
pub const TEST_KEY: &CVBytes = b"whats the Elvish word for friend";
|
||||
pub const TEST_KEY_WORDS: &CVWords = &guts::words_from_le_bytes_32(TEST_KEY);
|
||||
|
||||
type UniversalHashFn =
|
||||
unsafe fn(input: &[u8], key: &[u32; 8], counter: u64) -> [u8; UNIVERSAL_HASH_LEN];
|
||||
|
||||
pub fn test_universal_hash_fn(target_fn: UniversalHashFn) {
|
||||
// 31 (16 + 8 + 4 + 2 + 1) inputs
|
||||
const NUM_INPUTS: usize = 31;
|
||||
let mut input_buf = [0; BLOCK_LEN * NUM_INPUTS];
|
||||
paint_test_input(&mut input_buf);
|
||||
for len in [0, 1, BLOCK_LEN, BLOCK_LEN + 1, input_buf.len()] {
|
||||
for &counter in INITIAL_COUNTERS {
|
||||
let portable_output =
|
||||
crate::portable::universal_hash(&input_buf[..len], TEST_KEY_WORDS, counter);
|
||||
let test_output = unsafe { target_fn(&input_buf[..len], TEST_KEY_WORDS, counter) };
|
||||
assert_eq!(portable_output, test_output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reference_impl_universal_hash(
|
||||
input: &[u8],
|
||||
key: &[u8; crate::KEY_LEN],
|
||||
) -> [u8; UNIVERSAL_HASH_LEN] {
|
||||
// The reference_impl doesn't support XOF seeking, so we have to materialize an entire extended
|
||||
// output to seek to a block.
|
||||
const MAX_BLOCKS: usize = 31;
|
||||
assert!(input.len() / BLOCK_LEN <= MAX_BLOCKS);
|
||||
let mut output_buffer: [u8; BLOCK_LEN * MAX_BLOCKS] = [0u8; BLOCK_LEN * MAX_BLOCKS];
|
||||
let mut result = [0u8; UNIVERSAL_HASH_LEN];
|
||||
let mut i = 0;
|
||||
while i == 0 || i < input.len() {
|
||||
let block_len = cmp::min(input.len() - i, BLOCK_LEN);
|
||||
let mut reference_hasher = reference_impl::Hasher::new_keyed(key);
|
||||
reference_hasher.update(&input[i..i + block_len]);
|
||||
reference_hasher.finalize(&mut output_buffer);
|
||||
for (result_byte, output_byte) in result
|
||||
.iter_mut()
|
||||
.zip(output_buffer[i..i + UNIVERSAL_HASH_LEN].iter())
|
||||
{
|
||||
*result_byte ^= *output_byte;
|
||||
}
|
||||
i += BLOCK_LEN;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare_reference_impl_universal_hash() {
|
||||
const NUM_INPUTS: usize = 31;
|
||||
let mut input_buf = [0; BLOCK_LEN * NUM_INPUTS];
|
||||
paint_test_input(&mut input_buf);
|
||||
for len in [0, 1, BLOCK_LEN, BLOCK_LEN + 1, input_buf.len()] {
|
||||
let reference_output = reference_impl_universal_hash(&input_buf[..len], TEST_KEY);
|
||||
let test_output = crate::platform::Platform::detect().universal_hash(
|
||||
&input_buf[..len],
|
||||
TEST_KEY_WORDS,
|
||||
0,
|
||||
);
|
||||
assert_eq!(reference_output, test_output);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_key_bytes_equal_key_words() {
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in New Issue