Browse Source

Unroll SHA1Transform.

Rika Ichinose 1 year ago
parent
commit
961eccf64b
1 changed files with 57 additions and 67 deletions
  1. 57 67
      packages/hash/src/sha1.pp

+ 57 - 67
packages/hash/src/sha1.pp

@@ -20,7 +20,7 @@
 {$IFNDEF FPC_DOTTEDUNITS}
 {$IFNDEF FPC_DOTTEDUNITS}
 unit sha1;
 unit sha1;
 {$ENDIF FPC_DOTTEDUNITS}
 {$ENDIF FPC_DOTTEDUNITS}
-{$mode objfpc}{$h+}
+{$mode objfpc}{$h+}{$macro+}
 
 
 interface
 interface
 
 
@@ -56,23 +56,6 @@ uses System.SysUtils,System.SysConst;
 uses sysutils,sysconst;
 uses sysutils,sysconst;
 {$ENDIF FPC_DOTTEDUNITS}
 {$ENDIF FPC_DOTTEDUNITS}
 
 
-// inverts the bytes of (Count div 4) cardinals from source to target.
-procedure Invert(Source, Dest: Pointer; Count: PtrUInt);
-var
-  S: PByte;
-  T: PCardinal;
-  I: PtrUInt;
-begin
-  S := Source;
-  T := Dest;
-  for I := 1 to (Count div 4) do
-  begin
-    T^ := S[3] or (S[2] shl 8) or (S[1] shl 16) or (S[0] shl 24);
-    inc(S,4);
-    inc(T);
-  end;
-end;
-
 procedure SHA1Init(out ctx: TSHA1Context);
 procedure SHA1Init(out ctx: TSHA1Context);
 begin
 begin
   FillChar(ctx, sizeof(TSHA1Context), 0);
   FillChar(ctx, sizeof(TSHA1Context), 0);
@@ -114,62 +97,68 @@ const
 // Use original version if asked for, or when we have no optimized assembler version
 // Use original version if asked for, or when we have no optimized assembler version
 procedure SHA1Transform(var ctx: TSHA1Context; Buf: Pointer);
 procedure SHA1Transform(var ctx: TSHA1Context; Buf: Pointer);
 var
 var
-  A, B, C, D, E, T: Cardinal;
+  A, B, C, D, E, Blkv: Cardinal;
   Data: array[0..15] of Cardinal;
   Data: array[0..15] of Cardinal;
-  i: Integer;
 begin
 begin
   A := ctx.State[0];
   A := ctx.State[0];
   B := ctx.State[1];
   B := ctx.State[1];
   C := ctx.State[2];
   C := ctx.State[2];
   D := ctx.State[3];
   D := ctx.State[3];
   E := ctx.State[4];
   E := ctx.State[4];
-  Invert(Buf, @Data, 64);
 {$push}
 {$push}
 {$r-,q-}
 {$r-,q-}
