mirror of
https://github.com/BLAKE3-team/BLAKE3
synced 2024-05-28 01:16:02 +02:00
move xof tests
This commit is contained in:
parent
097225a43c
commit
2c62c3ba6c
|
@ -233,4 +233,15 @@ mod test {
|
|||
fn test_chunks_and_parents_vs_reference() {
|
||||
crate::test::test_chunks_and_parents_vs_reference(&implementation());
|
||||
}
|
||||
|
||||
// This is circular but do it anyway.
|
||||
#[test]
|
||||
fn test_xof_vs_portable() {
|
||||
crate::test::test_xof_vs_portable(&implementation());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xof_vs_reference() {
|
||||
crate::test::test_xof_vs_reference(&implementation());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,12 +98,13 @@ pub fn test_hash_chunks_vs_portable(test_impl: &Implementation) {
|
|||
let mut input_2_lengths = vec![1];
|
||||
let mut next_len = CHUNK_LEN;
|
||||
loop {
|
||||
input_2_lengths.push(next_len - 1);
|
||||
// 95 is one whole block plus one interesting part of another
|
||||
input_2_lengths.push(next_len - 95);
|
||||
input_2_lengths.push(next_len);
|
||||
if next_len == MAX_SIMD_DEGREE * CHUNK_LEN {
|
||||
break;
|
||||
}
|
||||
input_2_lengths.push(next_len + 1);
|
||||
input_2_lengths.push(next_len + 95);
|
||||
next_len += CHUNK_LEN;
|
||||
}
|
||||
for input_2_len in input_2_lengths {
|
||||
|
@ -257,12 +258,13 @@ pub fn test_chunks_and_parents_vs_reference(test_impl: &Implementation) {
|
|||
let mut test_lengths = vec![CHUNK_LEN + 1];
|
||||
let mut next_len = 2 * CHUNK_LEN;
|
||||
loop {
|
||||
test_lengths.push(next_len - 1);
|
||||
// 95 is one whole block plus one interesting part of another
|
||||
test_lengths.push(next_len - 95);
|
||||
test_lengths.push(next_len);
|
||||
if next_len == MAX_INPUT_LEN {
|
||||
break;
|
||||
}
|
||||
test_lengths.push(next_len + 1);
|
||||
test_lengths.push(next_len + 95);
|
||||
next_len += CHUNK_LEN;
|
||||
}
|
||||
for test_len in test_lengths {
|
||||
|
@ -279,3 +281,135 @@ pub fn test_chunks_and_parents_vs_reference(test_impl: &Implementation) {
|
|||
assert_eq!(ref_hash, test_hash);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_xof_vs_portable(test_impl: &Implementation) {
|
||||
let flags = CHUNK_START | CHUNK_END | ROOT | KEYED_HASH;
|
||||
for counter in INITIAL_COUNTERS {
|
||||
dbg!(counter);
|
||||
for input_len in [0, 1, BLOCK_LEN] {
|
||||
dbg!(input_len);
|
||||
let mut input_block = [0u8; BLOCK_LEN];
|
||||
for byte_index in 0..input_len {
|
||||
input_block[byte_index] = byte_index as u8 + 42;
|
||||
}
|
||||
// Try equal to and partway through every whole number of output blocks.
|
||||
const MAX_OUTPUT_LEN: usize = 2 * MAX_SIMD_DEGREE * BLOCK_LEN;
|
||||
let mut output_lengths = Vec::new();
|
||||
let mut next_len = 0;
|
||||
loop {
|
||||
output_lengths.push(next_len);
|
||||
if next_len == MAX_OUTPUT_LEN {
|
||||
break;
|
||||
}
|
||||
output_lengths.push(next_len + 31);
|
||||
next_len += BLOCK_LEN;
|
||||
}
|
||||
for output_len in output_lengths {
|
||||
dbg!(output_len);
|
||||
let mut portable_output = [0xff; MAX_OUTPUT_LEN];
|
||||
portable::implementation().xof(
|
||||
&input_block,
|
||||
input_len as u32,
|
||||
&TEST_KEY,
|
||||
counter,
|
||||
flags,
|
||||
&mut portable_output[..output_len],
|
||||
);
|
||||
let mut test_output = [0xff; MAX_OUTPUT_LEN];
|
||||
test_impl.xof(
|
||||
&input_block,
|
||||
input_len as u32,
|
||||
&TEST_KEY,
|
||||
counter,
|
||||
flags,
|
||||
&mut test_output[..output_len],
|
||||
);
|
||||
assert_eq!(portable_output, test_output);
|
||||
|
||||
// Double check that the implementation didn't overwrite.
|
||||
assert!(test_output[output_len..].iter().all(|&b| b == 0xff));
|
||||
|
||||
// The first XOR cancels out the output.
|
||||
test_impl.xof_xor(
|
||||
&input_block,
|
||||
input_len as u32,
|
||||
&TEST_KEY,
|
||||
counter,
|
||||
flags,
|
||||
&mut test_output[..output_len],
|
||||
);
|
||||
assert!(test_output[..output_len].iter().all(|&b| b == 0));
|
||||
assert!(test_output[output_len..].iter().all(|&b| b == 0xff));
|
||||
|
||||
// The second XOR restores out the output.
|
||||
test_impl.xof_xor(
|
||||
&input_block,
|
||||
input_len as u32,
|
||||
&TEST_KEY,
|
||||
counter,
|
||||
flags,
|
||||
&mut test_output[..output_len],
|
||||
);
|
||||
assert_eq!(portable_output, test_output);
|
||||
assert!(test_output[output_len..].iter().all(|&b| b == 0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_xof_vs_reference(test_impl: &Implementation) {
|
||||
let input = b"hello world";
|
||||
let mut input_block = [0; BLOCK_LEN];
|
||||
input_block[..input.len()].copy_from_slice(input);
|
||||
|
||||
const MAX_OUTPUT_LEN: usize = 2 * MAX_SIMD_DEGREE * BLOCK_LEN;
|
||||
let mut ref_output = [0; MAX_OUTPUT_LEN];
|
||||
let mut ref_hasher = reference_impl::Hasher::new_keyed(&TEST_KEY);
|
||||
ref_hasher.update(input);
|
||||
ref_hasher.finalize(&mut ref_output);
|
||||
|
||||
// Try equal to and partway through every whole number of output blocks.
|
||||
let mut output_lengths = vec![0, 1, 31];
|
||||
let mut next_len = BLOCK_LEN;
|
||||
loop {
|
||||
output_lengths.push(next_len);
|
||||
if next_len == MAX_OUTPUT_LEN {
|
||||
break;
|
||||
}
|
||||
output_lengths.push(next_len + 31);
|
||||
next_len += BLOCK_LEN;
|
||||
}
|
||||
|
||||
for output_len in output_lengths {
|
||||
dbg!(output_len);
|
||||
let mut test_output = [0; MAX_OUTPUT_LEN];
|
||||
test_impl.xof(
|
||||
&input_block,
|
||||
input.len() as u32,
|
||||
&TEST_KEY,
|
||||
0,
|
||||
crate::KEYED_HASH | crate::CHUNK_START | crate::CHUNK_END | crate::ROOT,
|
||||
&mut test_output[..output_len],
|
||||
);
|
||||
assert_eq!(ref_output[..output_len], test_output[..output_len]);
|
||||
|
||||
// Double check that the implementation didn't overwrite.
|
||||
assert!(test_output[output_len..].iter().all(|&b| b == 0));
|
||||
|
||||
// Do it again starting from block 1.
|
||||
if output_len >= BLOCK_LEN {
|
||||
test_impl.xof(
|
||||
&input_block,
|
||||
input.len() as u32,
|
||||
&TEST_KEY,
|
||||
1,
|
||||
crate::KEYED_HASH | crate::CHUNK_START | crate::CHUNK_END | crate::ROOT,
|
||||
&mut test_output[..output_len - BLOCK_LEN],
|
||||
);
|
||||
assert_eq!(
|
||||
ref_output[BLOCK_LEN..output_len],
|
||||
test_output[..output_len - BLOCK_LEN],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
137
src/test.rs
137
src/test.rs
|
@ -51,143 +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);
|
||||
|
||||
// Both xof() and xof_xof() have this signature.
|
||||
type XofFn = unsafe fn(
|
||||
block: &[u8; BLOCK_LEN],
|
||||
block_len: u8,
|
||||
cv: &[u32; 8],
|
||||
counter: u64,
|
||||
flags: u8,
|
||||
out: &mut [u8],
|
||||
);
|
||||
|
||||
pub fn test_xof_and_xor_fns(target_xof: XofFn, target_xof_xor: XofFn) {
|
||||
// 31 (16 + 8 + 4 + 2 + 1) outputs
|
||||
const NUM_OUTPUTS: usize = 31;
|
||||
let different_flags = [
|
||||
crate::CHUNK_START | crate::CHUNK_END | crate::ROOT,
|
||||
crate::PARENT | crate::ROOT | crate::KEYED_HASH,
|
||||
];
|
||||
for input_len in [0, 1, BLOCK_LEN] {
|
||||
let mut input_block = [0u8; BLOCK_LEN];
|
||||
paint_test_input(&mut input_block[..input_len]);
|
||||
for output_len in [0, 1, BLOCK_LEN, BLOCK_LEN + 1, BLOCK_LEN * NUM_OUTPUTS] {
|
||||
let mut test_output_buf = [0xff; BLOCK_LEN * NUM_OUTPUTS];
|
||||
for &counter in INITIAL_COUNTERS {
|
||||
for flags in different_flags {
|
||||
let mut expected_output_buf = [0xff; BLOCK_LEN * NUM_OUTPUTS];
|
||||
crate::portable::xof(
|
||||
&input_block,
|
||||
input_len as u8,
|
||||
TEST_KEY_WORDS,
|
||||
counter,
|
||||
flags,
|
||||
&mut expected_output_buf[..output_len],
|
||||
);
|
||||
|
||||
unsafe {
|
||||
target_xof(
|
||||
&input_block,
|
||||
input_len as u8,
|
||||
TEST_KEY_WORDS,
|
||||
counter,
|
||||
flags,
|
||||
&mut test_output_buf[..output_len],
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
expected_output_buf[..output_len],
|
||||
test_output_buf[..output_len],
|
||||
);
|
||||
// Make sure unsafe implementations don't overwrite. This shouldn't be possible in the
|
||||
// portable implementation, which is all safe code, but it could happen in others.
|
||||
assert!(test_output_buf[output_len..].iter().all(|&b| b == 0xff));
|
||||
|
||||
// The first XOR cancels out the output.
|
||||
unsafe {
|
||||
target_xof_xor(
|
||||
&input_block,
|
||||
input_len as u8,
|
||||
TEST_KEY_WORDS,
|
||||
counter,
|
||||
flags,
|
||||
&mut test_output_buf[..output_len],
|
||||
);
|
||||
}
|
||||
assert!(test_output_buf[..output_len].iter().all(|&b| b == 0));
|
||||
assert!(test_output_buf[output_len..].iter().all(|&b| b == 0xff));
|
||||
|
||||
// The second XOR restores out the output.
|
||||
unsafe {
|
||||
target_xof_xor(
|
||||
&input_block,
|
||||
input_len as u8,
|
||||
TEST_KEY_WORDS,
|
||||
counter,
|
||||
flags,
|
||||
&mut test_output_buf[..output_len],
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
expected_output_buf[..output_len],
|
||||
test_output_buf[..output_len],
|
||||
);
|
||||
assert!(test_output_buf[output_len..].iter().all(|&b| b == 0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare_reference_impl_xof() {
|
||||
const NUM_OUTPUTS: usize = 31;
|
||||
let input = b"hello world";
|
||||
let mut input_block = [0; BLOCK_LEN];
|
||||
input_block[..input.len()].copy_from_slice(input);
|
||||
|
||||
let mut reference_output_buf = [0; BLOCK_LEN * NUM_OUTPUTS];
|
||||
let mut reference_hasher = reference_impl::Hasher::new_keyed(TEST_KEY);
|
||||
reference_hasher.update(input);
|
||||
reference_hasher.finalize(&mut reference_output_buf);
|
||||
|
||||
for output_len in [0, 1, BLOCK_LEN, BLOCK_LEN + 1, BLOCK_LEN * NUM_OUTPUTS] {
|
||||
let mut test_output_buf = [0; BLOCK_LEN * NUM_OUTPUTS];
|
||||
crate::platform::Platform::detect().xof(
|
||||
&input_block,
|
||||
input.len() as u8,
|
||||
TEST_KEY_WORDS,
|
||||
0,
|
||||
crate::KEYED_HASH | crate::CHUNK_START | crate::CHUNK_END | crate::ROOT,
|
||||
&mut test_output_buf[..output_len],
|
||||
);
|
||||
assert_eq!(
|
||||
reference_output_buf[..output_len],
|
||||
test_output_buf[..output_len],
|
||||
);
|
||||
|
||||
// Make sure unsafe implementations don't overwrite. This shouldn't be possible in the
|
||||
// portable implementation, which is all safe code, but it could happen in others.
|
||||
assert!(test_output_buf[output_len..].iter().all(|&b| b == 0));
|
||||
|
||||
// Do it again starting from block 1.
|
||||
if output_len >= BLOCK_LEN {
|
||||
crate::platform::Platform::detect().xof(
|
||||
&input_block,
|
||||
input.len() as u8,
|
||||
TEST_KEY_WORDS,
|
||||
1,
|
||||
crate::KEYED_HASH | crate::CHUNK_START | crate::CHUNK_END | crate::ROOT,
|
||||
&mut test_output_buf[..output_len - BLOCK_LEN],
|
||||
);
|
||||
assert_eq!(
|
||||
reference_output_buf[BLOCK_LEN..output_len],
|
||||
test_output_buf[..output_len - BLOCK_LEN],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type UniversalHashFn =
|
||||
unsafe fn(input: &[u8], key: &[u32; 8], counter: u64) -> [u8; UNIVERSAL_HASH_LEN];
|
||||
|
||||
|
|
Loading…
Reference in New Issue