ab_blake3/
single_block.rs1#[cfg(test)]
7mod tests;
8
9#[cfg(not(target_arch = "spirv"))]
11use crate::platform::{le_bytes_from_words_32, words_from_le_bytes_32};
12#[cfg(not(target_arch = "spirv"))]
14use crate::{
15 BLOCK_LEN, BlockBytes, DERIVE_KEY_CONTEXT, DERIVE_KEY_MATERIAL, KEY_LEN, KEYED_HASH, OUT_LEN,
16};
17use crate::{BlockWords, CHUNK_END, CHUNK_START, CVWords, IV, ROOT, portable};
18#[cfg(not(target_arch = "spirv"))]
20use blake3::IncrementCounter;
21#[cfg(not(target_arch = "spirv"))]
23use blake3::platform::Platform;
24
25#[cfg(not(target_arch = "spirv"))]
28#[inline(always)]
29fn hash_block(input: &[u8], key: CVWords, flags: u8) -> Option<[u8; OUT_LEN]> {
30 if input.len() > BLOCK_LEN {
32 return None;
33 }
34
35 let mut cv = key;
36
37 let mut block = [0; BLOCK_LEN];
38 block[..input.len()].copy_from_slice(input);
39 Platform::detect().compress_in_place(
40 &mut cv,
41 &block,
42 input.len() as u8,
43 0,
44 flags | CHUNK_START | CHUNK_END | ROOT,
45 );
46
47 Some(*le_bytes_from_words_32(&cv))
48}
49
50#[cfg(not(target_arch = "spirv"))]
53#[inline(always)]
54fn hash_block_many_exact<const NUM_BLOCKS: usize>(
55 inputs: &[BlockBytes; NUM_BLOCKS],
56 outputs: &mut [[u8; OUT_LEN]; NUM_BLOCKS],
59 key: CVWords,
60 flags: u8,
61) {
62 let platform = Platform::detect();
63
64 let (input_chunks, remaining_inputs) = inputs.as_chunks::<16>();
65 let (output_chunks, remaining_output_chunks) = outputs.as_chunks_mut::<16>();
66
67 for (inputs, outputs) in input_chunks.iter().zip(output_chunks) {
68 platform.hash_many(
71 &inputs.each_ref(),
72 &key,
73 0,
74 IncrementCounter::No,
75 flags | CHUNK_START | CHUNK_END | ROOT,
76 0,
77 0,
78 outputs.as_flattened_mut(),
79 );
80 }
81
82 for (input, output) in remaining_inputs.iter().zip(remaining_output_chunks) {
83 let mut cv = key;
84
85 platform.compress_in_place(
86 &mut cv,
87 input,
88 BLOCK_LEN as u8,
89 0,
90 flags | CHUNK_START | CHUNK_END | ROOT,
91 );
92
93 output.copy_from_slice(le_bytes_from_words_32(&cv))
94 }
95}
96
97#[cfg(not(target_arch = "spirv"))]
102#[inline]
103#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
104pub fn single_block_hash(input: &[u8]) -> Option<[u8; OUT_LEN]> {
105 hash_block(input, *IV, 0)
106}
107
108#[cfg(not(target_arch = "spirv"))]
111#[inline]
112#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
113pub fn single_block_hash_many_exact<const NUM_BLOCKS: usize>(
114 inputs: &[BlockBytes; NUM_BLOCKS],
115 outputs: &mut [[u8; OUT_LEN]; NUM_BLOCKS],
118) {
119 hash_block_many_exact(inputs, outputs, *IV, 0)
120}
121
122#[cfg(not(target_arch = "spirv"))]
127#[inline]
128#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
129pub fn single_block_keyed_hash(key: &[u8; KEY_LEN], input: &[u8]) -> Option<[u8; OUT_LEN]> {
130 let key_words = words_from_le_bytes_32(key);
131 hash_block(input, key_words, KEYED_HASH)
132}
133
134#[cfg(not(target_arch = "spirv"))]
137#[inline]
138#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
139pub fn single_block_keyed_hash_many_exact<const NUM_BLOCKS: usize>(
140 key: &[u8; KEY_LEN],
141 inputs: &[BlockBytes; NUM_BLOCKS],
142 outputs: &mut [[u8; OUT_LEN]; NUM_BLOCKS],
145) {
146 let key_words = words_from_le_bytes_32(key);
147 hash_block_many_exact(inputs, outputs, key_words, KEYED_HASH)
148}
149
150#[cfg(not(target_arch = "spirv"))]
155#[inline]
156#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
157pub fn single_block_derive_key(context: &str, key_material: &[u8]) -> Option<[u8; OUT_LEN]> {
158 let context_key = hash_block(context.as_bytes(), *IV, DERIVE_KEY_CONTEXT)?;
159 let context_key_words = words_from_le_bytes_32(&context_key);
160 hash_block(key_material, context_key_words, DERIVE_KEY_MATERIAL)
161}
162
163#[inline]
178#[cfg_attr(feature = "no-panic", no_panic::no_panic)]
179pub fn single_block_hash_portable_words(input: &BlockWords, num_bytes: u32) -> CVWords {
180 let mut cv = *IV;
181
182 portable::compress_in_place_u32(
183 &mut cv,
184 input,
185 num_bytes,
186 0,
187 (CHUNK_START | CHUNK_END | ROOT) as u32,
188 );
189
190 cv
191}