-  i := 0;
-  repeat
-    T := (B and C) or (not B and D) + K20 + E;
-    E := D;
-    D := C;
-    C := rordword(B, 2);
-    B := A;
-    A := T + roldword(A, 5) + Data[i and 15];
-    Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
-    Inc(i);
-  until i > 19;
-
-  repeat
-    T := (B xor C xor D) + K40 + E;
-    E := D;
-    D := C;
-    C := rordword(B, 2);
-    B := A;
-    A := T + roldword(A, 5) + Data[i and 15];
-    Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
-    Inc(i);
-  until i > 39;
-
-  repeat
-    T := (B and C) or (B and D) or (C and D) + K60 + E;
-    E := D;
-    D := C;
-    C := rordword(B, 2);
-    B := A;
-    A := T + roldword(A, 5) + Data[i and 15];
-    Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
-    Inc(i);
-  until i > 59;
-
-  repeat
-    T := (B xor C xor D) + K80 + E;
-    E := D;
-    D := C;
-    C := rordword(B, 2);
-    B := A;
-    A := T + roldword(A, 5) + Data[i and 15];
-    Data[i and 15] := roldword(Data[i and 15] xor Data[(i+2) and 15] xor Data[(i+8) and 15] xor Data[(i+13) and 15], 1);
-    Inc(i);
-  until i > 79;
+
+// I is round index (0..79).
+{$define Sha1Round :=
+
+// (V, W, X, Y, Z) map to (A, B, C, D, E) rotated right by I mod 5.
+{$if I mod 5 = 0}     {$define V := A} {$define W := B} {$define X := C} {$define Y := D} {$define Z := E}
+{$elseif I mod 5 = 1} {$define V := E} {$define W := A} {$define X := B} {$define Y := C} {$define Z := D}
+{$elseif I mod 5 = 2} {$define V := D} {$define W := E} {$define X := A} {$define Y := B} {$define Z := C}
+{$elseif I mod 5 = 3} {$define V := C} {$define W := D} {$define X := E} {$define Y := A} {$define Z := B}
+{$else}               {$define V := B} {$define W := C} {$define X := D} {$define Y := E} {$define Z := A}
+{$endif}
+
+{$if I < 16}
+  Blkv := BEtoN(Unaligned(PCardinal(Buf)[I]));
+{$else}
+  Blkv := RolDWord(Data[(I + 13) and 15] xor Data[(I + 8) and 15] xor Data[(I + 2) and 15] xor Data[I and 15], 1);
+{$endif}
+
+  Z := Z + Blkv; // Handling Blkv first gives a chance to free its register for the following complex expressions added to Z as well.
+{$if I < 77} // for rounds 77 .. 79 this is a dead store
+  Data[I and 15] := Blkv;
+{$endif}
+  Z := Z + RolDWord(V, 5) +
+{$if I < 20}     ((W and (X xor Y)) xor Y) + K20
+{$elseif I < 40} (W xor X xor Y) + K40
+{$elseif I < 60} (((W or X) and Y) or (W and X)) + K60
+{$else}          (W xor X xor Y) + K80
+{$endif};
+  W := RorDWord(W, 2);
+
+  {$undef V} {$undef W} {$undef X} {$undef Y} {$undef Z}
+
+  {$undef I}}
+
+{$define I := 0} Sha1Round {$define I := 1} Sha1Round {$define I := 2} Sha1Round {$define I := 3} Sha1Round {$define I := 4} Sha1Round
+{$define I := 5} Sha1Round {$define I := 6} Sha1Round {$define I := 7} Sha1Round {$define I := 8} Sha1Round {$define I := 9} Sha1Round
+{$define I := 10} Sha1Round {$define I := 11} Sha1Round {$define I := 12} Sha1Round {$define I := 13} Sha1Round {$define I := 14} Sha1Round
+{$define I := 15} Sha1Round {$define I := 16} Sha1Round {$define I := 17} Sha1Round {$define I := 18} Sha1Round {$define I := 19} Sha1Round
+{$define I := 20} Sha1Round {$define I := 21} Sha1Round {$define I := 22} Sha1Round {$define I := 23} Sha1Round {$define I := 24} Sha1Round
+{$define I := 25} Sha1Round {$define I := 26} Sha1Round {$define I := 27} Sha1Round {$define I := 28} Sha1Round {$define I := 29} Sha1Round
+{$define I := 30} Sha1Round {$define I := 31} Sha1Round {$define I := 32} Sha1Round {$define I := 33} Sha1Round {$define I := 34} Sha1Round
+{$define I := 35} Sha1Round {$define I := 36} Sha1Round {$define I := 37} Sha1Round {$define I := 38} Sha1Round {$define I := 39} Sha1Round
+{$define I := 40} Sha1Round {$define I := 41} Sha1Round {$define I := 42} Sha1Round {$define I := 43} Sha1Round {$define I := 44} Sha1Round
+{$define I := 45} Sha1Round {$define I := 46} Sha1Round {$define I := 47} Sha1Round {$define I := 48} Sha1Round {$define I := 49} Sha1Round
+{$define I := 50} Sha1Round {$define I := 51} Sha1Round {$define I := 52} Sha1Round {$define I := 53} Sha1Round {$define I := 54} Sha1Round
+{$define I := 55} Sha1Round {$define I := 56} Sha1Round {$define I := 57} Sha1Round {$define I := 58} Sha1Round {$define I := 59} Sha1Round
+{$define I := 60} Sha1Round {$define I := 61} Sha1Round {$define I := 62} Sha1Round {$define I := 63} Sha1Round {$define I := 64} Sha1Round
+{$define I := 65} Sha1Round {$define I := 66} Sha1Round {$define I := 67} Sha1Round {$define I := 68} Sha1Round {$define I := 69} Sha1Round
+{$define I := 70} Sha1Round {$define I := 71} Sha1Round {$define I := 72} Sha1Round {$define I := 73} Sha1Round {$define I := 74} Sha1Round
+{$define I := 75} Sha1Round {$define I := 76} Sha1Round {$define I := 77} Sha1Round {$define I := 78} Sha1Round {$define I := 79} Sha1Round
+
+{$undef Sha1Round}
 
 
   Inc(ctx.State[0], A);
   Inc(ctx.State[0], A);
   Inc(ctx.State[1], B);
   Inc(ctx.State[1], B);
@@ -240,7 +229,7 @@ const
 procedure SHA1Final(var ctx: TSHA1Context; out Digest: TSHA1Digest);
 procedure SHA1Final(var ctx: TSHA1Context; out Digest: TSHA1Digest);
 var
 var
   Length: QWord;
   Length: QWord;
-  Pads: Cardinal;
+  Pads, I: SizeUint;
 begin
 begin
   // 1. Compute length of the whole stream in bits
   // 1. Compute length of the whole stream in bits
   Length := 8 * (ctx.Length + ctx.BufCnt);
   Length := 8 * (ctx.Length + ctx.BufCnt);
@@ -257,7 +246,8 @@ begin
   SHA1Update(ctx, Length, 8);
   SHA1Update(ctx, Length, 8);
 
 
   // 4. Invert state to digest
   // 4. Invert state to digest
-  Invert(@ctx.State, @Digest, 20);
+  for I := 0 to High(ctx.State) do
+    Unaligned(PUint32(PByte(Digest))[I]) := NtoBE(ctx.State[I]);
   FillChar(ctx, sizeof(TSHA1Context), 0);
   FillChar(ctx, sizeof(TSHA1Context), 0);
 end;
 end;