#[cfg(test)]
mod tests;
#[cfg(not(target_arch = "spirv"))]
use crate::platform::{le_bytes_from_words_32, words_from_le_bytes_32};
#[cfg(not(target_arch = "spirv"))]
use crate::{
BLOCK_LEN, BlockBytes, DERIVE_KEY_CONTEXT, DERIVE_KEY_MATERIAL, KEY_LEN, KEYED_HASH, OUT_LEN,
};
use crate::{BlockWords, CHUNK_END, CHUNK_START, CVWords, IV, ROOT, portable};
#[cfg(not(target_arch = "spirv"))]
use blake3::IncrementCounter;
#[cfg(not(target_arch = "spirv"))]
use blake3::platform::Platform;
#[cfg(not(target_arch = "spirv"))]
#[inline(always)]
fn hash_block(input: &[u8], key: CVWords, flags: u8) -> Option<[u8; OUT_LEN]> {
if input.len() > BLOCK_LEN {
return None;
}
let mut cv = key;
let mut block = [0; BLOCK_LEN];
block[..input.len()].copy_from_slice(input);
Platform::detect().compress_in_place(
&mut cv,
&block,
input.len() as u8,
0,
flags | CHUNK_START | CHUNK_END | ROOT,
);
Some(*le_bytes_from_words_32(&cv))
}
#[cfg(not(target_arch = "spirv"))]
#[inline(always)]
fn hash_block_many_exact<const NUM_BLOCKS: usize>(
inputs: &[BlockBytes; NUM_BLOCKS],
outputs: &mut [[u8; OUT_LEN]; NUM_BLOCKS],
key: CVWords,
flags: u8,
) {
let platform = Platform::detect();
let (input_chunks, remaining_inputs) = inputs.as_chunks::<16>();
let (output_chunks, remaining_output_chunks) = outputs.as_chunks_mut::<16>();
for (inputs, outputs) in input_chunks.iter().zip(output_chunks) {
platform.hash_many(
&inputs.each_ref(),
&key,
0,
IncrementCounter::No,
flags | CHUNK_START | CHUNK_END | ROOT,
0,
0,
outputs.as_flattened_mut(),
);
}
for (input, output) in remaining_inputs.iter().zip(remaining_output_chunks) {
let mut cv = key;
platform.compress_in_place(
&mut cv,
input,
BLOCK_LEN as u8,
0,
flags | CHUNK_START | CHUNK_END | ROOT,
);
output.copy_from_slice(le_bytes_from_words_32(&cv))
}
}
#[cfg(not(target_arch = "spirv"))]
#[inline]
#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
pub fn single_block_hash(input: &[u8]) -> Option<[u8; OUT_LEN]> {
hash_block(input, *IV, 0)
}
#[cfg(not(target_arch = "spirv"))]
#[inline]
#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
pub fn single_block_hash_many_exact<const NUM_BLOCKS: usize>(
inputs: &[BlockBytes; NUM_BLOCKS],
outputs: &mut [[u8; OUT_LEN]; NUM_BLOCKS],
) {
hash_block_many_exact(inputs, outputs, *IV, 0)
}
#[cfg(not(target_arch = "spirv"))]
#[inline]
#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
pub fn single_block_keyed_hash(key: &[u8; KEY_LEN], input: &[u8]) -> Option<[u8; OUT_LEN]> {
let key_words = words_from_le_bytes_32(key);
hash_block(input, key_words, KEYED_HASH)
}
#[cfg(not(target_arch = "spirv"))]
#[inline]
#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
pub fn single_block_keyed_hash_many_exact<const NUM_BLOCKS: usize>(
key: &[u8; KEY_LEN],
inputs: &[BlockBytes; NUM_BLOCKS],
outputs: &mut [[u8; OUT_LEN]; NUM_BLOCKS],
) {
let key_words = words_from_le_bytes_32(key);
hash_block_many_exact(inputs, outputs, key_words, KEYED_HASH)
}
#[cfg(not(target_arch = "spirv"))]
#[inline]
#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
pub fn single_block_derive_key(context: &str, key_material: &[u8]) -> Option<[u8; OUT_LEN]> {
let context_key = hash_block(context.as_bytes(), *IV, DERIVE_KEY_CONTEXT)?;
let context_key_words = words_from_le_bytes_32(&context_key);
hash_block(key_material, context_key_words, DERIVE_KEY_MATERIAL)
}
#[inline]
#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
pub fn single_block_hash_portable_words(input: &BlockWords, num_bytes: u32) -> CVWords {
let mut cv = *IV;
portable::compress_in_place_u32(
&mut cv,
input,
num_bytes,
0,
(CHUNK_START | CHUNK_END | ROOT) as u32,
);
cv
}