@@ -464,3 +464,251 @@ macro_rules! blake2_impl {
464464 impl_write!( $fix_state) ;
465465 }
466466}
467+
468+ macro_rules! blake2_p_impl {
469+ (
470+ $state: ident, $fix_state: ident, $compressor: ident, $builder: ident, $word: ident, $bytes: ident, $fanout: expr,
471+ $vardoc: expr, $doc: expr,
472+ ) => {
473+
474+ use $crate:: as_bytes:: AsBytes ;
475+
476+ use digest:: { Input , BlockInput , FixedOutput , VariableOutput , Reset } ;
477+ use digest:: InvalidOutputSize ;
478+ use digest:: generic_array:: GenericArray ;
479+ use digest:: generic_array:: typenum:: Unsigned ;
480+ use core:: cmp;
481+ use byte_tools:: { copy, zero} ;
482+ use crypto_mac:: { Mac , MacResult , InvalidKeyLength } ;
483+
484+ type Output = GenericArray <u8 , $bytes>;
485+
486+ #[ derive( Clone ) ]
487+ #[ doc=$vardoc]
488+ pub struct $state {
489+ n: usize ,
490+ m0: [ $word; 16 ] ,
491+ t0: u64 ,
492+ h0: $builder,
493+ h: [ $compressor; $fanout] ,
494+ m: [ [ $word; 16 ] ; $fanout] ,
495+ t: u64 ,
496+ }
497+
498+ impl $state {
499+ /// Creates a new hashing context with a key.
500+ ///
501+ /// **WARNING!** If you plan to use it for variable output MAC, then
502+ /// make sure to compare codes in constant time! It can be done
503+ /// for example by using `subtle` crate.
504+ pub fn new_keyed( key: & [ u8 ] , output_size: usize ) -> Self {
505+ let mut h0 = $builder:: new( ) ;
506+ h0. key( key. len( ) ) ;
507+ h0. out( output_size) ;
508+ h0. fanout( $fanout) ;
509+ h0. depth( 2 ) ;
510+ h0. inner_length( $bytes:: to_u8( ) ) ;
511+ let mut m0 = [ 0 ; 16 ] ;
512+ let mut t0 = 0 ;
513+ if !key. is_empty( ) {
514+ copy( key, m0. as_mut_bytes( ) ) ;
515+ t0 = 2 * $bytes:: to_u64( ) * $fanout;
516+ }
517+ let mut state = $state {
518+ n: output_size,
519+ h0,
520+ t0,
521+ m0,
522+ // everything else set up by reset()
523+ h: Default :: default ( ) ,
524+ m: Default :: default ( ) ,
525+ t: Default :: default ( ) ,
526+ } ;
527+ state. reset( ) ;
528+ state
529+ }
530+
531+ /// Updates the hashing context with more data.
532+ fn update( & mut self , mut data: & [ u8 ] ) {
533+ const BLOCK : usize = 2 * $bytes:: USIZE ;
534+ const RING : usize = BLOCK * $fanout;
535+
536+ if self . t < RING as u64 {
537+ // initial ring fill
538+ let ( d0, d1) = data. split_at( cmp:: min( data. len( ) , RING - self . t as usize ) ) ;
539+ self . m. as_mut_bytes( ) [ self . t as usize ..self . t as usize + d0. len( ) ] . copy_from_slice( d0) ;
540+ self . t += d0. len( ) as u64 ;
541+ data = d1;
542+ } else if self . t as usize % BLOCK != 0 {
543+ // complete partial block
544+ let ( d0, d1) = data. split_at( cmp:: min( data. len( ) , BLOCK - self . t as usize % BLOCK ) ) ;
545+ let ri = self . t as usize % RING ;
546+ self . m. as_mut_bytes( ) [ ri..ri + d0. len( ) ] . copy_from_slice( d0) ;
547+ self . t += d0. len( ) as u64 ;
548+ data = d1;
549+ }
550+
551+ // if there's data remaining, the ring is full of whole blocks
552+ for b in data. chunks( BLOCK ) {
553+ let i = self . t as usize / BLOCK % $fanout;
554+ self . h[ i] . compress( & mut self . m[ i] , 0 , 0 , self . t / RING as u64 * BLOCK as u64 ) ;
555+ self . m[ i] . as_mut_bytes( ) [ ..b. len( ) ] . copy_from_slice( b) ;
556+ self . t += b. len( ) as u64 ;
557+ }
558+ }
559+
560+ fn finalize( mut self ) -> Output {
561+ const BLOCK : usize = 2 * $bytes:: USIZE ;
562+ const RING : usize = BLOCK * $fanout;
563+
564+ self . h0. node_offset( 0 ) ;
565+ self . h0. node_depth( 1 ) ;
566+ let mut root = self . h0. build( ) ;
567+
568+ let mut ri = self . t as usize % RING ;
569+ let trb = self . t / RING as u64 * BLOCK as u64 ;
570+ if ri % BLOCK != 0 {
571+ let ni = ( ( self . t as usize & !( BLOCK - 1 ) ) + BLOCK ) % RING ;
572+ zero( & mut self . m. as_mut_bytes( ) [ ri..ni] ) ;
573+ }
574+ let mut inter = [ 0 ; 16 ] ;
575+ for i in 0 ..$fanout {
576+ if i != 0 && i & 1 == 0 {
577+ root. compress( & inter, 0 , 0 , i as u64 * $bytes:: to_u64( ) ) ;
578+ }
579+ let len = cmp:: min( ri, BLOCK ) ;
580+ ri -= len;
581+ let f1 = if i == $fanout - 1 { !0 } else { 0 } ;
582+ let ix0 = ( i & 1 ) * $bytes:: to_usize( ) ;
583+ let ix1 = ( ( i & 1 ) + 1 ) * $bytes:: to_usize( ) ;
584+ self . h[ i] . finalize_into_slice( & mut inter. as_mut_bytes( ) [ ix0..ix1] , & self . m[ i] , f1, trb + len as u64 ) ;
585+ }
586+ let mut out = GenericArray :: default ( ) ;
587+ root. finalize( & mut out, & inter, !0 , $fanout * $bytes:: to_u64( ) ) ;
588+ out
589+ }
590+ }
591+
592+ impl Default for $state {
593+ fn default ( ) -> Self { Self :: new_keyed( & [ ] , $bytes:: to_usize( ) ) }
594+ }
595+
596+ impl BlockInput for $state {
597+ type BlockSize = $bytes;
598+ }
599+
600+ impl Input for $state {
601+ fn input<B : AsRef <[ u8 ] >>( & mut self , data: B ) {
602+ self . update( data. as_ref( ) ) ;
603+ }
604+ }
605+
606+ impl VariableOutput for $state {
607+ fn new( output_size: usize ) -> Result <Self , InvalidOutputSize > {
608+ if output_size == 0 || output_size > $bytes:: to_usize( ) {
609+ return Err ( InvalidOutputSize ) ;
610+ }
611+ Ok ( Self :: new_keyed( & [ ] , output_size) )
612+ }
613+
614+ fn output_size( & self ) -> usize {
615+ self . n
616+ }
617+
618+ fn variable_result<F : FnOnce ( & [ u8 ] ) >( self , f: F ) {
619+ let n = self . n;
620+ let res = self . finalize( ) ;
621+ f( & res[ ..n] ) ;
622+ }
623+ }
624+
625+ impl Reset for $state {
626+ fn reset( & mut self ) {
627+ self . h0. node_depth( 0 ) ;
628+ for ( i, h) in self . h. iter_mut( ) . enumerate( ) {
629+ self . h0. node_offset( i) ;
630+ * h = self . h0. build( ) ;
631+ }
632+
633+ for m in self . m. iter_mut( ) {
634+ m. copy_from_slice( & self . m0) ;
635+ }
636+
637+ self . t = self . t0;
638+ }
639+ }
640+
641+ impl_opaque_debug!( $state) ;
642+ impl_write!( $state) ;
643+
644+
645+ #[ derive( Clone ) ]
646+ #[ doc=$doc]
647+ pub struct $fix_state {
648+ state: $state,
649+ }
650+
651+ impl Default for $fix_state {
652+ fn default ( ) -> Self {
653+ let state = $state:: new_keyed( & [ ] , $bytes:: to_usize( ) ) ;
654+ Self { state }
655+ }
656+ }
657+
658+ impl BlockInput for $fix_state {
659+ type BlockSize = $bytes;
660+ }
661+
662+ impl Input for $fix_state {
663+ fn input<B : AsRef <[ u8 ] >>( & mut self , data: B ) {
664+ self . state. update( data. as_ref( ) ) ;
665+ }
666+ }
667+
668+ impl FixedOutput for $fix_state {
669+ type OutputSize = $bytes;
670+
671+ fn fixed_result( self ) -> Output {
672+ self . state. finalize( )
673+ }
674+ }
675+
676+ impl Reset for $fix_state {
677+ fn reset( & mut self ) {
678+ self . state. reset( )
679+ }
680+ }
681+
682+ impl Mac for $fix_state {
683+ type OutputSize = $bytes;
684+ type KeySize = $bytes;
685+
686+ fn new( key: & GenericArray <u8 , $bytes>) -> Self {
687+ let state = $state:: new_keyed( key, $bytes:: to_usize( ) ) ;
688+ Self { state }
689+ }
690+
691+ fn new_varkey( key: & [ u8 ] ) -> Result <Self , InvalidKeyLength > {
692+ if key. len( ) > $bytes:: to_usize( ) {
693+ Err ( InvalidKeyLength )
694+ } else {
695+ let state = $state:: new_keyed( key, $bytes:: to_usize( ) ) ;
696+ Ok ( Self { state } )
697+ }
698+ }
699+
700+ fn input( & mut self , data: & [ u8 ] ) { self . state. update( data) ; }
701+
702+ fn reset( & mut self ) {
703+ <Self as Reset >:: reset( self )
704+ }
705+
706+ fn result( self ) -> MacResult <Self :: OutputSize > {
707+ MacResult :: new( self . state. finalize( ) )
708+ }
709+ }
710+
711+ impl_opaque_debug!( $fix_state) ;
712+ impl_write!( $fix_state) ;
713+ }
714+ }
0 commit comments