mirror of
https://github.com/BLAKE3-team/BLAKE3
synced 2024-05-28 13:46:02 +02:00
let the portable implementations handle any degree
This commit is contained in:
parent
01f5e7e6d7
commit
4761fd1bb6
|
@ -1,4 +1,4 @@
|
|||
use crate::platform::{ParentInOut, TransposedVectors};
|
||||
use crate::platform::{ParentInOut, TransposedVectors, MAX_SIMD_DEGREE};
|
||||
use crate::{
|
||||
counter_high, counter_low, CVBytes, CVWords, IncrementCounter, BLOCK_LEN, CHUNK_LEN, IV,
|
||||
MSG_SCHEDULE, OUT_LEN, UNIVERSAL_HASH_LEN,
|
||||
|
@ -179,11 +179,6 @@ pub fn hash_many<const N: usize>(
|
|||
}
|
||||
}
|
||||
|
||||
// Using DEGREE=2 instead of DEGREE=1 here (and so guaranteeing that all vectorized implementations
|
||||
// have DEGREE>=2) makes it easier to avoid screwing up the root parent node in a recursive hash.
|
||||
#[cfg(test)]
|
||||
pub const DEGREE: usize = 2;
|
||||
|
||||
/// General contract:
|
||||
/// - `input` is N chunks, each exactly 1 KiB, 1 <= N <= DEGREE
|
||||
/// - `output_column` is a multiple of DEGREE.
|
||||
|
@ -191,8 +186,8 @@ pub const DEGREE: usize = 2;
|
|||
/// from `output_column` to `output_column+N-1`. Columns prior to `output_column` must be
|
||||
/// unmodified.
|
||||
///
|
||||
/// The DEGREE of this portable implementation is 2, so the input here is either exactly 1 KiB or
|
||||
/// exactly 2 KiB.
|
||||
/// This portable implementation has no particular DEGREE. It will accept any number of chunks up
|
||||
/// to MAX_SIMD_DEGREE.
|
||||
pub fn hash_chunks(
|
||||
input: &[u8],
|
||||
key: &[u32; 8],
|
||||
|
@ -201,8 +196,9 @@ pub fn hash_chunks(
|
|||
output: &mut TransposedVectors,
|
||||
output_column: usize,
|
||||
) {
|
||||
debug_assert!(input.len() == CHUNK_LEN || input.len() == 2 * CHUNK_LEN);
|
||||
debug_assert_eq!(input.len() % CHUNK_LEN, 0);
|
||||
let num_chunks = input.len() / CHUNK_LEN;
|
||||
debug_assert!(num_chunks <= MAX_SIMD_DEGREE);
|
||||
for chunk_index in 0..num_chunks {
|
||||
let mut cv = *key;
|
||||
for block_index in 0..16 {
|
||||
|
@ -230,14 +226,15 @@ pub fn hash_chunks(
|
|||
/// General contract:
|
||||
/// - `cvs` contains `2*num_parents` transposed CVs, 1 <= num_parents <= DEGREE, starting at column 0
|
||||
/// There may be additional CVs present beyond the `2*num_parents` CVs indicated, but this function
|
||||
/// isn't aware of them and must not modify them. No flags are set internally (the caller must set
|
||||
/// `PARENT` in `flags`). Writes `num_parents` transposed parent CVs to the output, starting at
|
||||
/// column 0.
|
||||
/// isn't aware of them and must not modify them. (The caller will take care of an odd remaining
|
||||
/// CV, if any.) No flags are set internally. (The caller must set `PARENT` in `flags`). Writes
|
||||
/// `num_parents` transposed parent CVs to the output, starting at column 0.
|
||||
///
|
||||
/// The DEGREE of this portable implementation is 2, so num_parents is either 1 or 2.
|
||||
/// This portable implementation has no particular DEGREE. It will accept any number of parents up
|
||||
/// to MAX_SIMD_DEGREE.
|
||||
pub fn hash_parents(mut in_out: ParentInOut, key: &[u32; 8], flags: u8) {
|
||||
let (_, num_parents) = in_out.input();
|
||||
debug_assert!(num_parents == 1 || num_parents == 2);
|
||||
debug_assert!(num_parents <= MAX_SIMD_DEGREE);
|
||||
for parent_index in 0..num_parents {
|
||||
let (input, _) = in_out.input();
|
||||
let mut block = [0u8; BLOCK_LEN];
|
||||
|
@ -340,14 +337,20 @@ pub mod test {
|
|||
crate::test::test_hash_many_fn(hash_many, hash_many);
|
||||
}
|
||||
|
||||
// The portable implementations of the vectorized APIs aren't actually vectorized and don't
|
||||
// have any inherent DEGREE. They loop internally over any number of inputs. Here we
|
||||
// arbitrarily pick degree 4 to test them (against themselves, so not an especially interesting
|
||||
// test).
|
||||
const TEST_DEGREE: usize = 4;
|
||||
|
||||
#[test]
|
||||
fn test_hash_chunks() {
|
||||
crate::test::test_hash_chunks_fn(hash_chunks, DEGREE);
|
||||
crate::test::test_hash_chunks_fn(hash_chunks, TEST_DEGREE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_parents() {
|
||||
crate::test::test_hash_parents_fn(hash_parents, DEGREE);
|
||||
crate::test::test_hash_parents_fn(hash_parents, TEST_DEGREE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
103
src/test.rs
103
src/test.rs
|
@ -249,18 +249,23 @@ pub fn test_hash_chunks_fn(target_fn: HashChunksFn, degree: usize) {
|
|||
);
|
||||
}
|
||||
|
||||
// Here always hash one chunk at a time, even though portable::DEGREE is 2.
|
||||
let mut portable_output = TransposedVectors::default();
|
||||
for i in 0..(2 * test_degree) {
|
||||
crate::portable::hash_chunks(
|
||||
&input[i * CHUNK_LEN..][..CHUNK_LEN],
|
||||
TEST_KEY_WORDS,
|
||||
initial_counter + i as u64,
|
||||
crate::KEYED_HASH,
|
||||
&mut portable_output,
|
||||
i,
|
||||
);
|
||||
}
|
||||
crate::portable::hash_chunks(
|
||||
&input[..test_degree * CHUNK_LEN],
|
||||
TEST_KEY_WORDS,
|
||||
initial_counter,
|
||||
crate::KEYED_HASH,
|
||||
&mut portable_output,
|
||||
0,
|
||||
);
|
||||
crate::portable::hash_chunks(
|
||||
&input[test_degree * CHUNK_LEN..][..test_degree * CHUNK_LEN],
|
||||
TEST_KEY_WORDS,
|
||||
initial_counter + test_degree as u64,
|
||||
crate::KEYED_HASH,
|
||||
&mut portable_output,
|
||||
test_degree,
|
||||
);
|
||||
|
||||
assert_eq!(portable_output.0, test_output.0);
|
||||
}
|
||||
|
@ -302,22 +307,16 @@ pub fn test_hash_parents_fn(target_fn: HashParentsFn, degree: usize) {
|
|||
}
|
||||
|
||||
let mut portable_output = TransposedVectors(input.0);
|
||||
for i in 0..test_degree {
|
||||
for row in 0..8 {
|
||||
input[row][0] = input[row][2 * i];
|
||||
input[row][1] = input[row][2 * i + 1];
|
||||
}
|
||||
crate::portable::hash_parents(
|
||||
ParentInOut::Separate {
|
||||
input: &input,
|
||||
num_parents: 1,
|
||||
output: &mut portable_output,
|
||||
output_column: i,
|
||||
},
|
||||
TEST_KEY_WORDS,
|
||||
crate::KEYED_HASH | crate::PARENT,
|
||||
);
|
||||
}
|
||||
crate::portable::hash_parents(
|
||||
ParentInOut::Separate {
|
||||
input: &input,
|
||||
num_parents: test_degree,
|
||||
output: &mut portable_output,
|
||||
output_column: 0,
|
||||
},
|
||||
TEST_KEY_WORDS,
|
||||
crate::KEYED_HASH | crate::PARENT,
|
||||
);
|
||||
|
||||
assert_eq!(portable_output.0, test_output.0);
|
||||
}
|
||||
|
@ -337,28 +336,18 @@ pub fn test_hash_parents_fn(target_fn: HashParentsFn, degree: usize) {
|
|||
);
|
||||
}
|
||||
|
||||
let mut portable_input = TransposedVectors::default();
|
||||
let mut portable_output = TransposedVectors::default();
|
||||
paint_transposed_input(&mut portable_input);
|
||||
paint_transposed_input(&mut portable_output);
|
||||
for i in 0..test_degree {
|
||||
for row in 0..8 {
|
||||
portable_input[row][0] = portable_input[row][2 * i];
|
||||
portable_input[row][1] = portable_input[row][2 * i + 1];
|
||||
}
|
||||
crate::portable::hash_parents(
|
||||
ParentInOut::Separate {
|
||||
input: &portable_input,
|
||||
num_parents: 1,
|
||||
output: &mut portable_output,
|
||||
output_column: i,
|
||||
},
|
||||
TEST_KEY_WORDS,
|
||||
crate::KEYED_HASH | crate::PARENT,
|
||||
);
|
||||
}
|
||||
let mut portable_io = TransposedVectors::default();
|
||||
paint_transposed_input(&mut portable_io);
|
||||
crate::portable::hash_parents(
|
||||
ParentInOut::InPlace {
|
||||
in_out: &mut portable_io,
|
||||
num_parents: test_degree,
|
||||
},
|
||||
TEST_KEY_WORDS,
|
||||
crate::KEYED_HASH | crate::PARENT,
|
||||
);
|
||||
|
||||
assert_eq!(portable_output.0, test_io.0);
|
||||
assert_eq!(portable_io.0, test_io.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -432,6 +421,7 @@ fn root_hash_with_chunks_and_parents(
|
|||
degree: usize,
|
||||
input: &[u8],
|
||||
) -> [u8; 32] {
|
||||
assert_eq!(degree.count_ones(), 1, "power of 2");
|
||||
// TODO: handle the 1-chunk case?
|
||||
assert!(input.len() >= 2 * CHUNK_LEN);
|
||||
// TODO: hash partial chunks?
|
||||
|
@ -486,19 +476,20 @@ pub fn test_compare_reference_impl_chunks_and_hashes() {
|
|||
#[cfg(feature = "std")]
|
||||
dbg!(num_chunks);
|
||||
|
||||
let test_output = root_hash_with_chunks_and_parents(
|
||||
crate::portable::hash_chunks,
|
||||
crate::portable::hash_parents,
|
||||
crate::portable::DEGREE,
|
||||
&input[..num_chunks * CHUNK_LEN],
|
||||
);
|
||||
|
||||
let mut reference_output = [0u8; 32];
|
||||
let mut reference_hasher = reference_impl::Hasher::new();
|
||||
reference_hasher.update(&input[..num_chunks * CHUNK_LEN]);
|
||||
reference_hasher.finalize(&mut reference_output);
|
||||
|
||||
assert_eq!(reference_output, test_output);
|
||||
for test_degree in [2, 4, 8, 16] {
|
||||
let test_output = root_hash_with_chunks_and_parents(
|
||||
crate::portable::hash_chunks,
|
||||
crate::portable::hash_parents,
|
||||
test_degree,
|
||||
&input[..num_chunks * CHUNK_LEN],
|
||||
);
|
||||
assert_eq!(reference_output, test_output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue