@@ -500,17 +500,16 @@ macro_rules! blake2x_impl {
500500 impl $core_name {
501501 /// Create new core with specified output length.
502502 pub fn new( xof_len: $xof_len_type) -> Self {
503- // Root hasher construction is delegated to new_blake2x_root_hasher for deduplication and correctness.
504- $core_name {
505- root_hasher: Self :: new_blake2x_root_hasher( xof_len) ,
503+ Self {
504+ root_hasher: Self :: new_root_hasher( xof_len) ,
506505 xof_len,
507506 }
508507 }
509508
510509 /// Create new core with specified output length and a key.
511510 pub fn new_with_key( key: & [ u8 ] , xof_len: $xof_len_type) -> Self {
512- $core_name {
513- root_hasher: Self :: new_blake2x_root_hasher_with_key ( key, xof_len) ,
511+ Self {
512+ root_hasher: Self :: new_keyed_root_hasher ( key, xof_len) ,
514513 xof_len,
515514 }
516515 }
@@ -520,49 +519,38 @@ macro_rules! blake2x_impl {
520519 /// The Blake2X specification requires the total output length (xof_len) to be
521520 /// incorporated into the parameter block of the root hash computation. This ensures
522521 /// that Blake2X(M, L1) and Blake2X(M, L2) produce different outputs when L1 ≠ L2.
523- ///
524- /// This helper function encapsulates the word-size specific logic for both
525- /// Blake2b (64-bit) and Blake2s (32-bit) variants.
526- fn xof_parameter_adjustment( hasher: & mut $base_core, xof_len: $xof_len_type) {
522+ fn apply_xof_param( hasher: & mut $base_core, xof_len: $xof_len_type) {
527523 let xof_param_vec = if core:: mem:: size_of:: <$word>( ) == 8 {
528524 // Blake2b: xof_length is a u32 in the high 32-bits of parameter word p[1]
529525 let xof_param_val = ( ( xof_len as u64 ) << 32 ) as $word;
530- $vec:: new( 0 as $word, xof_param_val, 0 as $word, 0 as $word)
531-
526+ $vec:: new( 0 , xof_param_val, 0 , 0 )
532527 } else {
533- // Blake2s: xof_digest_length is a u32 in parameter word p[3].
534- // We start with a standard Blake2s parameter block and then
535- // XOR in the xof_len to modify the h state corresponding to p[3].
536- let xof_param_val = xof_len as $word;
537- // The parameter p[3] is the 4th element of the first SIMD vector.
538- $vec:: new( 0 , 0 , 0 , xof_param_val)
528+ // Blake2s: xof_digest_length is a u32 in parameter word p[3]
529+ $vec:: new( 0 , 0 , 0 , xof_len as $word)
539530 } ;
540531 hasher. h[ 0 ] = hasher. h[ 0 ] ^ xof_param_vec;
541532 #[ cfg( feature = "reset" ) ]
542533 { hasher. h0[ 0 ] = hasher. h0[ 0 ] ^ xof_param_vec; }
543534 }
544535
545536 /// Create Blake2 hasher specifically for Blake2X root hash computation.
546- fn new_blake2x_root_hasher ( xof_len: $xof_len_type) -> $base_core {
537+ fn new_root_hasher ( xof_len: $xof_len_type) -> $base_core {
547538 let mut hasher = <$base_core>:: new_with_params( & [ ] , & [ ] , 0 , $hash_size) ;
548- Self :: xof_parameter_adjustment ( & mut hasher, xof_len) ;
539+ Self :: apply_xof_param ( & mut hasher, xof_len) ;
549540 hasher
550541 }
551542
552543 /// Create Blake2 hasher for a keyed Blake2X root hash.
553- ///
554- /// This is similar to new_blake2x_root_hasher but includes the key length
555- /// in the parameter block for proper keyed hashing support.
556- fn new_blake2x_root_hasher_with_key( key: & [ u8 ] , xof_len: $xof_len_type) -> $base_core {
544+ fn new_keyed_root_hasher( key: & [ u8 ] , xof_len: $xof_len_type) -> $base_core {
557545 let mut hasher = <$base_core>:: new_with_params( & [ ] , & [ ] , key. len( ) , $hash_size) ;
558- Self :: xof_parameter_adjustment ( & mut hasher, xof_len) ;
546+ Self :: apply_xof_param ( & mut hasher, xof_len) ;
559547 hasher
560548 }
561549 }
562550
563551 impl Default for $core_name {
564552 fn default ( ) -> Self {
565- Self :: new( <$xof_len_type>:: MAX ) // Unknown size by default
553+ Self :: new( <$xof_len_type>:: MAX )
566554 }
567555 }
568556
@@ -587,10 +575,8 @@ macro_rules! blake2x_impl {
587575 type ReaderCore = $reader_name;
588576
589577 fn finalize_xof_core( & mut self , buffer: & mut Buffer <Self >) -> Self :: ReaderCore {
590- // Finalize the root hash H0
591578 let mut root_output = Output :: <$base_core>:: default ( ) ;
592579 self . root_hasher. finalize_variable_core( buffer, & mut root_output) ;
593-
594580 $reader_name:: new( root_output. into( ) , self . xof_len)
595581 }
596582 }
@@ -628,10 +614,8 @@ macro_rules! blake2x_impl {
628614 serialized_state: & digest:: crypto_common:: hazmat:: SerializedState <Self >,
629615 ) -> Result <Self , digest:: crypto_common:: hazmat:: DeserializeStateError > {
630616 let len_bytes = core:: mem:: size_of:: <$xof_len_type>( ) ;
631- let mut xof_len_bytes = [ 0u8 ; 8 ] ; // Max size for either u16 or u32
632- xof_len_bytes[ ..len_bytes] . copy_from_slice( & serialized_state[ ..len_bytes] ) ;
633617 let xof_len = <$xof_len_type>:: from_le_bytes(
634- xof_len_bytes [ ..len_bytes] . try_into( ) . unwrap( )
618+ serialized_state [ ..len_bytes] . try_into( ) . unwrap( )
635619 ) ;
636620 Ok ( Self :: new( xof_len) )
637621 }
@@ -642,7 +626,6 @@ macro_rules! blake2x_impl {
642626 pub struct $reader_name {
643627 root_hash: [ u8 ; $hash_size] ,
644628 node_offset: u32 ,
645- position: usize ,
646629 remaining: $xof_len_type,
647630 total_xof_len: $xof_len_type,
648631 }
@@ -652,25 +635,13 @@ macro_rules! blake2x_impl {
652635 Self {
653636 root_hash,
654637 node_offset: 0 ,
655- position: 0 ,
656638 remaining: xof_len,
657639 total_xof_len: xof_len,
658640 }
659641 }
660- }
661-
662- impl BlockSizeUser for $reader_name {
663- type BlockSize = $reader_block_size;
664- }
665-
666642
667- impl $reader_name {
668643 /// Build expansion node parameter array for Blake2X.
669- ///
670- /// Creates a unified parameter word array that encodes the expansion node
671- /// parameters according to the Blake2X specification. This handles the
672- /// word-size differences between Blake2b and Blake2s variants.
673- fn build_expansion_node_params(
644+ fn build_node_params(
674645 node_offset: u32 ,
675646 output_size: usize ,
676647 total_xof_len: $xof_len_type
@@ -679,115 +650,77 @@ macro_rules! blake2x_impl {
679650
680651 if core:: mem:: size_of:: <$word>( ) == 4 {
681652 // Blake2s (32-bit words)
682- // p[0]: digest_len | key_len (0) | fanout (0) | depth (0)
683653 p[ 0 ] = output_size as $word;
684- // p[1]: leaf_length (should be hash_size for Blake2Xs per specification)
685654 p[ 1 ] = $hash_size as $word;
686- // p[2]: node_offset (the block counter)
687655 p[ 2 ] = node_offset as $word;
688- // p[3]: xof_len(u16) | node_depth(u8, 0) << 16 | inner_len(u8, hash_size) << 24
689- let xof_len = total_xof_len as $word;
690- let node_depth = 0 as $word;
691- let inner_len = $hash_size as $word;
692- p[ 3 ] = xof_len | ( node_depth << 16 ) | ( inner_len << 24 ) ;
656+ // xof_len(u16) | node_depth(u8, 0) << 16 | inner_len(u8, hash_size) << 24
657+ p[ 3 ] = ( total_xof_len as $word) | ( ( $hash_size as $word) << 24 ) ;
693658 } else {
694659 // Blake2b (64-bit words)
695-
696- // p[0]: Contains bytes 0-7 with digest_length, key_length, fanout, depth, leaf_length
697- let digest_length = output_size as u64 ;
698- let key_length = 0u64 ; // No key for expansion nodes
699- let fanout = 0u64 ; // Unlimited fanout
700- let depth = 0u64 ; // Unlimited depth
701- let leaf_length = ( $hash_size as u64 ) << 32 ;
702- p[ 0 ] = ( digest_length | ( key_length << 8 ) | ( fanout << 16 ) | ( depth << 24 ) | leaf_length) as $word;
703-
704- // p[1]: Contains bytes 8-15 with node_offset (with XOF length in upper 32 bits)
705- // For Blake2b expansion nodes, we include the XOF length in the upper bits
706- let node_offset_full = ( ( total_xof_len as u64 ) << 32 ) + ( node_offset as u64 ) ;
707- p[ 1 ] = node_offset_full as $word;
708-
709- // p[2]: Contains bytes 16-23 with node_depth, inner_length
710- let node_depth = 0u64 ; // Leaf level
711- let inner_length = ( $hash_size as u64 ) << 8 ;
712- p[ 2 ] = ( node_depth | inner_length) as $word;
713-
714- // p[3..7]: All zeros (already initialized)
660+ // p[0]: digest_length | key_length(0) << 8 | fanout(0) << 16 | depth(0) << 24 | leaf_length << 32
661+ p[ 0 ] = ( output_size as u64 | ( ( $hash_size as u64 ) << 32 ) ) as $word;
662+ // p[1]: node_offset with XOF length in upper 32 bits
663+ p[ 1 ] = ( ( ( total_xof_len as u64 ) << 32 ) | ( node_offset as u64 ) ) as $word;
664+ // p[2]: node_depth(0) | inner_length << 8
665+ p[ 2 ] = ( ( $hash_size as u64 ) << 8 ) as $word;
715666 }
716667
717668 p
718669 }
719670
720671 /// Create hasher with expansion node parameter state.
721- ///
722- /// Initializes a Blake2 hasher with the given parameter array by XORing
723- /// the initialization vector with the parameter block.
724672 fn create_hasher_with_params( p: & [ $word; 8 ] ) -> $base_core {
725- // Initialize state h = IV ^ p
726- let h = [
673+ let mut node = <$base_core> :: new_with_params ( & [ ] , & [ ] , 0 , $hash_size ) ;
674+ node . h = [
727675 $vec:: new( $IV[ 0 ] , $IV[ 1 ] , $IV[ 2 ] , $IV[ 3 ] ) ^ $vec:: new( p[ 0 ] , p[ 1 ] , p[ 2 ] , p[ 3 ] ) ,
728676 $vec:: new( $IV[ 4 ] , $IV[ 5 ] , $IV[ 6 ] , $IV[ 7 ] ) ^ $vec:: new( p[ 4 ] , p[ 5 ] , p[ 6 ] , p[ 7 ] ) ,
729677 ] ;
730-
731- // Create hasher with expansion node parameters
732- let mut node = <$base_core>:: new_with_params( & [ ] , & [ ] , 0 , $hash_size) ;
733- node. h = h;
734678 #[ cfg( feature = "reset" ) ]
735- { node. h0 = h; }
736-
679+ { node. h0 = node. h; }
737680 node
738681 }
739682
740683 /// Blake2X expansion node function.
741- ///
742- /// Implements B2(node_offset, output_size, H0) from the Blake2X specification.
743- /// Each expansion node computes Blake2(H0) with specific tree parameters that
744- /// encode the node offset and output size.
745- fn expand_node( h0: & [ u8 ; $hash_size] , node_offset: u32 , output_size: usize , total_xof_len: $xof_len_type) -> [ u8 ; $hash_size] {
746- // Build expansion node parameter array
747- let p = Self :: build_expansion_node_params( node_offset, output_size, total_xof_len) ;
748-
749- // Create the node hasher with the parameter state
684+ fn expand_node(
685+ & self ,
686+ node_offset: u32 ,
687+ output_size: usize
688+ ) -> [ u8 ; $hash_size] {
689+ let p = Self :: build_node_params( node_offset, output_size, self . total_xof_len) ;
750690 let mut node_hasher = Self :: create_hasher_with_params( & p) ;
751691
752- // The hashing logic is now unified for both Blake2b and Blake2s
692+ // Hash the root hash as a single block
753693 let mut buffer = LazyBuffer :: default ( ) ;
754- buffer. digest_blocks( h0 , |blocks| {
694+ buffer. digest_blocks( & self . root_hash , |blocks| {
755695 node_hasher. update_blocks( blocks) ;
756696 } ) ;
757697
758- // Finalize and return
759- let mut output = [ 0u8 ; $hash_size] ;
760698 let mut var_output = Output :: <$base_core>:: default ( ) ;
761699 node_hasher. finalize_variable_core( & mut buffer, & mut var_output) ;
700+
701+ let mut output = [ 0u8 ; $hash_size] ;
762702 output[ ..output_size] . copy_from_slice( & var_output[ ..output_size] ) ;
763703 output
764704 }
765705 }
766706
707+ impl BlockSizeUser for $reader_name {
708+ type BlockSize = $reader_block_size;
709+ }
710+
767711 impl XofReaderCore for $reader_name {
768712 fn read_block( & mut self ) -> Block <Self > {
769713 let mut block = Block :: <Self >:: default ( ) ;
770714
771715 if self . remaining == 0 {
772- return block; // Return zeros if no more output needed
716+ return block;
773717 }
774718
775- // Determine output size for this block
776- let output_size = if self . remaining >= $hash_size as $xof_len_type {
777- $hash_size
778- } else {
779- self . remaining as usize
780- } ;
781-
782- // Blake2x expansion: Hash H0 with specific tree parameters for this node
783- let node_output = Self :: expand_node( & self . root_hash, self . node_offset, output_size, self . total_xof_len) ;
784-
785- // Copy output to block
719+ let output_size = core:: cmp:: min( self . remaining as usize , $hash_size) ;
720+ let node_output = self . expand_node( self . node_offset, output_size) ;
786721 block[ ..output_size] . copy_from_slice( & node_output[ ..output_size] ) ;
787722
788- // Update state
789723 self . node_offset += 1 ;
790- self . position += output_size;
791724 self . remaining -= output_size as $xof_len_type;
792725
793726 block
@@ -800,7 +733,6 @@ macro_rules! blake2x_impl {
800733 }
801734 }
802735
803-
804736 // Use buffer_xof macro to create the wrapper types
805737 digest:: buffer_xof!(
806738 #[ doc=$vardoc]
0 commit comments