@@ -88,24 +88,30 @@ INLINE void output_chaining_value(const output_t *self, uint8_t cv[32]) {
8888
8989INLINE void output_root_bytes (const output_t * self , uint64_t seek , uint8_t * out ,
9090 size_t out_len ) {
91+ if (out_len == 0 ) {
92+ return ;
93+ }
9194 uint64_t output_block_counter = seek / 64 ;
9295 size_t offset_within_block = seek % 64 ;
9396 uint8_t wide_buf [64 ];
94- while (out_len > 0 ) {
95- blake3_compress_xof (self -> input_cv , self -> block , self -> block_len ,
96- output_block_counter , self -> flags | ROOT , wide_buf );
97- size_t available_bytes = 64 - offset_within_block ;
98- size_t memcpy_len ;
99- if (out_len > available_bytes ) {
100- memcpy_len = available_bytes ;
101- } else {
102- memcpy_len = out_len ;
103- }
104- memcpy (out , wide_buf + offset_within_block , memcpy_len );
105- out += memcpy_len ;
106- out_len -= memcpy_len ;
97+ if (offset_within_block ) {
98+ blake3_compress_xof (self -> input_cv , self -> block , self -> block_len , output_block_counter , self -> flags | ROOT , wide_buf );
99+ const size_t available_bytes = 64 - offset_within_block ;
100+ const size_t bytes = out_len > available_bytes ? available_bytes : out_len ;
101+ memcpy (out , wide_buf + offset_within_block , bytes );
102+ out += bytes ;
103+ out_len -= bytes ;
107104 output_block_counter += 1 ;
108- offset_within_block = 0 ;
105+ }
106+ if (out_len / 64 ) {
107+ blake3_xof_many (self -> input_cv , self -> block , self -> block_len , output_block_counter , self -> flags | ROOT , out , out_len / 64 );
108+ }
109+ output_block_counter += out_len / 64 ;
110+ out += out_len & -64 ;
111+ out_len -= out_len & -64 ;
112+ if (out_len ) {
113+ blake3_compress_xof (self -> input_cv , self -> block , self -> block_len , output_block_counter , self -> flags | ROOT , wide_buf );
114+ memcpy (out , wide_buf , out_len );
109115 }
110116}
111117
@@ -134,9 +140,7 @@ INLINE void chunk_state_update(blake3_chunk_state *self, const uint8_t *input,
134140 input_len -= BLAKE3_BLOCK_LEN ;
135141 }
136142
137- size_t take = chunk_state_fill_buf (self , input , input_len );
138- input += take ;
139- input_len -= take ;
143+ chunk_state_fill_buf (self , input , input_len );
140144}
141145
142146INLINE output_t chunk_state_output (const blake3_chunk_state * self ) {
@@ -154,10 +158,10 @@ INLINE output_t parent_output(const uint8_t block[BLAKE3_BLOCK_LEN],
154158// Given some input larger than one chunk, return the number of bytes that
155159// should go in the left subtree. This is the largest power-of-2 number of
156160// chunks that leaves at least 1 byte for the right subtree.
157- INLINE size_t left_len (size_t content_len ) {
158- // Subtract 1 to reserve at least one byte for the right side. content_len
161+ INLINE size_t left_subtree_len (size_t input_len ) {
162+ // Subtract 1 to reserve at least one byte for the right side. input_len
159163 // should always be greater than BLAKE3_CHUNK_LEN.
160- size_t full_chunks = (content_len - 1 ) / BLAKE3_CHUNK_LEN ;
164+ size_t full_chunks = (input_len - 1 ) / BLAKE3_CHUNK_LEN ;
161165 return round_down_to_power_of_2 (full_chunks ) * BLAKE3_CHUNK_LEN ;
162166}
163167
@@ -246,26 +250,25 @@ INLINE size_t compress_parents_parallel(const uint8_t *child_chaining_values,
246250
247251// The wide helper function returns (writes out) an array of chaining values
248252// and returns the length of that array. The number of chaining values returned
249- // is the dyanmically detected SIMD degree, at most MAX_SIMD_DEGREE. Or fewer,
253+ // is the dynamically detected SIMD degree, at most MAX_SIMD_DEGREE. Or fewer,
250254// if the input is shorter than that many chunks. The reason for maintaining a
251255// wide array of chaining values going back up the tree, is to allow the
252256// implementation to hash as many parents in parallel as possible.
253257//
254258// As a special case when the SIMD degree is 1, this function will still return
255259// at least 2 outputs. This guarantees that this function doesn't perform the
256260// root compression. (If it did, it would use the wrong flags, and also we
257- // wouldn't be able to implement exendable ouput .) Note that this function is
261+ // wouldn't be able to implement extendable output .) Note that this function is
258262// not used when the whole input is only 1 chunk long; that's a different
259263// codepath.
260264//
261265// Why not just have the caller split the input on the first update(), instead
262266// of implementing this special rule? Because we don't want to limit SIMD or
263267// multi-threading parallelism for that update().
264- static size_t blake3_compress_subtree_wide (const uint8_t * input ,
265- size_t input_len ,
266- const uint32_t key [8 ],
267- uint64_t chunk_counter ,
268- uint8_t flags , uint8_t * out ) {
268+ size_t blake3_compress_subtree_wide (const uint8_t * input , size_t input_len ,
269+ const uint32_t key [8 ],
270+ uint64_t chunk_counter , uint8_t flags ,
271+ uint8_t * out , bool use_tbb ) {
269272 // Note that the single chunk case does *not* bump the SIMD degree up to 2
270273 // when it is 1. If this implementation adds multi-threading in the future,
271274 // this gives us the option of multi-threading even the 2-chunk case, which
@@ -279,7 +282,7 @@ static size_t blake3_compress_subtree_wide(const uint8_t *input,
279282 // the input into left and right subtrees. (Note that this is only optimal
280283 // as long as the SIMD degree is a power of 2. If we ever get a SIMD degree
281284 // of 3 or something, we'll need a more complicated strategy.)
282- size_t left_input_len = left_len (input_len );
285+ size_t left_input_len = left_subtree_len (input_len );
283286 size_t right_input_len = input_len - left_input_len ;
284287 const uint8_t * right_input = & input [left_input_len ];
285288 uint64_t right_chunk_counter =
@@ -299,12 +302,24 @@ static size_t blake3_compress_subtree_wide(const uint8_t *input,
299302 }
300303 uint8_t * right_cvs = & cv_array [degree * BLAKE3_OUT_LEN ];
301304
302- // Recurse! If this implementation adds multi-threading support in the
303- // future, this is where it will go.
304- size_t left_n = blake3_compress_subtree_wide (input , left_input_len , key ,
305- chunk_counter , flags , cv_array );
306- size_t right_n = blake3_compress_subtree_wide (
307- right_input , right_input_len , key , right_chunk_counter , flags , right_cvs );
305+ // Recurse!
306+ size_t left_n = -1 ;
307+ size_t right_n = -1 ;
308+
309+ #if defined(BLAKE3_USE_TBB )
310+ blake3_compress_subtree_wide_join_tbb (
311+ key , flags , use_tbb ,
312+ // left-hand side
313+ input , left_input_len , chunk_counter , cv_array , & left_n ,
314+ // right-hand side
315+ right_input , right_input_len , right_chunk_counter , right_cvs , & right_n );
316+ #else
317+ left_n = blake3_compress_subtree_wide (
318+ input , left_input_len , key , chunk_counter , flags , cv_array , use_tbb );
319+ right_n = blake3_compress_subtree_wide (right_input , right_input_len , key ,
320+ right_chunk_counter , flags , right_cvs ,
321+ use_tbb );
322+ #endif // BLAKE3_USE_TBB
308323
309324 // The special case again. If simd_degree=1, then we'll have left_n=1 and
310325 // right_n=1. Rather than compressing them into a single output, return
@@ -330,32 +345,37 @@ static size_t blake3_compress_subtree_wide(const uint8_t *input,
330345//
331346// As with compress_subtree_wide(), this function is not used on inputs of 1
332347// chunk or less. That's a different codepath.
333- INLINE void compress_subtree_to_parent_node (
334- const uint8_t * input , size_t input_len , const uint32_t key [8 ],
335- uint64_t chunk_counter , uint8_t flags , uint8_t out [2 * BLAKE3_OUT_LEN ]) {
348+ INLINE void
349+ compress_subtree_to_parent_node (const uint8_t * input , size_t input_len ,
350+ const uint32_t key [8 ], uint64_t chunk_counter ,
351+ uint8_t flags , uint8_t out [2 * BLAKE3_OUT_LEN ],
352+ bool use_tbb ) {
336353#if defined(BLAKE3_TESTING )
337354 assert (input_len > BLAKE3_CHUNK_LEN );
338355#endif
339356
340357 uint8_t cv_array [MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN ];
341358 size_t num_cvs = blake3_compress_subtree_wide (input , input_len , key ,
342- chunk_counter , flags , cv_array );
359+ chunk_counter , flags , cv_array , use_tbb );
343360 assert (num_cvs <= MAX_SIMD_DEGREE_OR_2 );
344-
345- // If MAX_SIMD_DEGREE is greater than 2 and there's enough input,
361+ // The following loop never executes when MAX_SIMD_DEGREE_OR_2 is 2, because
362+ // as we just asserted, num_cvs will always be <=2 in that case. But GCC
363+ // (particularly GCC 8.5) can't tell that it never executes, and if NDEBUG is
364+ // set then it emits incorrect warnings here. We tried a few different
365+ // hacks to silence these, but in the end our hacks just produced different
366+ // warnings (see https://github.com/BLAKE3-team/BLAKE3/pull/380). Out of
367+ // desperation, we ifdef out this entire loop when we know it's not needed.
368+ #if MAX_SIMD_DEGREE_OR_2 > 2
369+ // If MAX_SIMD_DEGREE_OR_2 is greater than 2 and there's enough input,
346370 // compress_subtree_wide() returns more than 2 chaining values. Condense
347371 // them into 2 by forming parent nodes repeatedly.
348372 uint8_t out_array [MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN / 2 ];
349- // The second half of this loop condition is always true, and we just
350- // asserted it above. But GCC can't tell that it's always true, and if NDEBUG
351- // is set on platforms where MAX_SIMD_DEGREE_OR_2 == 2, GCC emits spurious
352- // warnings here. GCC 8.5 is particularly sensitive, so if you're changing
353- // this code, test it against that version.
354- while (num_cvs > 2 && num_cvs <= MAX_SIMD_DEGREE_OR_2 ) {
373+ while (num_cvs > 2 ) {
355374 num_cvs =
356375 compress_parents_parallel (cv_array , num_cvs , key , flags , out_array );
357376 memcpy (cv_array , out_array , num_cvs * BLAKE3_OUT_LEN );
358377 }
378+ #endif
359379 memcpy (out , cv_array , 2 * BLAKE3_OUT_LEN );
360380}
361381
@@ -427,7 +447,7 @@ INLINE void hasher_merge_cv_stack(blake3_hasher *self, uint64_t total_len) {
427447// of the whole tree, and it would need to be ROOT finalized. We can't
428448// compress it until we know.
429449// 2) This 64 KiB input might complete a larger tree, whose root node is
430- // similarly going to be the the root of the whole tree. For example, maybe
450+ // similarly going to be the root of the whole tree. For example, maybe
431451// we have 196 KiB (that is, 128 + 64) hashed so far. We can't compress the
432452// node at the root of the 256 KiB subtree until we know how to finalize it.
433453//
@@ -452,8 +472,8 @@ INLINE void hasher_push_cv(blake3_hasher *self, uint8_t new_cv[BLAKE3_OUT_LEN],
452472 self -> cv_stack_len += 1 ;
453473}
454474
455- void blake3_hasher_update (blake3_hasher * self , const void * input ,
456- size_t input_len ) {
475+ INLINE void blake3_hasher_update_base (blake3_hasher * self , const void * input ,
476+ size_t input_len , bool use_tbb ) {
457477 // Explicitly checking for zero avoids causing UB by passing a null pointer
458478 // to memcpy. This comes up in practice with things like:
459479 // std::vector<uint8_t> v;
@@ -539,7 +559,7 @@ void blake3_hasher_update(blake3_hasher *self, const void *input,
539559 uint8_t cv_pair [2 * BLAKE3_OUT_LEN ];
540560 compress_subtree_to_parent_node (input_bytes , subtree_len , self -> key ,
541561 self -> chunk .chunk_counter ,
542- self -> chunk .flags , cv_pair );
562+ self -> chunk .flags , cv_pair , use_tbb );
543563 hasher_push_cv (self , cv_pair , self -> chunk .chunk_counter );
544564 hasher_push_cv (self , & cv_pair [BLAKE3_OUT_LEN ],
545565 self -> chunk .chunk_counter + (subtree_chunks / 2 ));
@@ -561,6 +581,20 @@ void blake3_hasher_update(blake3_hasher *self, const void *input,
561581 }
562582}
563583
584+ void blake3_hasher_update (blake3_hasher * self , const void * input ,
585+ size_t input_len ) {
586+ bool use_tbb = false;
587+ blake3_hasher_update_base (self , input , input_len , use_tbb );
588+ }
589+
590+ #if defined(BLAKE3_USE_TBB )
591+ void blake3_hasher_update_tbb (blake3_hasher * self , const void * input ,
592+ size_t input_len ) {
593+ bool use_tbb = true;
594+ blake3_hasher_update_base (self , input , input_len , use_tbb );
595+ }
596+ #endif // BLAKE3_USE_TBB
597+
564598void blake3_hasher_finalize (const blake3_hasher * self , uint8_t * out ,
565599 size_t out_len ) {
566600 blake3_hasher_finalize_seek (self , 0 , out , out_len );
0 commit comments