1
0
Fork 0
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:
Jack O'Connor 2023-07-09 20:47:29 -07:00
parent 2c62c3ba6c
commit 8d63b946eb
4 changed files with 87 additions and 65 deletions

View File

@ -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

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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!(