1
0
Fork 0
mirror of https://github.com/BLAKE3-team/BLAKE3 synced 2024-06-07 07:06:05 +02:00

move compression function tests

This commit is contained in:
Jack O'Connor 2023-07-09 14:39:43 -07:00
parent 5ee3d75afa
commit 41ebf95fe2
5 changed files with 106 additions and 42 deletions

View File

@ -11,3 +11,6 @@ edition = "2021"
[dependencies]
cfg-if = "1.0.0"
[dev-dependencies]
reference_impl = { path = "../../reference_impl" }

View File

@ -6,6 +6,10 @@ use core::sync::atomic::{AtomicPtr, Ordering::Relaxed};
mod portable;
#[cfg(test)]
mod test;
pub const OUT_LEN: usize = 32;
pub const BLOCK_LEN: usize = 64;
pub const CHUNK_LEN: usize = 1024;
pub const WORD_LEN: usize = 4;

View File

@ -189,3 +189,19 @@ pub unsafe extern "C" fn universal_hash(
) {
crate::universal_hash_using_compress(compress, input, input_len, key, counter, out)
}
#[cfg(test)]
mod test {
use super::*;
// This is circular but do it anyway.
#[test]
fn test_compress_vs_portable() {
crate::test::test_compress_vs_portable(compress);
}
#[test]
fn test_compress_vs_reference() {
crate::test::test_compress_vs_reference(compress);
}
}

View File

@ -0,0 +1,80 @@
use crate::*;
pub const TEST_KEY: CVBytes = *b"whats the Elvish word for friend";
// Test a few different initial counter values.
// - 0: The base case.
// - i32::MAX: *No* overflow. But carry bugs in tricky SIMD code can screw this up, if you XOR when
// you're supposed to ANDNOT.
// - u32::MAX: The low word of the counter overflows for all inputs except the first.
// - (42 << 32) + u32::MAX: Same but with a non-zero value in the high word.
const INITIAL_COUNTERS: [u64; 4] = [
0,
i32::MAX as u64,
u32::MAX as u64,
(42u64 << 32) + u32::MAX as u64,
];
const BLOCK_LENGTHS: [usize; 4] = [0, 1, 63, 64];
pub fn paint_test_input(buf: &mut [u8]) {
for (i, b) in buf.iter_mut().enumerate() {
*b = (i % 251) as u8;
}
}
pub fn test_compress_vs_portable(compress_fn: CompressFn) {
let flags = KEYED_HASH;
for block_len in BLOCK_LENGTHS {
dbg!(block_len);
let mut block = [0; BLOCK_LEN];
paint_test_input(&mut block[..block_len]);
for counter in INITIAL_COUNTERS {
dbg!(counter);
let portable_cv = Implementation::portable().compress(
&block,
block_len as u32,
&TEST_KEY,
counter,
flags,
);
let mut test_cv = TEST_KEY;
unsafe {
let test_cv_ptr: *mut CVBytes = &mut test_cv;
compress_fn(
&block,
block_len as u32,
test_cv_ptr,
counter,
flags,
test_cv_ptr,
);
}
assert_eq!(portable_cv, test_cv);
}
}
}
pub fn test_compress_vs_reference(compress_fn: CompressFn) {
let flags = CHUNK_START | CHUNK_END | ROOT | KEYED_HASH;
for block_len in BLOCK_LENGTHS {
dbg!(block_len);
let mut block = [0; BLOCK_LEN];
paint_test_input(&mut block[..block_len]);
let mut ref_hasher = reference_impl::Hasher::new_keyed(&TEST_KEY);
ref_hasher.update(&block[..block_len]);
let mut ref_hash = [0u8; 32];
ref_hasher.finalize(&mut ref_hash);
let mut test_cv = TEST_KEY;
unsafe {
let test_cv_ptr: *mut CVBytes = &mut test_cv;
compress_fn(&block, block_len as u32, test_cv_ptr, 0, flags, test_cv_ptr);
}
assert_eq!(ref_hash, test_cv);
}
}

View File

@ -1,9 +1,6 @@
use crate::platform::{ParentInOut, TransposedVectors, MAX_SIMD_DEGREE};
use crate::{
CVBytes, CVWords, IncrementCounter, BLOCK_LEN, CHUNK_LEN, OUT_LEN, UNIVERSAL_HASH_LEN,
};
use blake3_guts as guts;
use guts::{CVBytes, CVWords, BLOCK_LEN, CHUNK_LEN, OUT_LEN, UNIVERSAL_HASH_LEN};
use arrayref::array_ref;
use arrayvec::ArrayVec;
use core::cmp;
use core::usize;
@ -52,9 +49,7 @@ pub const TEST_CASES_MAX: usize = 100 * CHUNK_LEN;
// There's a test to make sure these two are equal below.
pub const TEST_KEY: &CVBytes = b"whats the Elvish word for friend";
pub const TEST_KEY_WORDS: &CVWords = &[
1952540791, 1752440947, 1816469605, 1752394102, 1919907616, 1868963940, 1919295602, 1684956521,
];
pub const TEST_KEY_WORDS: &CVWords = &guts::words_from_le_bytes_32(TEST_KEY);
// Test a few different initial counter values.
// - 0: The base case.
@ -73,40 +68,6 @@ pub fn paint_test_input(buf: &mut [u8]) {
}
}
type CompressInPlaceFn =
unsafe fn(cv: &mut CVWords, block: &[u8; BLOCK_LEN], block_len: u8, counter: u64, flags: u8);
type CompressXofFn = unsafe fn(
cv: &CVWords,
block: &[u8; BLOCK_LEN],
block_len: u8,
counter: u64,
flags: u8,
) -> [u8; 64];
// A shared helper function for platform-specific tests.
pub fn test_compress_fn(compress_in_place_fn: CompressInPlaceFn, compress_xof_fn: CompressXofFn) {
let initial_state = *TEST_KEY_WORDS;
let block_len: u8 = 61;
let mut block = [0; BLOCK_LEN];
paint_test_input(&mut block[..block_len as usize]);
// Use a counter with set bits in both 32-bit words.
let counter = (5u64 << 32) + 6;
let flags = crate::CHUNK_END | crate::ROOT | crate::KEYED_HASH;
let portable_out =
crate::portable::compress_xof(&initial_state, &block, block_len, counter as u64, flags);
let mut test_state = initial_state;
unsafe { compress_in_place_fn(&mut test_state, &block, block_len, counter as u64, flags) };
let test_state_bytes = crate::platform::le_bytes_from_words_32(&test_state);
let test_xof =
unsafe { compress_xof_fn(&initial_state, &block, block_len, counter as u64, flags) };
assert_eq!(&portable_out[..32], &test_state_bytes[..]);
assert_eq!(&portable_out[..], &test_xof[..]);
}
type HashManyFn<A> = unsafe fn(
inputs: &[&A],
key: &CVWords,