@@ -464,3 +464,251 @@ macro_rules! blake2_impl {
464
464
impl_write!( $fix_state) ;
465
465
}
466
466
}
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