Browse Source

update HashLib

Ugochukwu Mmaduekwe 5 years ago
parent
commit
efb77822df
76 changed files with 5686 additions and 2415 deletions
  1. 36 7
      src/libraries/hashlib4pascal/HashLib.inc
  2. 4 0
      src/libraries/hashlib4pascal/HashLibHelper.inc
  3. 34 15
      src/libraries/hashlib4pascal/HlpAdler32.pas
  4. 21 0
      src/libraries/hashlib4pascal/HlpArrayUtils.pas
  5. 12 11
      src/libraries/hashlib4pascal/HlpBits.pas
  6. 635 82
      src/libraries/hashlib4pascal/HlpBlake2B.pas
  7. 0 181
      src/libraries/hashlib4pascal/HlpBlake2BConfig.pas
  8. 0 164
      src/libraries/hashlib4pascal/HlpBlake2BIvBuilder.pas
  9. 420 0
      src/libraries/hashlib4pascal/HlpBlake2BP.pas
  10. 576 0
      src/libraries/hashlib4pascal/HlpBlake2BParams.pas
  11. 0 197
      src/libraries/hashlib4pascal/HlpBlake2BTreeConfig.pas
  12. 631 82
      src/libraries/hashlib4pascal/HlpBlake2S.pas
  13. 0 181
      src/libraries/hashlib4pascal/HlpBlake2SConfig.pas
  14. 0 168
      src/libraries/hashlib4pascal/HlpBlake2SIvBuilder.pas
  15. 420 0
      src/libraries/hashlib4pascal/HlpBlake2SP.pas
  16. 579 0
      src/libraries/hashlib4pascal/HlpBlake2SParams.pas
  17. 0 210
      src/libraries/hashlib4pascal/HlpBlake2STreeConfig.pas
  18. 111 37
      src/libraries/hashlib4pascal/HlpCRC.pas
  19. 3 2
      src/libraries/hashlib4pascal/HlpCRC16.pas
  20. 6 4
      src/libraries/hashlib4pascal/HlpCRC32.pas
  21. 75 41
      src/libraries/hashlib4pascal/HlpCRC32Fast.pas
  22. 3 3
      src/libraries/hashlib4pascal/HlpCRC64.pas
  23. 160 233
      src/libraries/hashlib4pascal/HlpConverters.pas
  24. 0 1
      src/libraries/hashlib4pascal/HlpGost.pas
  25. 0 1
      src/libraries/hashlib4pascal/HlpGrindahl256.pas
  26. 0 1
      src/libraries/hashlib4pascal/HlpGrindahl512.pas
  27. 0 1
      src/libraries/hashlib4pascal/HlpHAS160.pas
  28. 6 14
      src/libraries/hashlib4pascal/HlpHMACNotBuildInAdapter.pas
  29. 282 76
      src/libraries/hashlib4pascal/HlpHashFactory.pas
  30. 1 8
      src/libraries/hashlib4pascal/HlpHashLibTypes.pas
  31. 6 11
      src/libraries/hashlib4pascal/HlpHashResult.pas
  32. 6 36
      src/libraries/hashlib4pascal/HlpHaval.pas
  33. 0 31
      src/libraries/hashlib4pascal/HlpIBlake2BConfig.pas
  34. 29 1
      src/libraries/hashlib4pascal/HlpIBlake2BParams.pas
  35. 0 31
      src/libraries/hashlib4pascal/HlpIBlake2SConfig.pas
  36. 29 1
      src/libraries/hashlib4pascal/HlpIBlake2SParams.pas
  37. 45 12
      src/libraries/hashlib4pascal/HlpIHashInfo.pas
  38. 0 1
      src/libraries/hashlib4pascal/HlpMD4.pas
  39. 0 1
      src/libraries/hashlib4pascal/HlpMD5.pas
  40. 0 1
      src/libraries/hashlib4pascal/HlpMDBase.pas
  41. 50 55
      src/libraries/hashlib4pascal/HlpMurmur2.pas
  42. 36 54
      src/libraries/hashlib4pascal/HlpMurmur2_64.pas
  43. 25 27
      src/libraries/hashlib4pascal/HlpMurmurHash3_x64_128.pas
  44. 43 36
      src/libraries/hashlib4pascal/HlpMurmurHash3_x86_128.pas
  45. 40 39
      src/libraries/hashlib4pascal/HlpMurmurHash3_x86_32.pas
  46. 21 5
      src/libraries/hashlib4pascal/HlpNullDigest.pas
  47. 7 18
      src/libraries/hashlib4pascal/HlpPBKDF2_HMACNotBuildInAdapter.pas
  48. 158 69
      src/libraries/hashlib4pascal/HlpPBKDF_Argon2NotBuildInAdapter.pas
  49. 114 44
      src/libraries/hashlib4pascal/HlpPBKDF_ScryptNotBuildInAdapter.pas
  50. 0 1
      src/libraries/hashlib4pascal/HlpPanama.pas
  51. 0 1
      src/libraries/hashlib4pascal/HlpRIPEMD.pas
  52. 0 1
      src/libraries/hashlib4pascal/HlpRIPEMD128.pas
  53. 0 1
      src/libraries/hashlib4pascal/HlpRIPEMD160.pas
  54. 0 1
      src/libraries/hashlib4pascal/HlpRIPEMD256.pas
  55. 0 1
      src/libraries/hashlib4pascal/HlpRIPEMD320.pas
  56. 0 1
      src/libraries/hashlib4pascal/HlpRadioGatun32.pas
  57. 0 1
      src/libraries/hashlib4pascal/HlpRadioGatun64.pas
  58. 0 1
      src/libraries/hashlib4pascal/HlpSHA0.pas
  59. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_224.pas
  60. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_256.pas
  61. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_256Base.pas
  62. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_384.pas
  63. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_512.pas
  64. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_512Base.pas
  65. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_512_224.pas
  66. 0 1
      src/libraries/hashlib4pascal/HlpSHA2_512_256.pas
  67. 769 49
      src/libraries/hashlib4pascal/HlpSHA3.pas
  68. 141 87
      src/libraries/hashlib4pascal/HlpSipHash.pas
  69. 63 0
      src/libraries/hashlib4pascal/HlpSipHash128.pas
  70. 6 9
      src/libraries/hashlib4pascal/HlpSnefru.pas
  71. 0 1
      src/libraries/hashlib4pascal/HlpTiger.pas
  72. 0 1
      src/libraries/hashlib4pascal/HlpTiger2.pas
  73. 0 1
      src/libraries/hashlib4pascal/HlpWhirlPool.pas
  74. 26 21
      src/libraries/hashlib4pascal/HlpXXHash32.pas
  75. 43 36
      src/libraries/hashlib4pascal/HlpXXHash64.pas
  76. 14 0
      src/libraries/hashlib4pascal/README.md

+ 36 - 7
src/libraries/hashlib4pascal/HashLib.inc

@@ -19,6 +19,14 @@
 {$UNDEF DELPHI}
 {$UNDEF DELPHI}
 {$MODE delphi}
 {$MODE delphi}
 
 
+{$IFDEF FPC_LITTLE_ENDIAN}
+   {$DEFINE HASHLIB_LITTLE_ENDIAN}
+{$ENDIF}
+
+{$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT}
+   {$DEFINE HASHLIB_REQUIRES_PROPER_ALIGNMENT}
+{$ENDIF}
+
 {$DEFINE USE_UNROLLED_VARIANT}
 {$DEFINE USE_UNROLLED_VARIANT}
 
 
 // Disable Overflow and RangeChecks.
 // Disable Overflow and RangeChecks.
@@ -35,12 +43,14 @@
 
 
 // Optimizations
 // Optimizations
 {$OPTIMIZATION LEVEL3}
 {$OPTIMIZATION LEVEL3}
-{$OPTIMIZATION PEEPHOLE}
-{$OPTIMIZATION REGVAR}
-{$OPTIMIZATION LOOPUNROLL}
-{$OPTIMIZATION STRENGTH}
-{$OPTIMIZATION CSE}
-{$OPTIMIZATION DFA}
+// disable "USELOADMODIFYSTORE" because it produces incorrect result
+// when used in combination with -CpCOREAVX2 and -OpCOREAVX2 in FPC 3.2.0 beta
+{$IFDEF FPC_GREATER_THAN_3.0.4}
+   {$OPTIMIZATION NOUSELOADMODIFYSTORE}
+{$ENDIF}
+// level 4 optimizations
+{$OPTIMIZATION ORDERFIELDS}
+{$OPTIMIZATION DEADVALUES}
 
 
 {$IFDEF CPUI386}
 {$IFDEF CPUI386}
    {$OPTIMIZATION USEEBP}
    {$OPTIMIZATION USEEBP}
@@ -50,12 +60,25 @@
    {$OPTIMIZATION USERBP}
    {$OPTIMIZATION USERBP}
 {$ENDIF}
 {$ENDIF}
 
 
+{.$DEFINE USE_MTPROCS}
+{.$DEFINE USE_PASMP}
+
+{$IF DEFINED(USE_MTPROCS) AND DEFINED(USE_PASMP)}
+   {$MESSAGE ERROR 'Only One Threading Library can be used at a time.'}
+{$IFEND}
+
 {$ENDIF FPC}
 {$ENDIF FPC}
 
 
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
 
 
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
 
 
+{$DEFINE HASHLIB_LITTLE_ENDIAN}
+
+{$IFDEF CPUARM}
+   {$DEFINE HASHLIB_REQUIRES_PROPER_ALIGNMENT}
+{$ENDIF}
+
   // XE3 and Above
   // XE3 and Above
 {$IF CompilerVersion >= 24.0}
 {$IF CompilerVersion >= 24.0}
    {$DEFINE DELPHIXE3_UP}
    {$DEFINE DELPHIXE3_UP}
@@ -92,7 +115,7 @@
   // XE7 and Above
   // XE7 and Above
 {$IF CompilerVersion >= 28.0}
 {$IF CompilerVersion >= 28.0}
    {$DEFINE DELPHIXE7_UP}
    {$DEFINE DELPHIXE7_UP}
-   {$DEFINE HAS_DELPHI_PPL} // Has Delphi Parallel Programming Library
+   {.$DEFINE USE_DELPHI_PPL} // Use Delphi Parallel Programming Library
    {$DEFINE HAS_DELPHI_NET_ENCODING}
    {$DEFINE HAS_DELPHI_NET_ENCODING}
 {$IFEND}
 {$IFEND}
 
 
@@ -103,6 +126,12 @@
 
 
 {$DEFINE USE_UNROLLED_VARIANT}
 {$DEFINE USE_UNROLLED_VARIANT}
 
 
+{.$DEFINE USE_PASMP}
+
+{$IF DEFINED(USE_DELPHI_PPL) AND DEFINED(USE_PASMP)}
+   {$MESSAGE ERROR 'Only One Threading Library can be used at a time.'}
+{$IFEND}
+
 // This option is needed to enable code browsing (aka Ctrl+Click)
 // This option is needed to enable code browsing (aka Ctrl+Click)
 // It does not affect the binary size or generated code
 // It does not affect the binary size or generated code
 {$DEFINITIONINFO ON}
 {$DEFINITIONINFO ON}

+ 4 - 0
src/libraries/hashlib4pascal/HashLibHelper.inc

@@ -20,3 +20,7 @@
 {$IF FPC_FULLVERSION < 30000}
 {$IF FPC_FULLVERSION < 30000}
    {$MESSAGE ERROR 'This Library requires FreePascal 3.0.0 or higher.'}
    {$MESSAGE ERROR 'This Library requires FreePascal 3.0.0 or higher.'}
 {$IFEND}
 {$IFEND}
+
+{$IF FPC_FULLVERSION > 30004}
+   {$DEFINE FPC_GREATER_THAN_3.0.4}
+{$IFEND}

+ 34 - 15
src/libraries/hashlib4pascal/HlpAdler32.pas

@@ -10,7 +10,8 @@ uses
   HlpHash,
   HlpHash,
   HlpIHash,
   HlpIHash,
   HlpHashResult,
   HlpHashResult,
-  HlpIHashResult;
+  HlpIHashResult,
+  HlpConverters;
 
 
 type
 type
   TAdler32 = class sealed(THash, IChecksum, IHash32, ITransformBlock)
   TAdler32 = class sealed(THash, IChecksum, IHash32, ITransformBlock)
@@ -61,22 +62,30 @@ end;
 procedure TAdler32.TransformBytes(const AData: THashLibByteArray;
 procedure TAdler32.TransformBytes(const AData: THashLibByteArray;
   AIndex, ALength: Int32);
   AIndex, ALength: Int32);
 var
 var
-  LIdx, LN: Int32;
+  LN: Int32;
+  LPtrData: PByte;
+  LA, LB: UInt32;
 begin
 begin
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
   System.Assert(AIndex >= 0);
   System.Assert(AIndex >= 0);
   System.Assert(ALength >= 0);
   System.Assert(ALength >= 0);
   System.Assert(AIndex + ALength <= System.Length(AData));
   System.Assert(AIndex + ALength <= System.Length(AData));
 {$ENDIF DEBUG}
 {$ENDIF DEBUG}
-  LIdx := AIndex;
+  LPtrData := PByte(AData) + AIndex;
 
 
-  { while ALength > 0 do
+  {
+    LA := FA;
+    LB := FB;
+    while ALength > 0 do
     begin
     begin
-    FA := (FA + AData[LIdx]) mod MOD_ADLER;
-    FB := (FB + FA) mod MOD_ADLER;
-    System.Inc(LIdx);
+    LA := (LA + LPtrData^) mod MOD_ADLER;
+    LB := (LB + LA) mod MOD_ADLER;
+    System.Inc(LPtrData);
     System.Dec(ALength);
     System.Dec(ALength);
-    end; }
+    end;
+    FA := LA;
+    FB := LB;
+  }
 
 
   // lifted from PngEncoder Adler32.cs
   // lifted from PngEncoder Adler32.cs
 
 
@@ -84,7 +93,7 @@ begin
   begin
   begin
     // We can defer the modulo operation:
     // We can defer the modulo operation:
     // FA maximally grows from 65521 to 65521 + 255 * 3800
     // FA maximally grows from 65521 to 65521 + 255 * 3800
-    // FB maximally grows by3800 * median(FA) = 2090079800 < 2^31
+    // FB maximally grows by 3800 * median(FA) = 2090079800 < 2^31
     LN := 3800;
     LN := 3800;
     if (LN > ALength) then
     if (LN > ALength) then
     begin
     begin
@@ -92,21 +101,31 @@ begin
     end;
     end;
     ALength := ALength - LN;
     ALength := ALength - LN;
 
 
+    LA := FA;
+    LB := FB;
     while (LN - 1) >= 0 do
     while (LN - 1) >= 0 do
     begin
     begin
-      FA := (FA + AData[LIdx]);
-      FB := (FB + FA);
-      System.Inc(LIdx);
+      LA := (LA + LPtrData^);
+      LB := (LB + LA);
+      System.Inc(LPtrData);
       System.Dec(LN);
       System.Dec(LN);
     end;
     end;
-    FA := FA mod MOD_ADLER;
-    FB := FB mod MOD_ADLER;
+    LA := LA mod MOD_ADLER;
+    LB := LB mod MOD_ADLER;
+
+    FA := LA;
+    FB := LB;
   end;
   end;
 end;
 end;
 
 
 function TAdler32.TransformFinal: IHashResult;
 function TAdler32.TransformFinal: IHashResult;
+var
+  LBufferBytes: THashLibByteArray;
 begin
 begin
-  result := THashResult.Create(UInt32((FB shl 16) or FA));
+  System.SetLength(LBufferBytes, HashSize);
+  TConverters.ReadUInt32AsBytesBE(UInt32((FB shl 16) or FA), LBufferBytes, 0);
+
+  result := THashResult.Create(LBufferBytes);
   Initialize();
   Initialize();
 end;
 end;
 
 

+ 21 - 0
src/libraries/hashlib4pascal/HlpArrayUtils.pas

@@ -37,6 +37,9 @@ type
     class procedure ZeroFill(const ABuffer: THashLibUInt64Array);
     class procedure ZeroFill(const ABuffer: THashLibUInt64Array);
       overload; static;
       overload; static;
 
 
+    class function Concatenate(const ABuffer1, ABuffer2: THashLibByteArray)
+      : THashLibByteArray; static;
+
   end;
   end;
 
 
 implementation
 implementation
@@ -134,4 +137,22 @@ begin
   TArrayUtils.Fill(ABuffer, 0, System.Length(ABuffer), UInt64(0));
   TArrayUtils.Fill(ABuffer, 0, System.Length(ABuffer), UInt64(0));
 end;
 end;
 
 
+class function TArrayUtils.Concatenate(const ABuffer1,
+  ABuffer2: THashLibByteArray): THashLibByteArray;
+var
+  LABuffer1Length: Int32;
+begin
+  LABuffer1Length := System.Length(ABuffer1);
+  System.SetLength(Result, LABuffer1Length + System.Length(ABuffer2));
+  if ABuffer1 <> Nil then
+  begin
+    System.Move(ABuffer1[0], Result[0], LABuffer1Length * System.SizeOf(Byte));
+  end;
+  if ABuffer2 <> Nil then
+  begin
+    System.Move(ABuffer2[0], Result[LABuffer1Length], System.Length(ABuffer2) *
+      System.SizeOf(Byte));
+  end;
+end;
+
 end.
 end.

+ 12 - 11
src/libraries/hashlib4pascal/HlpBits.pas

@@ -129,9 +129,10 @@ begin
 {$IFDEF FPC}
 {$IFDEF FPC}
   Result := SwapEndian(AValue);
   Result := SwapEndian(AValue);
 {$ELSE}
 {$ELSE}
-  Result := (AValue and UInt32($000000FF)) shl 24 or
-    (AValue and UInt32($0000FF00)) shl 8 or (AValue and UInt32($00FF0000))
-    shr 8 or (AValue and UInt32($FF000000)) shr 24;
+  Result := ((AValue shl 24) and UInt32($FF000000)) or
+    ((AValue shl 8) and UInt32($00FF0000)) or
+    ((AValue shr 8) and UInt32($0000FF00)) or
+    ((AValue shr 24) and UInt32($000000FF));
 {$ENDIF FPC}
 {$ENDIF FPC}
 end;
 end;
 
 
@@ -140,14 +141,14 @@ begin
 {$IFDEF FPC}
 {$IFDEF FPC}
   Result := SwapEndian(AValue);
   Result := SwapEndian(AValue);
 {$ELSE}
 {$ELSE}
-  Result := (AValue and UInt64($00000000000000FF)) shl 56 or
-    (AValue and UInt64($000000000000FF00)) shl 40 or
-    (AValue and UInt64($0000000000FF0000)) shl 24 or
-    (AValue and UInt64($00000000FF000000)) shl 8 or
-    (AValue and UInt64($000000FF00000000)) shr 8 or
-    (AValue and UInt64($0000FF0000000000)) shr 24 or
-    (AValue and UInt64($00FF000000000000)) shr 40 or
-    (AValue and UInt64($FF00000000000000)) shr 56;
+  Result := ((AValue shl 56) and UInt64($FF00000000000000)) or
+    ((AValue shl 40) and UInt64($00FF000000000000)) or
+    ((AValue shl 24) and UInt64($0000FF0000000000)) or
+    ((AValue shl 8) and UInt64($000000FF00000000)) or
+    ((AValue shr 8) and UInt64($00000000FF000000)) or
+    ((AValue shr 24) and UInt64($0000000000FF0000)) or
+    ((AValue shr 40) and UInt64($000000000000FF00)) or
+    ((AValue shr 56) and UInt64($00000000000000FF));
 {$ENDIF FPC}
 {$ENDIF FPC}
 end;
 end;
 
 

+ 635 - 82
src/libraries/hashlib4pascal/HlpBlake2B.pas

@@ -6,17 +6,12 @@ interface
 
 
 uses
 uses
   SysUtils,
   SysUtils,
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpHash,
   HlpHash,
   HlpHashResult,
   HlpHashResult,
   HlpIHashResult,
   HlpIHashResult,
-  HlpIBlake2BConfig,
-  HlpBlake2BConfig,
-  HlpIBlake2BTreeConfig,
-  HlpBlake2BIvBuilder,
+  HlpIBlake2BParams,
+  HlpBlake2BParams,
   HlpIHash,
   HlpIHash,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpConverters,
   HlpConverters,
@@ -26,9 +21,15 @@ uses
 resourcestring
 resourcestring
   SInvalidConfigLength = 'Config Length Must Be 8 Words';
   SInvalidConfigLength = 'Config Length Must Be 8 Words';
   SConfigNil = 'Config Cannot Be Nil';
   SConfigNil = 'Config Cannot Be Nil';
+  SInvalidXOFSize =
+    'XOFSize in Bits must be Multiples of 8 and be Between %u and %u Bytes.';
+  SOutputLengthInvalid = 'Output Length is above the Digest Length';
+  SOutputBufferTooShort = 'Output Buffer Too Short';
+  SMaximumOutputLengthExceeded = '"Maximum Length is 2^32 blocks of 64 bytes';
+  SWritetoXofAfterReadError = '"%s" Write to Xof after Read not Allowed';
 
 
 type
 type
-  TBlake2B = class sealed(THash, ICryptoNotBuildIn, ITransformBlock)
+  TBlake2B = class(THash, ICryptoNotBuildIn, ITransformBlock)
   strict private
   strict private
 
 
 {$REGION 'Consts'}
 {$REGION 'Consts'}
@@ -61,59 +62,189 @@ type
       4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3);
       4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3);
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDREGION}
 {$ENDREGION}
-    class var
-
-      FDefaultConfig: IBlake2BConfig;
 
 
   var
   var
-    FM: array [0 .. 15] of UInt64;
-    FRawConfig, FState: THashLibUInt64Array;
-    FKey, FBuffer: THashLibByteArray;
-{$IFNDEF USE_UNROLLED_VARIANT}
-    FV: array [0 .. 15] of UInt64;
-{$ENDIF USE_UNROLLED_VARIANT}
-    FFilledBufferCount, FHashSize, FBlockSize: Int32;
-    FCounter0, FCounter1, FFinalizationFlag0, FFinalizationFlag1: UInt64;
     FTreeConfig: IBlake2BTreeConfig;
     FTreeConfig: IBlake2BTreeConfig;
+    FConfig: IBlake2BConfig;
+    FDoTransformKeyBlock: Boolean;
 
 
-    class constructor Blake2BConfig();
+    procedure Blake2BIncrementCounter(AIncrementCount: UInt64); inline;
 
 
 {$IFNDEF USE_UNROLLED_VARIANT}
 {$IFNDEF USE_UNROLLED_VARIANT}
     procedure G(a, b, c, d, r, i: Int32); inline;
     procedure G(a, b, c, d, r, i: Int32); inline;
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
     procedure Compress(ABlock: PByte; AStart: Int32);
     procedure Compress(ABlock: PByte; AStart: Int32);
 
 
-    procedure Finish(); inline;
-
   strict protected
   strict protected
+  var
+    FM: array [0 .. 15] of UInt64;
+    FState: THashLibUInt64Array;
+    FBuffer: THashLibByteArray;
+{$IFNDEF USE_UNROLLED_VARIANT}
+    FV: array [0 .. 15] of UInt64;
+{$ENDIF USE_UNROLLED_VARIANT}
+    FFilledBufferCount: Int32;
+    FCounter0, FCounter1, FFinalizationFlag0, FFinalizationFlag1: UInt64;
 
 
+    procedure Finish();
     function GetName: String; override;
     function GetName: String; override;
 
 
   public
   public
     constructor Create(); overload;
     constructor Create(); overload;
     constructor Create(const AConfig: IBlake2BConfig); overload;
     constructor Create(const AConfig: IBlake2BConfig); overload;
     constructor Create(const AConfig: IBlake2BConfig;
     constructor Create(const AConfig: IBlake2BConfig;
-      const ATreeConfig: IBlake2BTreeConfig); overload;
+      const ATreeConfig: IBlake2BTreeConfig;
+      ADoTransformKeyBlock: Boolean = True); overload;
     procedure Initialize; override;
     procedure Initialize; override;
     procedure TransformBytes(const AData: THashLibByteArray;
     procedure TransformBytes(const AData: THashLibByteArray;
       AIndex, ADataLength: Int32); override;
       AIndex, ADataLength: Int32); override;
     function TransformFinal: IHashResult; override;
     function TransformFinal: IHashResult; override;
+    function CloneInternal(): TBlake2B;
     function Clone(): IHash; override;
     function Clone(): IHash; override;
 
 
   end;
   end;
 
 
+type
+  /// <summary>
+  /// <b>TBlake2XBConfig</b> is used to configure hash function parameters and
+  /// keying.
+  /// </summary>
+  TBlake2XBConfig = record
+  private
+  var
+    FBlake2BConfig: IBlake2BConfig; // blake2b config object
+    FBlake2BTreeConfig: IBlake2BTreeConfig; // blake2b tree config object
+
+    function GetBlake2BConfig(): IBlake2BConfig; inline;
+    procedure SetBlake2BConfig(const AValue: IBlake2BConfig); inline;
+    function GetBlake2BTreeConfig(): IBlake2BTreeConfig; inline;
+    procedure SetBlake2BTreeConfig(const AValue: IBlake2BTreeConfig); inline;
+  public
+  var
+
+    constructor Create(ABlake2BConfig: IBlake2BConfig;
+      ABlake2BTreeConfig: IBlake2BTreeConfig);
+
+    function Clone(): TBlake2XBConfig;
+
+    property Blake2BConfig: IBlake2BConfig read GetBlake2BConfig
+      write SetBlake2BConfig;
+
+    property Blake2BTreeConfig: IBlake2BTreeConfig read GetBlake2BTreeConfig
+      write SetBlake2BTreeConfig;
+  end;
+
+type
+  TBlake2XB = class sealed(TBlake2B, IXOF)
+  strict private
+  const
+    Blake2BHashSize = Int32(64);
+
+  const
+    // Magic number to indicate an unknown length of digest
+    UnknownDigestLengthInBytes = UInt32((UInt64(1) shl 32) - 1);
+    // 4294967295 bytes
+    MaxNumberBlocks = UInt64(1) shl 32;
+    // 2^32 blocks of 64 bytes (256GiB)
+    // the maximum size in bytes the digest can produce when the length is unknown
+    UnknownMaxDigestLengthInBytes = UInt64(MaxNumberBlocks *
+      UInt64(Blake2BHashSize));
+
+  var
+    FXOFSizeInBits: UInt64;
+
+    function GetXOFSizeInBits: UInt64; inline;
+    procedure SetXOFSizeInBits(AXofSizeInBits: UInt64); inline;
+    function SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+
+    function NodeOffsetWithXOFDigestLength(AXOFSizeInBytes: UInt64)
+      : UInt64; inline;
+
+    function ComputeStepLength(): Int32; inline;
+
+    function GetResult(): THashLibByteArray;
+
+    constructor CreateInternal(const AConfig: IBlake2BConfig;
+      const ATreeConfig: IBlake2BTreeConfig);
+
+  strict protected
+  var
+    FBlake2XBConfig: TBlake2XBConfig;
+    FBlake2XBBufferPosition, FDigestPosition, FBlockPosition: UInt64;
+    FRootConfig, FOutputConfig: TBlake2XBConfig;
+    FRootHashDigest, FBlake2XBBuffer: THashLibByteArray;
+    FFinalized: Boolean;
+
+    function GetName: String; override;
+    property XOFSizeInBits: UInt64 read GetXOFSizeInBits write SetXOFSizeInBits;
+
+  public
+
+    constructor Create(const ABlake2XBConfig: TBlake2XBConfig);
+    procedure Initialize(); override;
+    function Clone(): IHash; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ADataLength: Int32); override;
+    function TransformFinal(): IHashResult; override;
+
+    procedure DoOutput(const ADestination: THashLibByteArray;
+      ADestinationOffset, AOutputLength: UInt64);
+
+  end;
+
+type
+  TBlake2BMACNotBuildInAdapter = class sealed(THash, IBlake2BMAC,
+    IBlake2BMACNotBuildIn, ICrypto, ICryptoNotBuildIn)
+
+  strict private
+  var
+    FHash: IHash;
+    FKey: THashLibByteArray;
+
+    constructor Create(const ABlake2BKey, ASalt, APersonalisation
+      : THashLibByteArray; AOutputLengthInBits: Int32); overload;
+    constructor Create(const AHash: IHash;
+      const ABlake2BKey: THashLibByteArray); overload;
+
+  strict protected
+
+    function GetName: String; override;
+
+    function GetKey(): THashLibByteArray;
+    procedure SetKey(const AValue: THashLibByteArray);
+
+  public
+
+    destructor Destroy; override;
+
+    procedure Clear();
+
+    procedure Initialize(); override;
+    function TransformFinal(): IHashResult; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ALength: Int32); override;
+    function Clone(): IHash; override;
+    property Key: THashLibByteArray read GetKey write SetKey;
+    property Name: String read GetName;
+
+    class function CreateBlake2BMAC(const ABlake2BKey, ASalt, APersonalisation
+      : THashLibByteArray; AOutputLengthInBits: Int32): IBlake2BMAC; static;
+
+  end;
+
 implementation
 implementation
 
 
 { TBlake2B }
 { TBlake2B }
 
 
-class constructor TBlake2B.Blake2BConfig;
+constructor TBlake2B.Create();
 begin
 begin
-  FDefaultConfig := TBlake2BConfig.Create();
+  Create(TBlake2BConfig.Create() as IBlake2BConfig);
 end;
 end;
 
 
-constructor TBlake2B.Create();
+procedure TBlake2B.Blake2BIncrementCounter(AIncrementCount: UInt64);
 begin
 begin
-  Create(TBlake2BConfig.Create() as IBlake2BConfig);
+  FCounter0 := FCounter0 + AIncrementCount;
+  System.Inc(FCounter1, Ord(FCounter0 < AIncrementCount));
 end;
 end;
 
 
 {$IFNDEF USE_UNROLLED_VARIANT}
 {$IFNDEF USE_UNROLLED_VARIANT}
@@ -138,29 +269,35 @@ end;
 
 
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
 
 
-function TBlake2B.Clone(): IHash;
+function TBlake2B.CloneInternal(): TBlake2B;
 var
 var
-  LHashInstance: TBlake2B;
+  LTreeConfig: IBlake2BTreeConfig;
 begin
 begin
-  LHashInstance := TBlake2B.Create(TBlake2BConfig.Create(FHashSize)
-    as IBlake2BConfig);
-  System.Move(FM, LHashInstance.FM, System.SizeOf(FM));
-  LHashInstance.FRawConfig := System.Copy(FRawConfig);
-  LHashInstance.FState := System.Copy(FState);
-  LHashInstance.FKey := System.Copy(FKey);
-  LHashInstance.FBuffer := System.Copy(FBuffer);
+  LTreeConfig := Nil;
+  if FTreeConfig <> Nil then
+  begin
+    LTreeConfig := FTreeConfig.Clone();
+  end;
+  Result := TBlake2B.Create(FConfig.Clone(), LTreeConfig, FDoTransformKeyBlock);
+  System.Move(FM, Result.FM, System.SizeOf(FM));
+  Result.FState := System.Copy(FState);
+  Result.FBuffer := System.Copy(FBuffer);
 {$IFNDEF USE_UNROLLED_VARIANT}
 {$IFNDEF USE_UNROLLED_VARIANT}
-  System.Move(FV, LHashInstance.FV, System.SizeOf(FV));
+  System.Move(FV, Result.FV, System.SizeOf(FV));
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
-  LHashInstance.FFilledBufferCount := FFilledBufferCount;
-  LHashInstance.FCounter0 := FCounter0;
-  LHashInstance.FCounter1 := FCounter1;
-  LHashInstance.FFinalizationFlag0 := FFinalizationFlag0;
-  LHashInstance.FFinalizationFlag1 := FFinalizationFlag1;
-  Result := LHashInstance as IHash;
+  Result.FFilledBufferCount := FFilledBufferCount;
+  Result.FCounter0 := FCounter0;
+  Result.FCounter1 := FCounter1;
+  Result.FFinalizationFlag0 := FFinalizationFlag0;
+  Result.FFinalizationFlag1 := FFinalizationFlag1;
   Result.BufferSize := BufferSize;
   Result.BufferSize := BufferSize;
 end;
 end;
 
 
+function TBlake2B.Clone(): IHash;
+begin
+  Result := CloneInternal() as IHash;
+end;
+
 procedure TBlake2B.Compress(ABlock: PByte; AStart: Int32);
 procedure TBlake2B.Compress(ABlock: PByte; AStart: Int32);
 var
 var
 {$IFDEF USE_UNROLLED_VARIANT}
 {$IFDEF USE_UNROLLED_VARIANT}
@@ -172,7 +309,7 @@ var
 
 
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
 begin
 begin
-  TConverters.le64_copy(ABlock, AStart, @(FM[0]), 0, FBlockSize);
+  TConverters.le64_copy(ABlock, AStart, @(FM[0]), 0, BlockSize);
 
 
 {$IFDEF USE_UNROLLED_VARIANT}
 {$IFDEF USE_UNROLLED_VARIANT}
   m0 := FM[0];
   m0 := FM[0];
@@ -1626,32 +1763,22 @@ begin
 end;
 end;
 
 
 constructor TBlake2B.Create(const AConfig: IBlake2BConfig;
 constructor TBlake2B.Create(const AConfig: IBlake2BConfig;
-  const ATreeConfig: IBlake2BTreeConfig);
-var
-  LConfig: IBlake2BConfig;
+  const ATreeConfig: IBlake2BTreeConfig; ADoTransformKeyBlock: Boolean);
 begin
 begin
-  LConfig := AConfig;
+  FConfig := AConfig;
   FTreeConfig := ATreeConfig;
   FTreeConfig := ATreeConfig;
-  FBlockSize := BlockSizeInBytes;
-
-  if (LConfig = Nil) then
-  begin
-    LConfig := FDefaultConfig;
-  end;
+  FDoTransformKeyBlock := ADoTransformKeyBlock;
 
 
-  FRawConfig := TBlake2BIvBuilder.ConfigB(LConfig, FTreeConfig);
-  if ((LConfig.Key <> Nil) and (System.Length(LConfig.Key) <> 0)) then
+  if (FConfig = Nil) then
   begin
   begin
-    FKey := System.Copy(LConfig.Key, System.Low(LConfig.Key),
-      System.Length(LConfig.Key));
-    System.SetLength(FKey, FBlockSize);
+    FConfig := TBlake2BConfig.DefaultConfig;
   end;
   end;
 
 
-  FHashSize := LConfig.HashSize;
-
   System.SetLength(FState, 8);
   System.SetLength(FState, 8);
 
 
-  Inherited Create(FHashSize, FBlockSize);
+  System.SetLength(FBuffer, BlockSizeInBytes);
+
+  Inherited Create(FConfig.HashSize, BlockSizeInBytes);
 end;
 end;
 
 
 procedure TBlake2B.Finish;
 procedure TBlake2B.Finish;
@@ -1659,11 +1786,11 @@ var
   LCount: Int32;
   LCount: Int32;
 begin
 begin
   // Last compression
   // Last compression
-  FCounter0 := FCounter0 + UInt64(FFilledBufferCount);
+  Blake2BIncrementCounter(UInt64(FFilledBufferCount));
 
 
   FFinalizationFlag0 := System.High(UInt64);
   FFinalizationFlag0 := System.High(UInt64);
 
 
-  if (FTreeConfig.IsLastNode) then
+  if (FTreeConfig <> Nil) and (FTreeConfig.IsLastNode) then
   begin
   begin
     FFinalizationFlag1 := System.High(UInt64);
     FFinalizationFlag1 := System.High(UInt64);
   end;
   end;
@@ -1682,12 +1809,27 @@ end;
 procedure TBlake2B.Initialize;
 procedure TBlake2B.Initialize;
 var
 var
   LIdx: Int32;
   LIdx: Int32;
+  LBlock: THashLibByteArray;
+  LRawConfig: THashLibUInt64Array;
 begin
 begin
-  if (FRawConfig = Nil) then
+  LRawConfig := TBlake2BIvBuilder.ConfigB(FConfig, FTreeConfig);
+  LBlock := Nil;
+
+  if FDoTransformKeyBlock then
+  begin
+    if ((FConfig.Key <> Nil) and (System.Length(FConfig.Key) <> 0)) then
+    begin
+      LBlock := System.Copy(FConfig.Key, System.Low(FConfig.Key),
+        System.Length(FConfig.Key));
+      System.SetLength(LBlock, BlockSizeInBytes);
+    end;
+  end;
+
+  if (LRawConfig = Nil) then
   begin
   begin
     raise EArgumentNilHashLibException.CreateRes(@SConfigNil);
     raise EArgumentNilHashLibException.CreateRes(@SConfigNil);
   end;
   end;
-  if (System.Length(FRawConfig) <> 8) then
+  if (System.Length(LRawConfig) <> 8) then
   begin
   begin
     raise EArgumentHashLibException.CreateRes(@SInvalidConfigLength);
     raise EArgumentHashLibException.CreateRes(@SInvalidConfigLength);
   end;
   end;
@@ -1708,8 +1850,6 @@ begin
 
 
   FFilledBufferCount := 0;
   FFilledBufferCount := 0;
 
 
-  System.SetLength(FBuffer, BlockSizeInBytes);
-
   TArrayUtils.ZeroFill(FBuffer);
   TArrayUtils.ZeroFill(FBuffer);
 
 
   System.FillChar(FM, System.SizeOf(FM), UInt64(0));
   System.FillChar(FM, System.SizeOf(FM), UInt64(0));
@@ -1719,12 +1859,16 @@ begin
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
   for LIdx := 0 to 7 do
   for LIdx := 0 to 7 do
   begin
   begin
-    FState[LIdx] := FState[LIdx] xor FRawConfig[LIdx];
+    FState[LIdx] := FState[LIdx] xor LRawConfig[LIdx];
   end;
   end;
 
 
-  if (FKey <> Nil) then
+  if FDoTransformKeyBlock then
   begin
   begin
-    TransformBytes(FKey, 0, System.Length(FKey));
+    if (LBlock <> Nil) then
+    begin
+      TransformBytes(LBlock, 0, System.Length(LBlock));
+      TArrayUtils.ZeroFill(LBlock); // burn key from memory
+    end;
   end;
   end;
 end;
 end;
 
 
@@ -1743,11 +1887,7 @@ begin
       System.Move(AData[LOffset], FBuffer[FFilledBufferCount],
       System.Move(AData[LOffset], FBuffer[FFilledBufferCount],
         LBufferRemaining);
         LBufferRemaining);
     end;
     end;
-    FCounter0 := FCounter0 + UInt64(BlockSizeInBytes);
-    if (FCounter0 = 0) then
-    begin
-      System.Inc(FCounter1);
-    end;
+    Blake2BIncrementCounter(UInt64(BlockSizeInBytes));
     Compress(PByte(FBuffer), 0);
     Compress(PByte(FBuffer), 0);
     LOffset := LOffset + LBufferRemaining;
     LOffset := LOffset + LBufferRemaining;
     ADataLength := ADataLength - LBufferRemaining;
     ADataLength := ADataLength - LBufferRemaining;
@@ -1756,11 +1896,7 @@ begin
 
 
   while (ADataLength > BlockSizeInBytes) do
   while (ADataLength > BlockSizeInBytes) do
   begin
   begin
-    FCounter0 := FCounter0 + UInt64(BlockSizeInBytes);
-    if (FCounter0 = 0) then
-    begin
-      System.Inc(FCounter1);
-    end;
+    Blake2BIncrementCounter(UInt64(BlockSizeInBytes));
     Compress(PByte(AData), LOffset);
     Compress(PByte(AData), LOffset);
     LOffset := LOffset + BlockSizeInBytes;
     LOffset := LOffset + BlockSizeInBytes;
     ADataLength := ADataLength - BlockSizeInBytes;
     ADataLength := ADataLength - BlockSizeInBytes;
@@ -1778,7 +1914,7 @@ var
   LBuffer: THashLibByteArray;
   LBuffer: THashLibByteArray;
 begin
 begin
   Finish();
   Finish();
-  System.SetLength(LBuffer, FHashSize);
+  System.SetLength(LBuffer, HashSize);
   TConverters.le64_copy(PUInt64(FState), 0, PByte(LBuffer), 0,
   TConverters.le64_copy(PUInt64(FState), 0, PByte(LBuffer), 0,
     System.Length(LBuffer));
     System.Length(LBuffer));
   Result := THashResult.Create(LBuffer);
   Result := THashResult.Create(LBuffer);
@@ -1790,4 +1926,421 @@ begin
   Result := Format('%s_%u', [Self.ClassName, Self.HashSize * 8]);
   Result := Format('%s_%u', [Self.ClassName, Self.HashSize * 8]);
 end;
 end;
 
 
+{ TBlake2XBConfig }
+
+function TBlake2XBConfig.GetBlake2BConfig: IBlake2BConfig;
+begin
+  Result := FBlake2BConfig;
+end;
+
+function TBlake2XBConfig.GetBlake2BTreeConfig: IBlake2BTreeConfig;
+begin
+  Result := FBlake2BTreeConfig;
+end;
+
+procedure TBlake2XBConfig.SetBlake2BConfig(const AValue: IBlake2BConfig);
+begin
+  FBlake2BConfig := AValue;
+end;
+
+procedure TBlake2XBConfig.SetBlake2BTreeConfig(const AValue
+  : IBlake2BTreeConfig);
+begin
+  FBlake2BTreeConfig := AValue;
+end;
+
+function TBlake2XBConfig.Clone(): TBlake2XBConfig;
+begin
+  Result := Default (TBlake2XBConfig);
+  if FBlake2BConfig <> Nil then
+  begin
+    Result.Blake2BConfig := FBlake2BConfig.Clone();
+  end;
+
+  if FBlake2BTreeConfig <> Nil then
+  begin
+    Result.Blake2BTreeConfig := FBlake2BTreeConfig.Clone();
+  end;
+end;
+
+constructor TBlake2XBConfig.Create(ABlake2BConfig: IBlake2BConfig;
+  ABlake2BTreeConfig: IBlake2BTreeConfig);
+begin
+  FBlake2BConfig := ABlake2BConfig;
+  FBlake2BTreeConfig := ABlake2BTreeConfig;
+end;
+
+{ TBlake2XB }
+
+function TBlake2XB.GetXOFSizeInBits: UInt64;
+begin
+  Result := FXOFSizeInBits;
+end;
+
+procedure TBlake2XB.SetXOFSizeInBits(AXofSizeInBits: UInt64);
+begin
+  SetXOFSizeInBitsInternal(AXofSizeInBits);
+end;
+
+function TBlake2XB.SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+var
+  LXofSizeInBytes: UInt64;
+begin
+  LXofSizeInBytes := AXofSizeInBits shr 3;
+  If ((AXofSizeInBits and $7) <> 0) or (LXofSizeInBytes < 1) or
+    (LXofSizeInBytes > UInt64(UnknownDigestLengthInBytes)) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateResFmt(@SInvalidXOFSize,
+      [1, UInt64(UnknownDigestLengthInBytes)]);
+  end;
+  FXOFSizeInBits := AXofSizeInBits;
+  Result := Self;
+end;
+
+function TBlake2XB.NodeOffsetWithXOFDigestLength(AXOFSizeInBytes
+  : UInt64): UInt64;
+begin
+  Result := (UInt64(AXOFSizeInBytes) shl 32);
+end;
+
+function TBlake2XB.ComputeStepLength: Int32;
+var
+  LXofSizeInBytes, LDiff: UInt64;
+begin
+  LXofSizeInBytes := XOFSizeInBits shr 3;
+  LDiff := LXofSizeInBytes - FDigestPosition;
+  if (LXofSizeInBytes = UInt64(UnknownDigestLengthInBytes)) then
+  begin
+    Result := Blake2BHashSize;
+    Exit;
+  end;
+
+  if UInt64(Blake2BHashSize) < LDiff then
+  begin
+    Result := UInt64(Blake2BHashSize)
+  end
+  else
+  begin
+    Result := LDiff;
+  end;
+end;
+
+function TBlake2XB.GetName: String;
+begin
+  Result := Format('%s_%s_%u', [Self.ClassName, 'XOFSizeInBytes',
+    (Self as IXOF).XOFSizeInBits shr 3]);
+end;
+
+function TBlake2XB.Clone(): IHash;
+var
+  LHashInstance: TBlake2XB;
+  LXof: IXOF;
+begin
+  // Xof Cloning
+  LXof := (TBlake2XB.CreateInternal(FRootConfig.Blake2BConfig,
+    FRootConfig.Blake2BTreeConfig) as IXOF);
+  LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
+
+  // Blake2XB Cloning
+  LHashInstance := LXof as TBlake2XB;
+  LHashInstance.FBlake2XBConfig := FBlake2XBConfig.Clone();
+  LHashInstance.FBlake2XBBufferPosition := FBlake2XBBufferPosition;
+  LHashInstance.FDigestPosition := FDigestPosition;
+  LHashInstance.FBlockPosition := FBlockPosition;
+  LHashInstance.FRootConfig := FRootConfig.Clone();
+  LHashInstance.FOutputConfig := FOutputConfig.Clone();
+  LHashInstance.FRootHashDigest := System.Copy(FRootHashDigest);
+  LHashInstance.FBlake2XBBuffer := System.Copy(FBlake2XBBuffer);
+  LHashInstance.FFinalized := FFinalized;
+
+  // Internal Blake2B Cloning
+  System.Move(FM, LHashInstance.FM, System.SizeOf(FM));
+  LHashInstance.FState := System.Copy(FState);
+  LHashInstance.FBuffer := System.Copy(FBuffer);
+{$IFNDEF USE_UNROLLED_VARIANT}
+  System.Move(FV, LHashInstance.FV, System.SizeOf(FV));
+{$ENDIF USE_UNROLLED_VARIANT}
+  LHashInstance.FFilledBufferCount := FFilledBufferCount;
+  LHashInstance.FCounter0 := FCounter0;
+  LHashInstance.FCounter1 := FCounter1;
+  LHashInstance.FFinalizationFlag0 := FFinalizationFlag0;
+  LHashInstance.FFinalizationFlag1 := FFinalizationFlag1;
+
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TBlake2XB.CreateInternal(const AConfig: IBlake2BConfig;
+  const ATreeConfig: IBlake2BTreeConfig);
+begin
+  inherited Create(AConfig, ATreeConfig);
+end;
+
+constructor TBlake2XB.Create(const ABlake2XBConfig: TBlake2XBConfig);
+begin
+  FBlake2XBConfig := ABlake2XBConfig;
+  // Create root hash config.
+  FRootConfig := Default (TBlake2XBConfig);
+
+  FRootConfig.Blake2BConfig := FBlake2XBConfig.Blake2BConfig;
+
+  if FRootConfig.Blake2BConfig = Nil then
+  begin
+    FRootConfig.Blake2BConfig := TBlake2BConfig.Create();
+  end
+  else
+  begin
+    FRootConfig.Blake2BConfig.Key := FBlake2XBConfig.Blake2BConfig.Key;
+    FRootConfig.Blake2BConfig.Salt := FBlake2XBConfig.Blake2BConfig.Salt;
+    FRootConfig.Blake2BConfig.Personalisation :=
+      FBlake2XBConfig.Blake2BConfig.Personalisation;
+  end;
+
+  FRootConfig.Blake2BTreeConfig := FBlake2XBConfig.Blake2BTreeConfig;
+
+  if FRootConfig.Blake2BTreeConfig = Nil then
+  begin
+    FRootConfig.Blake2BTreeConfig := TBlake2BTreeConfig.Create();
+    FRootConfig.Blake2BTreeConfig.FanOut := 1;
+    FRootConfig.Blake2BTreeConfig.MaxDepth := 1;
+
+    FRootConfig.Blake2BTreeConfig.LeafSize := 0;
+    FRootConfig.Blake2BTreeConfig.NodeOffset := 0;
+    FRootConfig.Blake2BTreeConfig.NodeDepth := 0;
+    FRootConfig.Blake2BTreeConfig.InnerHashSize := 0;
+    FRootConfig.Blake2BTreeConfig.IsLastNode := False;
+  end;
+
+  // Create initial config for output hashes.
+  FOutputConfig := Default (TBlake2XBConfig);
+
+  FOutputConfig.Blake2BConfig := TBlake2BConfig.Create();
+  FOutputConfig.Blake2BConfig.Salt := FRootConfig.Blake2BConfig.Salt;
+  FOutputConfig.Blake2BConfig.Personalisation :=
+    FRootConfig.Blake2BConfig.Personalisation;
+
+  FOutputConfig.Blake2BTreeConfig := TBlake2BTreeConfig.Create();
+
+  CreateInternal(FRootConfig.Blake2BConfig, FRootConfig.Blake2BTreeConfig);
+
+  System.SetLength(FBlake2XBBuffer, Blake2BHashSize);
+end;
+
+procedure TBlake2XB.Initialize;
+var
+  LXofSizeInBytes: UInt64;
+begin
+  LXofSizeInBytes := XOFSizeInBits shr 3;
+
+  FRootConfig.Blake2BTreeConfig.NodeOffset := NodeOffsetWithXOFDigestLength
+    (LXofSizeInBytes);
+
+  FOutputConfig.Blake2BTreeConfig.NodeOffset := NodeOffsetWithXOFDigestLength
+    (LXofSizeInBytes);
+
+  FBlake2XBBufferPosition := Blake2BHashSize;
+  FRootHashDigest := Nil;
+  FBlockPosition := 0;
+  FDigestPosition := 0;
+  FFinalized := False;
+  TArrayUtils.ZeroFill(FBlake2XBBuffer);
+  inherited Initialize();
+end;
+
+procedure TBlake2XB.DoOutput(const ADestination: THashLibByteArray;
+  ADestinationOffset, AOutputLength: UInt64);
+var
+  LDestinationOffset: UInt64;
+begin
+
+  if (UInt64(System.Length(ADestination)) - ADestinationOffset) < AOutputLength
+  then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateRes(@SOutputBufferTooShort);
+  end;
+
+  if ((XOFSizeInBits shr 3) <> UnknownDigestLengthInBytes) then
+  begin
+    if ((FDigestPosition + AOutputLength) > (XOFSizeInBits shr 3)) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateRes
+        (@SOutputLengthInvalid);
+    end;
+  end
+  else if ((FBlockPosition shl 5) >= UnknownMaxDigestLengthInBytes) then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateRes
+      (@SMaximumOutputLengthExceeded);
+  end;
+
+  if not FFinalized then
+  begin
+    Finish();
+    FFinalized := True;
+  end;
+
+  LDestinationOffset := ADestinationOffset;
+
+  if (FRootHashDigest = Nil) then
+  begin
+    // Get root digest
+    System.SetLength(FRootHashDigest, Blake2BHashSize);
+    TConverters.le64_copy(PUInt64(FState), 0, PByte(FRootHashDigest), 0,
+      System.Length(FRootHashDigest));
+  end;
+
+  while AOutputLength > 0 do
+  begin
+    if FBlake2XBBufferPosition >= UInt64(Blake2BHashSize) then
+    begin
+      FOutputConfig.Blake2BConfig.HashSize := ComputeStepLength();
+      FOutputConfig.Blake2BTreeConfig.InnerHashSize := Blake2BHashSize;
+
+      FBlake2XBBuffer := (TBlake2B.Create(FOutputConfig.Blake2BConfig,
+        FOutputConfig.Blake2BTreeConfig) as IHash).ComputeBytes(FRootHashDigest)
+        .GetBytes();
+      FOutputConfig.Blake2BTreeConfig.NodeOffset :=
+        FOutputConfig.Blake2BTreeConfig.NodeOffset + 1;
+      FBlake2XBBufferPosition := 0;
+    end;
+
+    ADestination[LDestinationOffset] := FBlake2XBBuffer
+      [FBlake2XBBufferPosition];
+
+    System.Inc(FBlake2XBBufferPosition);
+    System.Dec(AOutputLength);
+    System.Inc(FDigestPosition);
+    System.Inc(LDestinationOffset);
+  end;
+end;
+
+function TBlake2XB.GetResult: THashLibByteArray;
+var
+  LXofSizeInBytes: UInt64;
+begin
+  System.SetLength(Result, XOFSizeInBits shr 3);
+
+  LXofSizeInBytes := XOFSizeInBits shr 3;
+
+  System.SetLength(Result, LXofSizeInBytes);
+
+  DoOutput(Result, 0, LXofSizeInBytes);
+end;
+
+procedure TBlake2XB.TransformBytes(const AData: THashLibByteArray;
+  AIndex, ADataLength: Int32);
+begin
+  if FFinalized then
+  begin
+    raise EInvalidOperationHashLibException.CreateResFmt
+      (@SWritetoXofAfterReadError, [Name]);
+  end;
+  inherited TransformBytes(AData, AIndex, ADataLength);
+end;
+
+function TBlake2XB.TransformFinal: IHashResult;
+var
+  LBuffer: THashLibByteArray;
+begin
+  LBuffer := GetResult();
+{$IFDEF DEBUG}
+  System.Assert(UInt64(System.Length(LBuffer)) = (XOFSizeInBits shr 3));
+{$ENDIF DEBUG}
+  Initialize();
+  Result := THashResult.Create(LBuffer);
+end;
+
+{ TBlake2BMACNotBuildInAdapter }
+
+procedure TBlake2BMACNotBuildInAdapter.Clear();
+begin
+  TArrayUtils.ZeroFill(FKey);
+end;
+
+function TBlake2BMACNotBuildInAdapter.Clone(): IHash;
+var
+  LHashInstance: TBlake2BMACNotBuildInAdapter;
+begin
+  LHashInstance := TBlake2BMACNotBuildInAdapter.Create(FHash.Clone(), FKey);
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TBlake2BMACNotBuildInAdapter.Create(const ABlake2BKey, ASalt,
+  APersonalisation: THashLibByteArray; AOutputLengthInBits: Int32);
+var
+  LConfig: TBlake2BConfig;
+begin
+  LConfig := TBlake2BConfig.Create(AOutputLengthInBits shr 3);
+  LConfig.Key := ABlake2BKey;
+  LConfig.Salt := ASalt;
+  LConfig.Personalisation := APersonalisation;
+  Create(TBlake2B.Create(LConfig, Nil) as IHash, ABlake2BKey);
+end;
+
+constructor TBlake2BMACNotBuildInAdapter.Create(const AHash: IHash;
+  const ABlake2BKey: THashLibByteArray);
+begin
+  Inherited Create(AHash.HashSize, AHash.BlockSize);
+  SetKey(ABlake2BKey);
+  FHash := AHash;
+end;
+
+class function TBlake2BMACNotBuildInAdapter.CreateBlake2BMAC(const ABlake2BKey,
+  ASalt, APersonalisation: THashLibByteArray; AOutputLengthInBits: Int32)
+  : IBlake2BMAC;
+begin
+  Result := TBlake2BMACNotBuildInAdapter.Create(ABlake2BKey, ASalt,
+    APersonalisation, AOutputLengthInBits) as IBlake2BMAC;
+end;
+
+destructor TBlake2BMACNotBuildInAdapter.Destroy;
+begin
+  Clear();
+  inherited Destroy;
+end;
+
+function TBlake2BMACNotBuildInAdapter.GetKey: THashLibByteArray;
+begin
+  Result := System.Copy(FKey);
+end;
+
+function TBlake2BMACNotBuildInAdapter.GetName: String;
+begin
+  Result := Format('%s', ['TBlake2BMAC']);
+end;
+
+procedure TBlake2BMACNotBuildInAdapter.Initialize;
+begin
+  FHash.Initialize;
+end;
+
+procedure TBlake2BMACNotBuildInAdapter.SetKey(const AValue: THashLibByteArray);
+begin
+  if (AValue = Nil) then
+  begin
+    FKey := Nil;
+  end
+  else
+  begin
+    FKey := System.Copy(AValue);
+  end;
+end;
+
+procedure TBlake2BMACNotBuildInAdapter.TransformBytes
+  (const AData: THashLibByteArray; AIndex, ALength: Int32);
+begin
+{$IFDEF DEBUG}
+  System.Assert(AIndex >= 0);
+  System.Assert(ALength >= 0);
+  System.Assert(AIndex + ALength <= System.Length(AData));
+{$ENDIF}
+  FHash.TransformBytes(AData, AIndex, ALength);
+end;
+
+function TBlake2BMACNotBuildInAdapter.TransformFinal: IHashResult;
+begin
+  Result := FHash.TransformFinal();
+end;
+
 end.
 end.

+ 0 - 181
src/libraries/hashlib4pascal/HlpBlake2BConfig.pas

@@ -1,181 +0,0 @@
-unit HlpBlake2BConfig;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-  HlpIBlake2BConfig,
-  HlpHashSize,
-  HlpHashLibTypes;
-
-resourcestring
-  SInvalidHashSize =
-    'BLAKE2B HashSize must be restricted to one of the following [1 .. 64], "%d"';
-  SInvalidKeyLength = '"Key" Length Must Not Be Greater Than 64, "%d"';
-  SInvalidPersonalisationLength =
-    '"Personalisation" Length Must Be Equal To 16, "%d"';
-  SInvalidSaltLength = '"Salt" Length Must Be Equal To 16, "%d"';
-
-type
-
-  TBlake2BConfig = class sealed(TInterfacedObject, IBlake2BConfig)
-
-  strict private
-
-  var
-
-    FHashSize: Int32;
-    FPersonalisation, FSalt, FKey: THashLibByteArray;
-
-    procedure ValidateHashSize(AHashSize: Int32); inline;
-    procedure ValidateKeyLength(const AKey: THashLibByteArray); inline;
-    procedure ValidatePersonalisationLength(const APersonalisation
-      : THashLibByteArray); inline;
-    procedure ValidateSaltLength(const ASalt: THashLibByteArray); inline;
-
-    function GetPersonalisation: THashLibByteArray; inline;
-    procedure SetPersonalisation(const AValue: THashLibByteArray); inline;
-
-    function GetSalt: THashLibByteArray; inline;
-    procedure SetSalt(const AValue: THashLibByteArray); inline;
-
-    function GetKey: THashLibByteArray; inline;
-    procedure SetKey(const AValue: THashLibByteArray); inline;
-
-    function GetHashSize: Int32; inline;
-    procedure SetHashSize(AValue: Int32); inline;
-
-  public
-    constructor Create(AHashSize: THashSize = THashSize.hsHashSize512);
-      overload;
-    constructor Create(AHashSize: Int32); overload;
-    property Personalisation: THashLibByteArray read GetPersonalisation
-      write SetPersonalisation;
-    property Salt: THashLibByteArray read GetSalt write SetSalt;
-    property Key: THashLibByteArray read GetKey write SetKey;
-    property HashSize: Int32 read GetHashSize write SetHashSize;
-
-  end;
-
-implementation
-
-{ TBlake2BConfig }
-
-procedure TBlake2BConfig.ValidateHashSize(AHashSize: Int32);
-begin
-  if not((AHashSize) in [1 .. 64]) or (((AHashSize * 8) and 7) <> 0) then
-  begin
-    raise EArgumentHashLibException.CreateResFmt(@SInvalidHashSize,
-      [AHashSize]);
-  end;
-end;
-
-procedure TBlake2BConfig.ValidateKeyLength(const AKey: THashLibByteArray);
-var
-  KeyLength: Int32;
-begin
-  if (AKey <> Nil) then
-  begin
-    KeyLength := System.Length(AKey);
-    if (KeyLength > 64) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidKeyLength,
-        [KeyLength]);
-    end;
-  end;
-end;
-
-procedure TBlake2BConfig.ValidatePersonalisationLength(const APersonalisation
-  : THashLibByteArray);
-var
-  PersonalisationLength: Int32;
-begin
-  if (APersonalisation <> Nil) then
-  begin
-    PersonalisationLength := System.Length(APersonalisation);
-    if (PersonalisationLength <> 16) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateResFmt
-        (@SInvalidPersonalisationLength, [PersonalisationLength]);
-    end;
-  end;
-end;
-
-procedure TBlake2BConfig.ValidateSaltLength(const ASalt: THashLibByteArray);
-var
-  SaltLength: Int32;
-begin
-  if (ASalt <> Nil) then
-  begin
-    SaltLength := System.Length(ASalt);
-    if (SaltLength <> 16) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateResFmt
-        (@SInvalidSaltLength, [SaltLength]);
-    end;
-  end;
-end;
-
-function TBlake2BConfig.GetHashSize: Int32;
-begin
-  result := FHashSize;
-end;
-
-function TBlake2BConfig.GetKey: THashLibByteArray;
-begin
-  result := FKey;
-end;
-
-function TBlake2BConfig.GetPersonalisation: THashLibByteArray;
-begin
-  result := FPersonalisation;
-end;
-
-function TBlake2BConfig.GetSalt: THashLibByteArray;
-begin
-  result := FSalt;
-end;
-
-procedure TBlake2BConfig.SetHashSize(AValue: Int32);
-begin
-  ValidateHashSize(AValue);
-  FHashSize := AValue;
-end;
-
-procedure TBlake2BConfig.SetKey(const AValue: THashLibByteArray);
-begin
-  ValidateKeyLength(AValue);
-  FKey := AValue;
-end;
-
-procedure TBlake2BConfig.SetPersonalisation(const AValue: THashLibByteArray);
-begin
-  ValidatePersonalisationLength(AValue);
-  FPersonalisation := AValue;
-end;
-
-procedure TBlake2BConfig.SetSalt(const AValue: THashLibByteArray);
-begin
-  ValidateSaltLength(AValue);
-  FSalt := AValue;
-end;
-
-constructor TBlake2BConfig.Create(AHashSize: THashSize);
-var
-  LHashSize: Int32;
-begin
-  Inherited Create();
-  LHashSize := Int32(AHashSize);
-  ValidateHashSize(LHashSize);
-  FHashSize := LHashSize;
-end;
-
-constructor TBlake2BConfig.Create(AHashSize: Int32);
-begin
-  Inherited Create();
-  ValidateHashSize(AHashSize);
-  FHashSize := AHashSize;
-end;
-
-end.

+ 0 - 164
src/libraries/hashlib4pascal/HlpBlake2BIvBuilder.pas

@@ -1,164 +0,0 @@
-unit HlpBlake2BIvBuilder;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
-  HlpConverters,
-  HlpBlake2BTreeConfig,
-  HlpIBlake2BConfig,
-  HlpIBlake2BTreeConfig,
-  HlpHashLibTypes;
-
-resourcestring
-  SInvalidHashSize =
-    '"HashSize" Must Be Greater Than 0 And Less Than or Equal To 64';
-  SInvalidKeyLength = '"Key" Length Must Not Be Greater Than 64';
-  SInvalidPersonalisationLength =
-    '"Personalisation" Length Must Be Equal To 16';
-  SInvalidSaltLength = '"Salt" Length Must Be Equal To 16';
-  STreeIncorrectInnerHashSize =
-    'Tree Inner Hash Size Must Not Be Greater Than 64';
-
-type
-  TBlake2BIvBuilder = class sealed(TObject)
-
-  strict private
-    class var
-
-      FSequentialTreeConfig: IBlake2BTreeConfig;
-
-    class procedure VerifyConfigB(const AConfig: IBlake2BConfig;
-      const ATreeConfig: IBlake2BTreeConfig; AIsSequential: Boolean); static;
-
-    class constructor Blake2BIvBuilder();
-
-  public
-    class function ConfigB(const AConfig: IBlake2BConfig;
-      var ATreeConfig: IBlake2BTreeConfig): THashLibUInt64Array; static;
-
-  end;
-
-implementation
-
-{ TBlake2BIvBuilder }
-
-class procedure TBlake2BIvBuilder.VerifyConfigB(const AConfig: IBlake2BConfig;
-  const ATreeConfig: IBlake2BTreeConfig; AIsSequential: Boolean);
-begin
-
-  // digest length
-  if ((AConfig.HashSize <= 0) or (AConfig.HashSize > 64)) then
-  begin
-    raise EArgumentOutOfRangeHashLibException.CreateRes(@SInvalidHashSize);
-  end;
-
-  // Key length
-  if (AConfig.Key <> Nil) then
-  begin
-    if (System.Length(AConfig.Key) > 64) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes(@SInvalidKeyLength);
-    end;
-  end;
-
-  // Salt length
-  if (AConfig.Salt <> Nil) then
-  begin
-    if (System.Length(AConfig.Salt) <> 16) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes(@SInvalidSaltLength);
-    end;
-  end;
-
-  // Personalisation length
-  if (AConfig.Personalisation <> Nil) then
-  begin
-    if (System.Length(AConfig.Personalisation) <> 16) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes
-        (@SInvalidPersonalisationLength);
-    end;
-  end;
-
-  // Tree InnerHashSize
-  if (ATreeConfig <> Nil) then
-  begin
-
-    if ((not AIsSequential) and ((ATreeConfig.InnerHashSize <= 0))) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.Create
-        ('treeConfig.TreeIntermediateHashSize');
-    end;
-
-    if (ATreeConfig.InnerHashSize > 64) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes
-        (@STreeIncorrectInnerHashSize);
-    end;
-  end;
-
-end;
-
-class constructor TBlake2BIvBuilder.Blake2BIvBuilder;
-begin
-  FSequentialTreeConfig := TBlake2BTreeConfig.Create();
-  FSequentialTreeConfig.FanOut := 1;
-  FSequentialTreeConfig.MaxDepth := 1;
-  FSequentialTreeConfig.LeafSize := 0;
-  FSequentialTreeConfig.NodeOffset := 0;
-  FSequentialTreeConfig.NodeDepth := 0;
-  FSequentialTreeConfig.InnerHashSize := 0;
-  FSequentialTreeConfig.IsLastNode := False;
-end;
-
-class function TBlake2BIvBuilder.ConfigB(const AConfig: IBlake2BConfig;
-  var ATreeConfig: IBlake2BTreeConfig): THashLibUInt64Array;
-var
-  LIsSequential: Boolean;
-  LBuffer: THashLibByteArray;
-begin
-  LIsSequential := ATreeConfig = Nil;
-  if (LIsSequential) then
-  begin
-    ATreeConfig := FSequentialTreeConfig;
-  end;
-
-  VerifyConfigB(AConfig, ATreeConfig, LIsSequential);
-
-  System.SetLength(LBuffer, 64);
-
-  LBuffer[0] := AConfig.HashSize;
-  LBuffer[1] := System.Length(AConfig.Key);
-
-  if ATreeConfig <> Nil then
-  begin
-    LBuffer[2] := ATreeConfig.FanOut;
-    LBuffer[3] := ATreeConfig.MaxDepth;
-    TConverters.ReadUInt32AsBytesLE(ATreeConfig.LeafSize, LBuffer, 4);
-    TConverters.ReadUInt64AsBytesLE(ATreeConfig.NodeOffset, LBuffer, 8);
-    LBuffer[16] := ATreeConfig.NodeDepth;
-    LBuffer[17] := ATreeConfig.InnerHashSize;
-  end;
-
-  if AConfig.Salt <> Nil then
-  begin
-    System.Move(AConfig.Salt[0], LBuffer[32], 16 * System.SizeOf(Byte));
-  end;
-
-  if AConfig.Personalisation <> Nil then
-  begin
-    System.Move(AConfig.Personalisation[0], LBuffer[48],
-      16 * System.SizeOf(Byte));
-  end;
-
-  System.SetLength(Result, 8);
-  TConverters.le64_copy(PByte(LBuffer), 0, PUInt64(Result), 0,
-    System.Length(LBuffer) * System.SizeOf(Byte));
-end;
-
-end.

+ 420 - 0
src/libraries/hashlib4pascal/HlpBlake2BP.pas

@@ -0,0 +1,420 @@
+unit HlpBlake2BP;
+
+{$I HashLib.inc}
+
+interface
+
+uses
+  SysUtils,
+{$IFDEF USE_DELPHI_PPL}
+  System.Classes,
+  System.Threading,
+{$ENDIF USE_DELPHI_PPL}
+{$IFDEF USE_PASMP}
+  PasMP,
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+  MTProcs,
+{$ENDIF USE_MTPROCS}
+  HlpHash,
+  HlpIHashResult,
+  HlpBlake2B,
+  HlpIBlake2BParams,
+  HlpBlake2BParams,
+  HlpIHash,
+  HlpIHashInfo,
+  HlpArrayUtils,
+  HlpHashLibTypes;
+
+type
+  TBlake2BP = class sealed(THash, ICryptoNotBuildIn, ITransformBlock)
+  strict private
+
+  type
+    PDataContainer = ^TDataContainer;
+
+    TDataContainer = record
+      PtrData: PByte;
+      Counter: UInt64;
+    end;
+
+  const
+    BlockSizeInBytes = Int32(128);
+    OutSizeInBytes = Int32(64);
+    ParallelismDegree = Int32(4);
+
+  var
+    // had to use the classes directly for performance purposes
+    FRootHash: TBlake2B;
+    FLeafHashes: THashLibGenericArray<TBlake2B>;
+    FBuffer, FKey: THashLibByteArray;
+    FBufferLength: UInt64;
+
+    /// <summary>
+    /// <br />Blake2B defaults to setting the expected output length <br />
+    /// from the <c>HashSize</c> in the <c>TBlake2BConfig</c> class. <br />In
+    /// some cases, however, we do not want this, as the output length <br />
+    /// of these instances is given by <c>TBlake2BTreeConfig.InnerSize</c>
+    /// instead. <br />
+    /// </summary>
+    function Blake2BPCreateLeafParam(const ABlake2BConfig: IBlake2BConfig;
+      const ABlake2BTreeConfig: IBlake2BTreeConfig): TBlake2B;
+    function Blake2BPCreateLeaf(AOffset: UInt64): TBlake2B;
+    function Blake2BPCreateRoot(): TBlake2B;
+    procedure ParallelComputation(AIdx: Int32; ADataContainer: PDataContainer);
+
+    procedure DoParallelComputation(ADataContainer: PDataContainer);
+
+    function DeepCloneBlake2BInstances(const ALeafHashes
+      : THashLibGenericArray<TBlake2B>): THashLibGenericArray<TBlake2B>;
+
+    procedure Clear();
+
+    constructor CreateInternal(AHashSize: Int32);
+
+{$IFDEF USE_PASMP}
+    procedure PasMPParallelComputationWrapper(const AJob: PPasMPJob;
+      const AThreadIndex: LongInt; const ADataContainer: Pointer;
+      const AFromIndex, AToIndex: TPasMPNativeInt); inline;
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+    procedure MTProcsParallelComputationWrapper(AIdx: PtrInt;
+      ADataContainer: Pointer; AItem: TMultiThreadProcItem); inline;
+{$ENDIF USE_MTPROCS}
+  strict protected
+    function GetName: String; override;
+
+  public
+    constructor Create(AHashSize: Int32; const AKey: THashLibByteArray);
+    destructor Destroy; override;
+    procedure Initialize; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ADataLength: Int32); override;
+    function TransformFinal: IHashResult; override;
+    function Clone(): IHash; override;
+  end;
+
+implementation
+
+{ TBlake2BP }
+
+function TBlake2BP.Blake2BPCreateLeafParam(const ABlake2BConfig: IBlake2BConfig;
+  const ABlake2BTreeConfig: IBlake2BTreeConfig): TBlake2B;
+begin
+  Result := TBlake2B.Create(ABlake2BConfig, ABlake2BTreeConfig);
+end;
+
+function TBlake2BP.Blake2BPCreateLeaf(AOffset: UInt64): TBlake2B;
+var
+  LBlake2BConfig: IBlake2BConfig;
+  LBlake2BTreeConfig: IBlake2BTreeConfig;
+begin
+  LBlake2BConfig := TBlake2BConfig.Create(HashSize);
+  LBlake2BConfig.Key := FKey;
+  LBlake2BTreeConfig := TBlake2BTreeConfig.Create();
+  LBlake2BTreeConfig.FanOut := ParallelismDegree;
+  LBlake2BTreeConfig.MaxDepth := 2;
+  LBlake2BTreeConfig.NodeDepth := 0;
+  LBlake2BTreeConfig.LeafSize := 0;
+  LBlake2BTreeConfig.NodeOffset := AOffset;
+  LBlake2BTreeConfig.InnerHashSize := OutSizeInBytes;
+  if AOffset = (ParallelismDegree - 1) then
+  begin
+    LBlake2BTreeConfig.IsLastNode := True;
+  end;
+  Result := Blake2BPCreateLeafParam(LBlake2BConfig, LBlake2BTreeConfig);
+end;
+
+function TBlake2BP.Blake2BPCreateRoot(): TBlake2B;
+var
+  LBlake2BConfig: IBlake2BConfig;
+  LBlake2BTreeConfig: IBlake2BTreeConfig;
+begin
+  LBlake2BConfig := TBlake2BConfig.Create(HashSize);
+  LBlake2BConfig.Key := FKey;
+  LBlake2BTreeConfig := TBlake2BTreeConfig.Create();
+  LBlake2BTreeConfig.FanOut := ParallelismDegree;
+  LBlake2BTreeConfig.MaxDepth := 2;
+  LBlake2BTreeConfig.NodeDepth := 1;
+  LBlake2BTreeConfig.LeafSize := 0;
+  LBlake2BTreeConfig.NodeOffset := 0;
+  LBlake2BTreeConfig.InnerHashSize := OutSizeInBytes;
+  LBlake2BTreeConfig.IsLastNode := True;
+  Result := TBlake2B.Create(LBlake2BConfig, LBlake2BTreeConfig, False);
+end;
+
+procedure TBlake2BP.Clear;
+begin
+  TArrayUtils.ZeroFill(FKey);
+end;
+
+function TBlake2BP.DeepCloneBlake2BInstances(const ALeafHashes
+  : THashLibGenericArray<TBlake2B>): THashLibGenericArray<TBlake2B>;
+var
+  LIdx: Int32;
+begin
+  System.SetLength(Result, System.Length(ALeafHashes));
+  for LIdx := System.Low(ALeafHashes) to System.High(ALeafHashes) do
+  begin
+    Result[LIdx] := ALeafHashes[LIdx].CloneInternal();
+  end;
+end;
+
+function TBlake2BP.Clone(): IHash;
+var
+  LHashInstance: TBlake2BP;
+begin
+  LHashInstance := TBlake2BP.CreateInternal(HashSize);
+  LHashInstance.FKey := System.Copy(FKey);
+  if FRootHash <> Nil then
+  begin
+    LHashInstance.FRootHash := FRootHash.CloneInternal();
+  end;
+  LHashInstance.FLeafHashes := DeepCloneBlake2BInstances(FLeafHashes);
+  LHashInstance.FBuffer := System.Copy(FBuffer);
+  LHashInstance.FBufferLength := FBufferLength;
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TBlake2BP.CreateInternal(AHashSize: Int32);
+begin
+  Inherited Create(AHashSize, BlockSizeInBytes);
+end;
+
+constructor TBlake2BP.Create(AHashSize: Int32; const AKey: THashLibByteArray);
+var
+  LIdx: Int32;
+begin
+  Inherited Create(AHashSize, BlockSizeInBytes);
+  System.SetLength(FBuffer, ParallelismDegree * BlockSizeInBytes);
+  System.SetLength(FLeafHashes, ParallelismDegree);
+  FKey := System.Copy(AKey);
+  FRootHash := Blake2BPCreateRoot;
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    FLeafHashes[LIdx] := Blake2BPCreateLeaf(LIdx);
+  end;
+end;
+
+destructor TBlake2BP.Destroy;
+var
+  LIdx: Int32;
+begin
+  Clear();
+  FRootHash.Free;
+  FRootHash := Nil;
+  for LIdx := System.Low(FLeafHashes) to System.High(FLeafHashes) do
+  begin
+    FLeafHashes[LIdx].Free;
+    FLeafHashes[LIdx] := Nil;
+  end;
+  FLeafHashes := Nil;
+  inherited Destroy;
+end;
+
+function TBlake2BP.GetName: String;
+begin
+  Result := Format('%s_%u', [Self.ClassName, Self.HashSize * 8]);
+end;
+
+procedure TBlake2BP.Initialize;
+var
+  LIdx: Int32;
+begin
+  FRootHash.Initialize;
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    FLeafHashes[LIdx].Initialize;
+    FLeafHashes[LIdx].HashSize := OutSizeInBytes;
+  end;
+  TArrayUtils.ZeroFill(FBuffer);
+  FBufferLength := 0;
+end;
+
+procedure TBlake2BP.ParallelComputation(AIdx: Int32;
+  ADataContainer: PDataContainer);
+var
+  LLeafHashes: THashLibGenericArray<TBlake2B>;
+  LTemp: THashLibByteArray;
+  LCounter: UInt64;
+  LPtrData: PByte;
+begin
+  System.SetLength(LTemp, BlockSizeInBytes);
+  LPtrData := ADataContainer^.PtrData;
+  LCounter := ADataContainer^.Counter;
+  System.Inc(LPtrData, AIdx * BlockSizeInBytes);
+  LLeafHashes := FLeafHashes;
+  while (LCounter >= (ParallelismDegree * BlockSizeInBytes)) do
+  begin
+    System.Move(LPtrData^, LTemp[0], BlockSizeInBytes);
+    LLeafHashes[AIdx].TransformBytes(LTemp, 0, BlockSizeInBytes);
+    System.Inc(LPtrData, UInt64(ParallelismDegree * BlockSizeInBytes));
+    LCounter := LCounter - UInt64(ParallelismDegree * BlockSizeInBytes);
+  end;
+end;
+
+{$IFDEF USE_PASMP}
+
+procedure TBlake2BP.PasMPParallelComputationWrapper(const AJob: PPasMPJob;
+  const AThreadIndex: LongInt; const ADataContainer: Pointer;
+  const AFromIndex, AToIndex: TPasMPNativeInt);
+begin
+  ParallelComputation(AFromIndex, ADataContainer);
+end;
+{$ENDIF}
+{$IFDEF USE_MTPROCS}
+
+procedure TBlake2BP.MTProcsParallelComputationWrapper(AIdx: PtrInt;
+  ADataContainer: Pointer; AItem: TMultiThreadProcItem);
+begin
+  ParallelComputation(AIdx, ADataContainer);
+end;
+{$ENDIF}
+{$IF DEFINED(USE_DELPHI_PPL)}
+
+procedure TBlake2BP.DoParallelComputation(ADataContainer: PDataContainer);
+
+  function CreateTask(AIdx: Int32; ADataContainer: PDataContainer): ITask;
+  begin
+    Result := TTask.Create(
+      procedure()
+      begin
+        ParallelComputation(AIdx, ADataContainer);
+      end);
+  end;
+
+var
+  LArrayTasks: array of ITask;
+  LIdx: Int32;
+begin
+  System.SetLength(LArrayTasks, ParallelismDegree);
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    LArrayTasks[LIdx] := CreateTask(LIdx, ADataContainer);
+    LArrayTasks[LIdx].Start;
+  end;
+  TTask.WaitForAll(LArrayTasks);
+end;
+
+{$ELSEIF DEFINED(USE_PASMP) OR DEFINED(USE_MTPROCS)}
+
+procedure TBlake2BP.DoParallelComputation(ADataContainer: PDataContainer);
+begin
+{$IF DEFINED(USE_PASMP)}
+  TPasMP.CreateGlobalInstance;
+  GlobalPasMP.Invoke(GlobalPasMP.ParallelFor(ADataContainer, 0,
+    ParallelismDegree - 1, PasMPParallelComputationWrapper));
+{$ELSEIF DEFINED(USE_MTPROCS)}
+  ProcThreadPool.DoParallel(MTProcsParallelComputationWrapper, 0,
+    ParallelismDegree - 1, ADataContainer);
+{$ELSE}
+{$MESSAGE ERROR 'Unsupported Threading Library.'}
+{$IFEND USE_PASMP}
+end;
+
+{$ELSE}
+
+procedure TBlake2BP.DoParallelComputation(ADataContainer: PDataContainer);
+var
+  LIdx: Int32;
+begin
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    ParallelComputation(LIdx, ADataContainer);
+  end;
+end;
+{$IFEND USE_DELPHI_PPL}
+
+procedure TBlake2BP.TransformBytes(const AData: THashLibByteArray;
+AIndex, ADataLength: Int32);
+var
+  LLeft, LFill, LDataLength: UInt64;
+  LPtrData: PByte;
+  LIdx: Int32;
+  LLeafHashes: THashLibGenericArray<TBlake2B>;
+  LPtrDataContainer: PDataContainer;
+begin
+  LLeafHashes := FLeafHashes;
+  LDataLength := UInt64(ADataLength);
+  LPtrData := PByte(AData) + AIndex;
+  LLeft := FBufferLength;
+  LFill := UInt64(System.Length(FBuffer)) - LLeft;
+
+  if (LLeft > 0) and (LDataLength >= LFill) then
+  begin
+    System.Move(LPtrData^, FBuffer[LLeft], LFill);
+
+    for LIdx := 0 to System.Pred(ParallelismDegree) do
+    begin
+      LLeafHashes[LIdx].TransformBytes(FBuffer, LIdx * BlockSizeInBytes,
+        BlockSizeInBytes);
+    end;
+
+    System.Inc(LPtrData, LFill);
+    LDataLength := LDataLength - LFill;
+    LLeft := 0;
+  end;
+
+  LPtrDataContainer := New(PDataContainer);
+  try
+    LPtrDataContainer^.PtrData := LPtrData;
+    LPtrDataContainer^.Counter := LDataLength;
+    DoParallelComputation(LPtrDataContainer);
+  finally
+    Dispose(LPtrDataContainer);
+  end;
+
+  System.Inc(LPtrData, LDataLength - (LDataLength mod UInt64(ParallelismDegree *
+    BlockSizeInBytes)));
+  LDataLength := LDataLength mod UInt64(ParallelismDegree * BlockSizeInBytes);
+
+  if (LDataLength > 0) then
+  begin
+    System.Move(LPtrData^, FBuffer[LLeft], LDataLength);
+  end;
+
+  FBufferLength := UInt32(LLeft) + UInt32(LDataLength);
+end;
+
+function TBlake2BP.TransformFinal: IHashResult;
+var
+  LHash: THashLibMatrixByteArray;
+  LIdx: Int32;
+  LLeft: UInt64;
+  LLeafHashes: THashLibGenericArray<TBlake2B>;
+  LRootHash: TBlake2B;
+begin
+  LLeafHashes := FLeafHashes;
+  LRootHash := FRootHash;
+  System.SetLength(LHash, ParallelismDegree);
+  for LIdx := System.Low(LHash) to System.High(LHash) do
+  begin
+    System.SetLength(LHash[LIdx], OutSizeInBytes);
+  end;
+
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    if (FBufferLength > (LIdx * BlockSizeInBytes)) then
+    begin
+      LLeft := FBufferLength - UInt64(LIdx * BlockSizeInBytes);
+      if (LLeft > BlockSizeInBytes) then
+      begin
+        LLeft := BlockSizeInBytes;
+      end;
+      LLeafHashes[LIdx].TransformBytes(FBuffer, LIdx * BlockSizeInBytes,
+        Int32(LLeft));
+    end;
+
+    LHash[LIdx] := LLeafHashes[LIdx].TransformFinal().GetBytes();
+  end;
+
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    LRootHash.TransformBytes(LHash[LIdx], 0, OutSizeInBytes);
+  end;
+  Result := LRootHash.TransformFinal();
+  Initialize();
+end;
+
+end.

+ 576 - 0
src/libraries/hashlib4pascal/HlpBlake2BParams.pas

@@ -0,0 +1,576 @@
+unit HlpBlake2BParams;
+
+{$I HashLib.inc}
+
+interface
+
+uses
+  HlpIBlake2BParams,
+  HlpHashSize,
+  HlpArrayUtils,
+  HlpHashLibTypes,
+  HlpConverters;
+
+resourcestring
+  SInvalidHashSize =
+    'BLAKE2B HashSize must be restricted to one of the following [1 .. 64], "%d"';
+  SInvalidKeyLength = '"Key" Length Must Not Be Greater Than 64, "%d"';
+  SInvalidPersonalisationLength =
+    '"Personalisation" Length Must Be Equal To 16, "%d"';
+  SInvalidSaltLength = '"Salt" Length Must Be Equal To 16, "%d"';
+
+  SInvalidFanOutParameter =
+    'FanOut Value Should be Between [0 .. 255] for Blake2B';
+  SInvalidMaxDepthParameter =
+    'MaxDepth Value Should be Between [1 .. 255] for Blake2B';
+  SInvalidNodeDepthParameter =
+    'NodeDepth Value Should be Between [0 .. 255] for Blake2B';
+  SInvalidInnerHashSizeParameter =
+    'InnerHashSize Value Should be Between [0 .. 64] for Blake2B';
+  SInvalidNodeOffsetParameter =
+    'NodeOffset Value Should be Between [0 .. (2^64-1)] for Blake2B';
+
+  STreeIncorrectInnerHashSize =
+    'Tree Inner Hash Size Must Not Be Greater Than 64, "%d"';
+
+type
+  TBlake2BConfig = class sealed(TInterfacedObject, IBlake2BConfig)
+
+  strict private
+
+  var
+
+    FHashSize: Int32;
+    FPersonalisation, FSalt, FKey: THashLibByteArray;
+
+    class function GetDefaultConfig: IBlake2BConfig; static;
+
+    procedure ValidateHashSize(AHashSize: Int32); inline;
+    procedure ValidateKeyLength(const AKey: THashLibByteArray); inline;
+    procedure ValidatePersonalisationLength(const APersonalisation
+      : THashLibByteArray); inline;
+    procedure ValidateSaltLength(const ASalt: THashLibByteArray); inline;
+
+    function GetPersonalisation: THashLibByteArray; inline;
+    procedure SetPersonalisation(const AValue: THashLibByteArray); inline;
+
+    function GetSalt: THashLibByteArray; inline;
+    procedure SetSalt(const AValue: THashLibByteArray); inline;
+
+    function GetKey: THashLibByteArray; inline;
+    procedure SetKey(const AValue: THashLibByteArray); inline;
+
+    function GetHashSize: Int32; inline;
+    procedure SetHashSize(AValue: Int32); inline;
+
+  public
+    constructor Create(AHashSize: THashSize = THashSize.hsHashSize512);
+      overload;
+    constructor Create(AHashSize: Int32); overload;
+    destructor Destroy; override;
+    property Personalisation: THashLibByteArray read GetPersonalisation
+      write SetPersonalisation;
+    property Salt: THashLibByteArray read GetSalt write SetSalt;
+    property Key: THashLibByteArray read GetKey write SetKey;
+    property HashSize: Int32 read GetHashSize write SetHashSize;
+
+    class property DefaultConfig: IBlake2BConfig read GetDefaultConfig;
+
+    function Clone(): IBlake2BConfig;
+
+    procedure Clear();
+
+  end;
+
+type
+  TBlake2BTreeConfig = class sealed(TInterfacedObject, IBlake2BTreeConfig)
+
+  strict private
+
+  var
+    FFanOut, FMaxDepth, FNodeDepth, FInnerHashSize: Byte;
+    FLeafSize: UInt32;
+    FNodeOffset: UInt64;
+    FIsLastNode: Boolean;
+
+    procedure ValidateFanOut(AFanOut: Byte); inline;
+    procedure ValidateInnerHashSize(AInnerHashSize: Byte); inline;
+    procedure ValidateMaxDepth(AMaxDepth: Byte); inline;
+    procedure ValidateNodeDepth(ANodeDepth: Byte); inline;
+    procedure ValidateNodeOffset(ANodeOffset: UInt64); inline;
+
+    function GetFanOut: Byte; inline;
+    procedure SetFanOut(AValue: Byte); inline;
+
+    function GetMaxDepth: Byte; inline;
+    procedure SetMaxDepth(AValue: Byte); inline;
+
+    function GetNodeDepth: Byte; inline;
+    procedure SetNodeDepth(AValue: Byte); inline;
+
+    function GetInnerHashSize: Byte; inline;
+    procedure SetInnerHashSize(AValue: Byte); inline;
+
+    function GetLeafSize: UInt32; inline;
+    procedure SetLeafSize(AValue: UInt32); inline;
+
+    function GetNodeOffset: UInt64; inline;
+    procedure SetNodeOffset(AValue: UInt64); inline;
+
+    function GetIsLastNode: Boolean; inline;
+    procedure SetIsLastNode(AValue: Boolean); inline;
+
+    class function GetSequentialTreeConfig: IBlake2BTreeConfig; static;
+
+  public
+    constructor Create();
+
+    property FanOut: Byte read GetFanOut write SetFanOut;
+
+    property MaxDepth: Byte read GetMaxDepth write SetMaxDepth;
+
+    property NodeDepth: Byte read GetNodeDepth write SetNodeDepth;
+
+    property InnerHashSize: Byte read GetInnerHashSize write SetInnerHashSize;
+
+    property LeafSize: UInt32 read GetLeafSize write SetLeafSize;
+
+    property NodeOffset: UInt64 read GetNodeOffset write SetNodeOffset;
+
+    property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
+
+    function Clone(): IBlake2BTreeConfig;
+
+    class property SequentialTreeConfig: IBlake2BTreeConfig
+      read GetSequentialTreeConfig;
+
+  end;
+
+type
+  TBlake2BIvBuilder = class sealed(TObject)
+
+  strict private
+
+    class procedure VerifyConfigB(const AConfig: IBlake2BConfig;
+      const ATreeConfig: IBlake2BTreeConfig; AIsSequential: Boolean); static;
+
+  public
+    class function ConfigB(const AConfig: IBlake2BConfig;
+      var ATreeConfig: IBlake2BTreeConfig): THashLibUInt64Array; static;
+
+  end;
+
+implementation
+
+{ TBlake2BConfig }
+
+class function TBlake2BConfig.GetDefaultConfig: IBlake2BConfig;
+begin
+  Result := TBlake2BConfig.Create();
+end;
+
+procedure TBlake2BConfig.ValidateHashSize(AHashSize: Int32);
+begin
+  if not((AHashSize) in [1 .. 64]) or (((AHashSize * 8) and 7) <> 0) then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidHashSize,
+      [AHashSize]);
+  end;
+end;
+
+procedure TBlake2BConfig.ValidateKeyLength(const AKey: THashLibByteArray);
+var
+  KeyLength: Int32;
+begin
+  if (AKey <> Nil) then
+  begin
+    KeyLength := System.Length(AKey);
+    if (KeyLength > 64) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidKeyLength,
+        [KeyLength]);
+    end;
+  end;
+end;
+
+procedure TBlake2BConfig.ValidatePersonalisationLength(const APersonalisation
+  : THashLibByteArray);
+var
+  PersonalisationLength: Int32;
+begin
+  if (APersonalisation <> Nil) then
+  begin
+    PersonalisationLength := System.Length(APersonalisation);
+    if (PersonalisationLength <> 16) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidPersonalisationLength, [PersonalisationLength]);
+    end;
+  end;
+end;
+
+procedure TBlake2BConfig.ValidateSaltLength(const ASalt: THashLibByteArray);
+var
+  SaltLength: Int32;
+begin
+  if (ASalt <> Nil) then
+  begin
+    SaltLength := System.Length(ASalt);
+    if (SaltLength <> 16) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidSaltLength, [SaltLength]);
+    end;
+  end;
+end;
+
+function TBlake2BConfig.GetHashSize: Int32;
+begin
+  Result := FHashSize;
+end;
+
+function TBlake2BConfig.GetKey: THashLibByteArray;
+begin
+  Result := FKey;
+end;
+
+function TBlake2BConfig.GetPersonalisation: THashLibByteArray;
+begin
+  Result := FPersonalisation;
+end;
+
+function TBlake2BConfig.GetSalt: THashLibByteArray;
+begin
+  Result := FSalt;
+end;
+
+procedure TBlake2BConfig.SetHashSize(AValue: Int32);
+begin
+  ValidateHashSize(AValue);
+  FHashSize := AValue;
+end;
+
+procedure TBlake2BConfig.SetKey(const AValue: THashLibByteArray);
+begin
+  ValidateKeyLength(AValue);
+  FKey := System.Copy(AValue);
+end;
+
+procedure TBlake2BConfig.SetPersonalisation(const AValue: THashLibByteArray);
+begin
+  ValidatePersonalisationLength(AValue);
+  FPersonalisation := System.Copy(AValue);
+end;
+
+procedure TBlake2BConfig.SetSalt(const AValue: THashLibByteArray);
+begin
+  ValidateSaltLength(AValue);
+  FSalt := System.Copy(AValue);
+end;
+
+constructor TBlake2BConfig.Create(AHashSize: THashSize);
+var
+  LHashSize: Int32;
+begin
+  Inherited Create();
+  LHashSize := Int32(AHashSize);
+  ValidateHashSize(LHashSize);
+  FHashSize := LHashSize;
+end;
+
+constructor TBlake2BConfig.Create(AHashSize: Int32);
+begin
+  Inherited Create();
+  ValidateHashSize(AHashSize);
+  FHashSize := AHashSize;
+end;
+
+procedure TBlake2BConfig.Clear;
+begin
+  TArrayUtils.ZeroFill(FKey);
+end;
+
+destructor TBlake2BConfig.Destroy;
+begin
+  Clear();
+  inherited Destroy;
+end;
+
+function TBlake2BConfig.Clone(): IBlake2BConfig;
+begin
+  Result := TBlake2BConfig.Create(FHashSize);
+  Result.Key := System.Copy(FKey);
+  Result.Personalisation := System.Copy(FPersonalisation);
+  Result.Salt := System.Copy(FSalt);
+end;
+
+{ TBlake2BTreeConfig }
+
+procedure TBlake2BTreeConfig.ValidateFanOut(AFanOut: Byte);
+begin
+  if not(AFanOut in [0 .. 255]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes(@SInvalidFanOutParameter);
+  end;
+end;
+
+procedure TBlake2BTreeConfig.ValidateInnerHashSize(AInnerHashSize: Byte);
+begin
+  if not(AInnerHashSize in [0 .. 64]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidInnerHashSizeParameter);
+  end;
+end;
+
+procedure TBlake2BTreeConfig.ValidateMaxDepth(AMaxDepth: Byte);
+begin
+  if not(AMaxDepth in [1 .. 255]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidMaxDepthParameter);
+  end;
+end;
+
+procedure TBlake2BTreeConfig.ValidateNodeDepth(ANodeDepth: Byte);
+begin
+  if not(ANodeDepth in [0 .. 255]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidNodeDepthParameter);
+  end;
+end;
+
+procedure TBlake2BTreeConfig.ValidateNodeOffset(ANodeOffset: UInt64);
+begin
+  // ANodeOffset > ((2^64) - 1)
+  if ANodeOffset > System.High(UInt64) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidNodeOffsetParameter);
+  end;
+end;
+
+function TBlake2BTreeConfig.GetFanOut: Byte;
+begin
+  Result := FFanOut;
+end;
+
+function TBlake2BTreeConfig.GetInnerHashSize: Byte;
+begin
+  Result := FInnerHashSize;
+end;
+
+function TBlake2BTreeConfig.GetIsLastNode: Boolean;
+begin
+  Result := FIsLastNode;
+end;
+
+function TBlake2BTreeConfig.GetLeafSize: UInt32;
+begin
+  Result := FLeafSize;
+end;
+
+function TBlake2BTreeConfig.GetMaxDepth: Byte;
+begin
+  Result := FMaxDepth;
+end;
+
+function TBlake2BTreeConfig.GetNodeDepth: Byte;
+begin
+  Result := FNodeDepth;
+end;
+
+function TBlake2BTreeConfig.GetNodeOffset: UInt64;
+begin
+  Result := FNodeOffset;
+end;
+
+procedure TBlake2BTreeConfig.SetFanOut(AValue: Byte);
+begin
+  ValidateFanOut(AValue);
+  FFanOut := AValue;
+end;
+
+procedure TBlake2BTreeConfig.SetInnerHashSize(AValue: Byte);
+begin
+  ValidateInnerHashSize(AValue);
+  FInnerHashSize := AValue;
+end;
+
+procedure TBlake2BTreeConfig.SetIsLastNode(AValue: Boolean);
+begin
+  FIsLastNode := AValue;
+end;
+
+procedure TBlake2BTreeConfig.SetLeafSize(AValue: UInt32);
+begin
+  FLeafSize := AValue;
+end;
+
+procedure TBlake2BTreeConfig.SetMaxDepth(AValue: Byte);
+begin
+  ValidateMaxDepth(AValue);
+  FMaxDepth := AValue;
+end;
+
+procedure TBlake2BTreeConfig.SetNodeDepth(AValue: Byte);
+begin
+  ValidateNodeDepth(AValue);
+  FNodeDepth := AValue;
+end;
+
+procedure TBlake2BTreeConfig.SetNodeOffset(AValue: UInt64);
+begin
+  ValidateNodeOffset(AValue);
+  FNodeOffset := AValue;
+end;
+
+constructor TBlake2BTreeConfig.Create;
+begin
+  Inherited Create();
+  FFanOut := 0;
+  FMaxDepth := 0;
+  FLeafSize := 64;
+  FNodeOffset := 0;
+  FNodeDepth := 0;
+  FInnerHashSize := 64;
+  FIsLastNode := False;
+end;
+
+function TBlake2BTreeConfig.Clone(): IBlake2BTreeConfig;
+var
+  LResult: TBlake2BTreeConfig;
+begin
+  LResult := TBlake2BTreeConfig.Create();
+  LResult.FFanOut := FFanOut;
+  LResult.FInnerHashSize := FInnerHashSize;
+  LResult.FMaxDepth := FMaxDepth;
+  LResult.FNodeDepth := FNodeDepth;
+  LResult.FLeafSize := FLeafSize;
+  LResult.FNodeOffset := FNodeOffset;
+  LResult.FIsLastNode := FIsLastNode;
+  Result := LResult as IBlake2BTreeConfig;
+end;
+
+class function TBlake2BTreeConfig.GetSequentialTreeConfig: IBlake2BTreeConfig;
+begin
+  Result := TBlake2BTreeConfig.Create();
+  Result.FanOut := 1;
+  Result.MaxDepth := 1;
+  Result.LeafSize := 0;
+  Result.NodeOffset := 0;
+  Result.NodeDepth := 0;
+  Result.InnerHashSize := 0;
+  Result.IsLastNode := False;
+end;
+
+{ TBlake2BIvBuilder }
+
+class procedure TBlake2BIvBuilder.VerifyConfigB(const AConfig: IBlake2BConfig;
+  const ATreeConfig: IBlake2BTreeConfig; AIsSequential: Boolean);
+begin
+
+  // digest length
+  if ((AConfig.HashSize <= 0) or (AConfig.HashSize > 64)) then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidHashSize,
+      [AConfig.HashSize]);
+  end;
+
+  // Key length
+  if (AConfig.Key <> Nil) then
+  begin
+    if (System.Length(AConfig.Key) > 64) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidKeyLength,
+        [System.Length(AConfig.Key)]);
+    end;
+  end;
+
+  // Personalisation length
+  if (AConfig.Personalisation <> Nil) then
+  begin
+    if (System.Length(AConfig.Personalisation) <> 16) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidPersonalisationLength,
+        [System.Length(AConfig.Personalisation)]);
+    end;
+  end;
+
+  // Salt length
+  if (AConfig.Salt <> Nil) then
+  begin
+    if (System.Length(AConfig.Salt) <> 16) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidSaltLength, [System.Length(AConfig.Salt)]);
+    end;
+  end;
+
+  // Tree InnerHashSize
+  if (ATreeConfig <> Nil) then
+  begin
+
+    if ((AIsSequential) and ((ATreeConfig.InnerHashSize <> 0))) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.Create
+        ('treeConfig.TreeIntermediateHashSize');
+    end;
+
+    if (ATreeConfig.InnerHashSize > 64) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@STreeIncorrectInnerHashSize, [ATreeConfig.InnerHashSize]);
+    end;
+  end;
+
+end;
+
+class function TBlake2BIvBuilder.ConfigB(const AConfig: IBlake2BConfig;
+  var ATreeConfig: IBlake2BTreeConfig): THashLibUInt64Array;
+var
+  LIsSequential: Boolean;
+  LBuffer: THashLibByteArray;
+begin
+  LIsSequential := ATreeConfig = Nil;
+  if (LIsSequential) then
+  begin
+    ATreeConfig := TBlake2BTreeConfig.SequentialTreeConfig;
+  end;
+
+  VerifyConfigB(AConfig, ATreeConfig, LIsSequential);
+
+  System.SetLength(LBuffer, 64);
+
+  LBuffer[0] := AConfig.HashSize;
+  LBuffer[1] := System.Length(AConfig.Key);
+
+  if ATreeConfig <> Nil then
+  begin
+    LBuffer[2] := ATreeConfig.FanOut;
+    LBuffer[3] := ATreeConfig.MaxDepth;
+    TConverters.ReadUInt32AsBytesLE(ATreeConfig.LeafSize, LBuffer, 4);
+    TConverters.ReadUInt64AsBytesLE(ATreeConfig.NodeOffset, LBuffer, 8);
+    LBuffer[16] := ATreeConfig.NodeDepth;
+    LBuffer[17] := ATreeConfig.InnerHashSize;
+  end;
+
+  if AConfig.Salt <> Nil then
+  begin
+    System.Move(AConfig.Salt[0], LBuffer[32], 16 * System.SizeOf(Byte));
+  end;
+
+  if AConfig.Personalisation <> Nil then
+  begin
+    System.Move(AConfig.Personalisation[0], LBuffer[48],
+      16 * System.SizeOf(Byte));
+  end;
+
+  System.SetLength(Result, 8);
+  TConverters.le64_copy(PByte(LBuffer), 0, PUInt64(Result), 0,
+    System.Length(LBuffer) * System.SizeOf(Byte));
+end;
+
+end.

+ 0 - 197
src/libraries/hashlib4pascal/HlpBlake2BTreeConfig.pas

@@ -1,197 +0,0 @@
-unit HlpBlake2BTreeConfig;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-  HlpIBlake2BTreeConfig,
-  HlpHashLibTypes;
-
-resourcestring
-  SInvalidFanOutParameter =
-    'FanOut Value Should be Between [0 .. 255] for Blake2B';
-  SInvalidMaxDepthParameter =
-    'FanOut Value Should be Between [1 .. 255] for Blake2B';
-  SInvalidNodeDepthParameter =
-    'NodeDepth Value Should be Between [0 .. 255] for Blake2B';
-  SInvalidInnerHashSizeParameter =
-    'InnerHashSize Value Should be Between [0 .. 64] for Blake2B';
-
-type
-
-  TBlake2BTreeConfig = class sealed(TInterfacedObject, IBlake2BTreeConfig)
-
-  strict private
-  var
-    FFanOut, FMaxDepth, FNodeDepth, FInnerHashSize: Byte;
-    FLeafSize: UInt32;
-    FNodeOffset: UInt64;
-    FIsLastNode: Boolean;
-
-    procedure ValidateFanOut(AFanOut: Byte); inline;
-    procedure ValidateInnerHashSize(AInnerHashSize: Byte); inline;
-    procedure ValidateMaxDepth(AMaxDepth: Byte); inline;
-    procedure ValidateNodeDepth(ANodeDepth: Byte); inline;
-
-    function GetFanOut: Byte; inline;
-    procedure SetFanOut(AValue: Byte); inline;
-
-    function GetMaxDepth: Byte; inline;
-    procedure SetMaxDepth(AValue: Byte); inline;
-
-    function GetNodeDepth: Byte; inline;
-    procedure SetNodeDepth(AValue: Byte); inline;
-
-    function GetInnerHashSize: Byte; inline;
-    procedure SetInnerHashSize(AValue: Byte); inline;
-
-    function GetLeafSize: UInt32; inline;
-    procedure SetLeafSize(AValue: UInt32); inline;
-
-    function GetNodeOffset: UInt64; inline;
-    procedure SetNodeOffset(AValue: UInt64); inline;
-
-    function GetIsLastNode: Boolean; inline;
-    procedure SetIsLastNode(AValue: Boolean); inline;
-
-  public
-    constructor Create();
-
-    property FanOut: Byte read GetFanOut write SetFanOut;
-
-    property MaxDepth: Byte read GetMaxDepth write SetMaxDepth;
-
-    property NodeDepth: Byte read GetNodeDepth write SetNodeDepth;
-
-    property InnerHashSize: Byte read GetInnerHashSize write SetInnerHashSize;
-
-    property LeafSize: UInt32 read GetLeafSize write SetLeafSize;
-
-    property NodeOffset: UInt64 read GetNodeOffset write SetNodeOffset;
-
-    property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
-
-  end;
-
-implementation
-
-{ TBlake2BTreeConfig }
-
-procedure TBlake2BTreeConfig.ValidateFanOut(AFanOut: Byte);
-begin
-  if not(AFanOut in [0 .. 255]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes(@SInvalidFanOutParameter);
-  end;
-end;
-
-procedure TBlake2BTreeConfig.ValidateInnerHashSize(AInnerHashSize: Byte);
-begin
-  if not(AInnerHashSize in [0 .. 64]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes
-      (@SInvalidInnerHashSizeParameter);
-  end;
-end;
-
-procedure TBlake2BTreeConfig.ValidateMaxDepth(AMaxDepth: Byte);
-begin
-  if not(AMaxDepth in [1 .. 255]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes
-      (@SInvalidMaxDepthParameter);
-  end;
-end;
-
-procedure TBlake2BTreeConfig.ValidateNodeDepth(ANodeDepth: Byte);
-begin
-  if not(ANodeDepth in [0 .. 255]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes
-      (@SInvalidNodeDepthParameter);
-  end;
-end;
-
-function TBlake2BTreeConfig.GetFanOut: Byte;
-begin
-  result := FFanOut;
-end;
-
-function TBlake2BTreeConfig.GetInnerHashSize: Byte;
-begin
-  result := FInnerHashSize;
-end;
-
-function TBlake2BTreeConfig.GetIsLastNode: Boolean;
-begin
-  result := FIsLastNode;
-end;
-
-function TBlake2BTreeConfig.GetLeafSize: UInt32;
-begin
-  result := FLeafSize;
-end;
-
-function TBlake2BTreeConfig.GetMaxDepth: Byte;
-begin
-  result := FMaxDepth;
-end;
-
-function TBlake2BTreeConfig.GetNodeDepth: Byte;
-begin
-  result := FNodeDepth;
-end;
-
-function TBlake2BTreeConfig.GetNodeOffset: UInt64;
-begin
-  result := FNodeOffset;
-end;
-
-procedure TBlake2BTreeConfig.SetFanOut(AValue: Byte);
-begin
-  ValidateFanOut(AValue);
-  FFanOut := AValue;
-end;
-
-procedure TBlake2BTreeConfig.SetInnerHashSize(AValue: Byte);
-begin
-  ValidateInnerHashSize(AValue);
-  FInnerHashSize := AValue;
-end;
-
-procedure TBlake2BTreeConfig.SetIsLastNode(AValue: Boolean);
-begin
-  FIsLastNode := AValue;
-end;
-
-procedure TBlake2BTreeConfig.SetLeafSize(AValue: UInt32);
-begin
-  FLeafSize := AValue;
-end;
-
-procedure TBlake2BTreeConfig.SetMaxDepth(AValue: Byte);
-begin
-  ValidateMaxDepth(AValue);
-  FMaxDepth := AValue;
-end;
-
-procedure TBlake2BTreeConfig.SetNodeDepth(AValue: Byte);
-begin
-  ValidateNodeDepth(AValue);
-  FNodeDepth := AValue;
-end;
-
-procedure TBlake2BTreeConfig.SetNodeOffset(AValue: UInt64);
-begin
-  FNodeOffset := AValue;
-end;
-
-constructor TBlake2BTreeConfig.Create;
-begin
-  Inherited Create();
-  ValidateInnerHashSize(64);
-  FInnerHashSize := 64;
-end;
-
-end.

+ 631 - 82
src/libraries/hashlib4pascal/HlpBlake2S.pas

@@ -6,17 +6,12 @@ interface
 
 
 uses
 uses
   SysUtils,
   SysUtils,
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpHash,
   HlpHash,
   HlpHashResult,
   HlpHashResult,
   HlpIHashResult,
   HlpIHashResult,
-  HlpIBlake2SConfig,
-  HlpBlake2SConfig,
-  HlpIBlake2STreeConfig,
-  HlpBlake2SIvBuilder,
+  HlpIBlake2SParams,
+  HlpBlake2SParams,
   HlpIHash,
   HlpIHash,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpConverters,
   HlpConverters,
@@ -26,9 +21,15 @@ uses
 resourcestring
 resourcestring
   SInvalidConfigLength = 'Config Length Must Be 8 Words';
   SInvalidConfigLength = 'Config Length Must Be 8 Words';
   SConfigNil = 'Config Cannot Be Nil';
   SConfigNil = 'Config Cannot Be Nil';
+  SInvalidXOFSize =
+    'XOFSize in Bits must be Multiples of 8 and be Between %u and %u Bytes.';
+  SOutputLengthInvalid = 'Output Length is above the Digest Length';
+  SOutputBufferTooShort = 'Output Buffer Too Short';
+  SMaximumOutputLengthExceeded = '"Maximum Length is 2^32 blocks of 32 bytes';
+  SWritetoXofAfterReadError = '"%s" Write to Xof after Read not Allowed';
 
 
 type
 type
-  TBlake2S = class sealed(THash, ICryptoNotBuildIn, ITransformBlock)
+  TBlake2S = class(THash, ICryptoNotBuildIn, ITransformBlock)
   strict private
   strict private
 
 
 {$REGION 'Consts'}
 {$REGION 'Consts'}
@@ -61,44 +62,171 @@ type
       (10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0));
       (10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0));
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDREGION}
 {$ENDREGION}
-    class var
-
-      FDefaultConfig: IBlake2SConfig;
 
 
   var
   var
-    FM: array [0 .. 15] of UInt32;
-    FRawConfig, FState: THashLibUInt32Array;
-    FKey, FBuffer: THashLibByteArray;
-{$IFNDEF USE_UNROLLED_VARIANT}
-    FV: array [0 .. 15] of UInt32;
-{$ENDIF USE_UNROLLED_VARIANT}
-    FFilledBufferCount, FHashSize, FBlockSize: Int32;
-    FCounter0, FCounter1, FFinalizationFlag0, FFinalizationFlag1: UInt32;
     FTreeConfig: IBlake2STreeConfig;
     FTreeConfig: IBlake2STreeConfig;
+    FConfig: IBlake2SConfig;
+    FDoTransformKeyBlock: Boolean;
 
 
-    class constructor Blake2SConfig();
+    procedure Blake2SIncrementCounter(AIncrementCount: UInt32); inline;
 
 
 {$IFNDEF USE_UNROLLED_VARIANT}
 {$IFNDEF USE_UNROLLED_VARIANT}
     procedure G(a, b, c, d, r, i: Int32); inline;
     procedure G(a, b, c, d, r, i: Int32); inline;
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
     procedure Compress(ABlock: PByte; AStart: Int32);
     procedure Compress(ABlock: PByte; AStart: Int32);
 
 
-    procedure Finish(); inline;
-
   strict protected
   strict protected
+  var
+    FState: THashLibUInt32Array;
+    FM: array [0 .. 15] of UInt32;
+    FBuffer: THashLibByteArray;
+{$IFNDEF USE_UNROLLED_VARIANT}
+    FV: array [0 .. 15] of UInt32;
+{$ENDIF USE_UNROLLED_VARIANT}
+    FFilledBufferCount: Int32;
+    FCounter0, FCounter1, FFinalizationFlag0, FFinalizationFlag1: UInt32;
 
 
+    procedure Finish();
     function GetName: String; override;
     function GetName: String; override;
 
 
   public
   public
     constructor Create(); overload;
     constructor Create(); overload;
     constructor Create(const AConfig: IBlake2SConfig); overload;
     constructor Create(const AConfig: IBlake2SConfig); overload;
     constructor Create(const AConfig: IBlake2SConfig;
     constructor Create(const AConfig: IBlake2SConfig;
-      const ATreeConfig: IBlake2STreeConfig); overload;
+      const ATreeConfig: IBlake2STreeConfig;
+      ADoTransformKeyBlock: Boolean = True); overload;
     procedure Initialize; override;
     procedure Initialize; override;
     procedure TransformBytes(const AData: THashLibByteArray;
     procedure TransformBytes(const AData: THashLibByteArray;
       AIndex, ADataLength: Int32); override;
       AIndex, ADataLength: Int32); override;
     function TransformFinal: IHashResult; override;
     function TransformFinal: IHashResult; override;
+    function CloneInternal(): TBlake2S;
+    function Clone(): IHash; override;
+
+  end;
+
+type
+  /// <summary>
+  /// <b>TBlake2XSConfig</b> is used to configure hash function parameters and
+  /// keying.
+  /// </summary>
+  TBlake2XSConfig = record
+  private
+  var
+    FBlake2SConfig: IBlake2SConfig; // blake2s config object
+    FBlake2STreeConfig: IBlake2STreeConfig; // blake2s tree config object
+
+    function GetBlake2SConfig(): IBlake2SConfig; inline;
+    procedure SetBlake2SConfig(const AValue: IBlake2SConfig); inline;
+    function GetBlake2STreeConfig(): IBlake2STreeConfig; inline;
+    procedure SetBlake2STreeConfig(const AValue: IBlake2STreeConfig); inline;
+  public
+  var
+
+    constructor Create(ABlake2SConfig: IBlake2SConfig;
+      ABlake2STreeConfig: IBlake2STreeConfig);
+
+    function Clone(): TBlake2XSConfig;
+
+    property Blake2SConfig: IBlake2SConfig read GetBlake2SConfig
+      write SetBlake2SConfig;
+
+    property Blake2STreeConfig: IBlake2STreeConfig read GetBlake2STreeConfig
+      write SetBlake2STreeConfig;
+  end;
+
+type
+  TBlake2XS = class sealed(TBlake2S, IXOF)
+  strict private
+  const
+    Blake2SHashSize = Int32(32);
+
+  const
+    // Magic number to indicate an unknown length of digest
+    UnknownDigestLengthInBytes = UInt16((UInt32(1) shl 16) - 1); // 65535 bytes
+    MaxNumberBlocks = UInt64(1) shl 32;
+    // 2^32 blocks of 32 bytes (128GiB)
+    // the maximum size in bytes the digest can produce when the length is unknown
+    UnknownMaxDigestLengthInBytes = UInt64(MaxNumberBlocks *
+      UInt64(Blake2SHashSize));
+
+  var
+    FXOFSizeInBits: UInt64;
+
+    function GetXOFSizeInBits: UInt64; inline;
+    procedure SetXOFSizeInBits(AXofSizeInBits: UInt64); inline;
+    function SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+
+    function NodeOffsetWithXOFDigestLength(AXOFSizeInBytes: UInt64)
+      : UInt64; inline;
+
+    function ComputeStepLength(): Int32; inline;
+
+    function GetResult(): THashLibByteArray;
+
+    constructor CreateInternal(const AConfig: IBlake2SConfig;
+      const ATreeConfig: IBlake2STreeConfig);
+
+  strict protected
+  var
+    FBlake2XSConfig: TBlake2XSConfig;
+    FBlake2XSBufferPosition, FDigestPosition, FBlockPosition: UInt64;
+    FRootConfig, FOutputConfig: TBlake2XSConfig;
+    FRootHashDigest, FBlake2XSBuffer: THashLibByteArray;
+    FFinalized: Boolean;
+
+    function GetName: String; override;
+    property XOFSizeInBits: UInt64 read GetXOFSizeInBits write SetXOFSizeInBits;
+  public
+
+    constructor Create(const ABlake2XSConfig: TBlake2XSConfig);
+    procedure Initialize(); override;
+    function Clone(): IHash; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ADataLength: Int32); override;
+    function TransformFinal(): IHashResult; override;
+
+    procedure DoOutput(const ADestination: THashLibByteArray;
+      ADestinationOffset, AOutputLength: UInt64);
+
+  end;
+
+type
+  TBlake2SMACNotBuildInAdapter = class sealed(THash, IBlake2SMAC,
+    IBlake2SMACNotBuildIn, ICrypto, ICryptoNotBuildIn)
+
+  strict private
+  var
+    FHash: IHash;
+    FKey: THashLibByteArray;
+
+    constructor Create(const ABlake2SKey, ASalt, APersonalisation
+      : THashLibByteArray; AOutputLengthInBits: Int32); overload;
+    constructor Create(const AHash: IHash;
+      const ABlake2SKey: THashLibByteArray); overload;
+
+  strict protected
+
+    function GetName: String; override;
+
+    function GetKey(): THashLibByteArray;
+    procedure SetKey(const AValue: THashLibByteArray);
+
+  public
+
+    destructor Destroy; override;
+
+    procedure Clear();
+
+    procedure Initialize(); override;
+    function TransformFinal(): IHashResult; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ALength: Int32); override;
     function Clone(): IHash; override;
     function Clone(): IHash; override;
+    property Key: THashLibByteArray read GetKey write SetKey;
+    property Name: String read GetName;
+
+    class function CreateBlake2SMAC(const ABlake2SKey, ASalt, APersonalisation
+      : THashLibByteArray; AOutputLengthInBits: Int32): IBlake2SMAC; static;
 
 
   end;
   end;
 
 
@@ -106,14 +234,15 @@ implementation
 
 
 { TBlake2S }
 { TBlake2S }
 
 
-class constructor TBlake2S.Blake2SConfig;
+constructor TBlake2S.Create();
 begin
 begin
-  FDefaultConfig := TBlake2SConfig.Create();
+  Create(TBlake2SConfig.Create() as IBlake2SConfig);
 end;
 end;
 
 
-constructor TBlake2S.Create();
+procedure TBlake2S.Blake2SIncrementCounter(AIncrementCount: UInt32);
 begin
 begin
-  Create(TBlake2SConfig.Create() as IBlake2SConfig);
+  FCounter0 := FCounter0 + AIncrementCount;
+  System.Inc(FCounter1, Ord(FCounter0 < AIncrementCount));
 end;
 end;
 
 
 {$IFNDEF USE_UNROLLED_VARIANT}
 {$IFNDEF USE_UNROLLED_VARIANT}
@@ -132,29 +261,35 @@ end;
 
 
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
 
 
-function TBlake2S.Clone(): IHash;
+function TBlake2S.CloneInternal(): TBlake2S;
 var
 var
-  LHashInstance: TBlake2S;
+  LTreeConfig: IBlake2STreeConfig;
 begin
 begin
-  LHashInstance := TBlake2S.Create(TBlake2SConfig.Create(FHashSize)
-    as IBlake2SConfig);
-  System.Move(FM, LHashInstance.FM, System.SizeOf(FM));
-  LHashInstance.FRawConfig := System.Copy(FRawConfig);
-  LHashInstance.FState := System.Copy(FState);
-  LHashInstance.FKey := System.Copy(FKey);
-  LHashInstance.FBuffer := System.Copy(FBuffer);
+  LTreeConfig := Nil;
+  if FTreeConfig <> Nil then
+  begin
+    LTreeConfig := FTreeConfig.Clone();
+  end;
+  Result := TBlake2S.Create(FConfig.Clone(), LTreeConfig, FDoTransformKeyBlock);
+  System.Move(FM, Result.FM, System.SizeOf(FM));
+  Result.FState := System.Copy(FState);
+  Result.FBuffer := System.Copy(FBuffer);
 {$IFNDEF USE_UNROLLED_VARIANT}
 {$IFNDEF USE_UNROLLED_VARIANT}
-  System.Move(FV, LHashInstance.FV, System.SizeOf(FV));
+  System.Move(FV, Result.FV, System.SizeOf(FV));
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
-  LHashInstance.FFilledBufferCount := FFilledBufferCount;
-  LHashInstance.FCounter0 := FCounter0;
-  LHashInstance.FCounter1 := FCounter1;
-  LHashInstance.FFinalizationFlag0 := FFinalizationFlag0;
-  LHashInstance.FFinalizationFlag1 := FFinalizationFlag1;
-  Result := LHashInstance as IHash;
+  Result.FFilledBufferCount := FFilledBufferCount;
+  Result.FCounter0 := FCounter0;
+  Result.FCounter1 := FCounter1;
+  Result.FFinalizationFlag0 := FFinalizationFlag0;
+  Result.FFinalizationFlag1 := FFinalizationFlag1;
   Result.BufferSize := BufferSize;
   Result.BufferSize := BufferSize;
 end;
 end;
 
 
+function TBlake2S.Clone(): IHash;
+begin
+  Result := CloneInternal() as IHash;
+end;
+
 procedure TBlake2S.Compress(ABlock: PByte; AStart: Int32);
 procedure TBlake2S.Compress(ABlock: PByte; AStart: Int32);
 var
 var
 {$IFDEF USE_UNROLLED_VARIANT}
 {$IFDEF USE_UNROLLED_VARIANT}
@@ -166,7 +301,7 @@ var
 
 
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
 begin
 begin
-  TConverters.le32_copy(ABlock, AStart, @(FM[0]), 0, FBlockSize);
+  TConverters.le32_copy(ABlock, AStart, @(FM[0]), 0, BlockSize);
 
 
 {$IFDEF USE_UNROLLED_VARIANT}
 {$IFDEF USE_UNROLLED_VARIANT}
   m0 := FM[0];
   m0 := FM[0];
@@ -1406,32 +1541,22 @@ begin
 end;
 end;
 
 
 constructor TBlake2S.Create(const AConfig: IBlake2SConfig;
 constructor TBlake2S.Create(const AConfig: IBlake2SConfig;
-  const ATreeConfig: IBlake2STreeConfig);
-var
-  LConfig: IBlake2SConfig;
+  const ATreeConfig: IBlake2STreeConfig; ADoTransformKeyBlock: Boolean);
 begin
 begin
-  LConfig := AConfig;
+  FConfig := AConfig;
   FTreeConfig := ATreeConfig;
   FTreeConfig := ATreeConfig;
-  FBlockSize := BlockSizeInBytes;
-
-  if (LConfig = Nil) then
-  begin
-    LConfig := FDefaultConfig;
-  end;
+  FDoTransformKeyBlock := ADoTransformKeyBlock;
 
 
-  FRawConfig := TBlake2SIvBuilder.ConfigS(LConfig, FTreeConfig);
-  if ((LConfig.Key <> Nil) and (System.Length(LConfig.Key) <> 0)) then
+  if (FConfig = Nil) then
   begin
   begin
-    FKey := System.Copy(LConfig.Key, System.Low(LConfig.Key),
-      System.Length(LConfig.Key));
-    System.SetLength(FKey, FBlockSize);
+    FConfig := TBlake2SConfig.DefaultConfig;
   end;
   end;
 
 
-  FHashSize := LConfig.HashSize;
-
   System.SetLength(FState, 8);
   System.SetLength(FState, 8);
 
 
-  Inherited Create(FHashSize, FBlockSize);
+  System.SetLength(FBuffer, BlockSizeInBytes);
+
+  Inherited Create(FConfig.HashSize, BlockSizeInBytes);
 end;
 end;
 
 
 procedure TBlake2S.Finish;
 procedure TBlake2S.Finish;
@@ -1439,11 +1564,11 @@ var
   LCount: Int32;
   LCount: Int32;
 begin
 begin
   // Last compression
   // Last compression
-  FCounter0 := FCounter0 + UInt32(FFilledBufferCount);
+  Blake2SIncrementCounter(UInt32(FFilledBufferCount));
 
 
   FFinalizationFlag0 := System.High(UInt32);
   FFinalizationFlag0 := System.High(UInt32);
 
 
-  if (FTreeConfig.IsLastNode) then
+  if (FTreeConfig <> Nil) and (FTreeConfig.IsLastNode) then
   begin
   begin
     FFinalizationFlag1 := System.High(UInt32);
     FFinalizationFlag1 := System.High(UInt32);
   end;
   end;
@@ -1462,12 +1587,27 @@ end;
 procedure TBlake2S.Initialize;
 procedure TBlake2S.Initialize;
 var
 var
   LIdx: Int32;
   LIdx: Int32;
+  LBlock: THashLibByteArray;
+  LRawConfig: THashLibUInt32Array;
 begin
 begin
-  if (FRawConfig = Nil) then
+  LRawConfig := TBlake2SIvBuilder.ConfigS(FConfig, FTreeConfig);
+  LBlock := Nil;
+
+  if FDoTransformKeyBlock then
+  begin
+    if ((FConfig.Key <> Nil) and (System.Length(FConfig.Key) <> 0)) then
+    begin
+      LBlock := System.Copy(FConfig.Key, System.Low(FConfig.Key),
+        System.Length(FConfig.Key));
+      System.SetLength(LBlock, BlockSizeInBytes);
+    end;
+  end;
+
+  if (LRawConfig = Nil) then
   begin
   begin
     raise EArgumentNilHashLibException.CreateRes(@SConfigNil);
     raise EArgumentNilHashLibException.CreateRes(@SConfigNil);
   end;
   end;
-  if (System.Length(FRawConfig) <> 8) then
+  if (System.Length(LRawConfig) <> 8) then
   begin
   begin
     raise EArgumentHashLibException.CreateRes(@SInvalidConfigLength);
     raise EArgumentHashLibException.CreateRes(@SInvalidConfigLength);
   end;
   end;
@@ -1488,8 +1628,6 @@ begin
 
 
   FFilledBufferCount := 0;
   FFilledBufferCount := 0;
 
 
-  System.SetLength(FBuffer, BlockSizeInBytes);
-
   TArrayUtils.ZeroFill(FBuffer);
   TArrayUtils.ZeroFill(FBuffer);
 
 
   System.FillChar(FM, System.SizeOf(FM), UInt32(0));
   System.FillChar(FM, System.SizeOf(FM), UInt32(0));
@@ -1499,12 +1637,16 @@ begin
 {$ENDIF USE_UNROLLED_VARIANT}
 {$ENDIF USE_UNROLLED_VARIANT}
   for LIdx := 0 to 7 do
   for LIdx := 0 to 7 do
   begin
   begin
-    FState[LIdx] := FState[LIdx] xor FRawConfig[LIdx];
+    FState[LIdx] := FState[LIdx] xor LRawConfig[LIdx];
   end;
   end;
 
 
-  if (FKey <> Nil) then
+  if FDoTransformKeyBlock then
   begin
   begin
-    TransformBytes(FKey, 0, System.Length(FKey));
+    if (LBlock <> Nil) then
+    begin
+      TransformBytes(LBlock, 0, System.Length(LBlock));
+      TArrayUtils.ZeroFill(LBlock); // burn key from memory
+    end;
   end;
   end;
 end;
 end;
 
 
@@ -1523,11 +1665,7 @@ begin
       System.Move(AData[LOffset], FBuffer[FFilledBufferCount],
       System.Move(AData[LOffset], FBuffer[FFilledBufferCount],
         LBufferRemaining);
         LBufferRemaining);
     end;
     end;
-    FCounter0 := FCounter0 + UInt32(BlockSizeInBytes);
-    if (FCounter0 = 0) then
-    begin
-      System.Inc(FCounter1);
-    end;
+    Blake2SIncrementCounter(UInt32(BlockSizeInBytes));
     Compress(PByte(FBuffer), 0);
     Compress(PByte(FBuffer), 0);
     LOffset := LOffset + LBufferRemaining;
     LOffset := LOffset + LBufferRemaining;
     ADataLength := ADataLength - LBufferRemaining;
     ADataLength := ADataLength - LBufferRemaining;
@@ -1536,11 +1674,7 @@ begin
 
 
   while (ADataLength > BlockSizeInBytes) do
   while (ADataLength > BlockSizeInBytes) do
   begin
   begin
-    FCounter0 := FCounter0 + UInt32(BlockSizeInBytes);
-    if (FCounter0 = 0) then
-    begin
-      System.Inc(FCounter1);
-    end;
+    Blake2SIncrementCounter(UInt32(BlockSizeInBytes));
     Compress(PByte(AData), LOffset);
     Compress(PByte(AData), LOffset);
     LOffset := LOffset + BlockSizeInBytes;
     LOffset := LOffset + BlockSizeInBytes;
     ADataLength := ADataLength - BlockSizeInBytes;
     ADataLength := ADataLength - BlockSizeInBytes;
@@ -1558,7 +1692,7 @@ var
   LBuffer: THashLibByteArray;
   LBuffer: THashLibByteArray;
 begin
 begin
   Finish();
   Finish();
-  System.SetLength(LBuffer, FHashSize);
+  System.SetLength(LBuffer, HashSize);
   TConverters.le32_copy(PCardinal(FState), 0, PByte(LBuffer), 0,
   TConverters.le32_copy(PCardinal(FState), 0, PByte(LBuffer), 0,
     System.Length(LBuffer));
     System.Length(LBuffer));
   Result := THashResult.Create(LBuffer);
   Result := THashResult.Create(LBuffer);
@@ -1570,4 +1704,419 @@ begin
   Result := Format('%s_%u', [Self.ClassName, Self.HashSize * 8]);
   Result := Format('%s_%u', [Self.ClassName, Self.HashSize * 8]);
 end;
 end;
 
 
+{ TBlake2XSConfig }
+
+function TBlake2XSConfig.GetBlake2SConfig: IBlake2SConfig;
+begin
+  Result := FBlake2SConfig;
+end;
+
+function TBlake2XSConfig.GetBlake2STreeConfig: IBlake2STreeConfig;
+begin
+  Result := FBlake2STreeConfig;
+end;
+
+procedure TBlake2XSConfig.SetBlake2SConfig(const AValue: IBlake2SConfig);
+begin
+  FBlake2SConfig := AValue;
+end;
+
+procedure TBlake2XSConfig.SetBlake2STreeConfig(const AValue
+  : IBlake2STreeConfig);
+begin
+  FBlake2STreeConfig := AValue;
+end;
+
+function TBlake2XSConfig.Clone(): TBlake2XSConfig;
+begin
+  Result := Default (TBlake2XSConfig);
+  if FBlake2SConfig <> Nil then
+  begin
+    Result.Blake2SConfig := FBlake2SConfig.Clone();
+  end;
+
+  if FBlake2STreeConfig <> Nil then
+  begin
+    Result.Blake2STreeConfig := FBlake2STreeConfig.Clone();
+  end;
+end;
+
+constructor TBlake2XSConfig.Create(ABlake2SConfig: IBlake2SConfig;
+  ABlake2STreeConfig: IBlake2STreeConfig);
+begin
+  FBlake2SConfig := ABlake2SConfig;
+  FBlake2STreeConfig := ABlake2STreeConfig;
+end;
+
+{ TBlake2XS }
+
+function TBlake2XS.GetXOFSizeInBits: UInt64;
+begin
+  Result := FXOFSizeInBits;
+end;
+
+procedure TBlake2XS.SetXOFSizeInBits(AXofSizeInBits: UInt64);
+begin
+  SetXOFSizeInBitsInternal(AXofSizeInBits);
+end;
+
+function TBlake2XS.SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+var
+  LXofSizeInBytes: UInt64;
+begin
+  LXofSizeInBytes := AXofSizeInBits shr 3;
+  If ((AXofSizeInBits and $7) <> 0) or (LXofSizeInBytes < 1) or
+    (LXofSizeInBytes > UInt64(UnknownDigestLengthInBytes)) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateResFmt(@SInvalidXOFSize,
+      [1, UInt64(UnknownDigestLengthInBytes)]);
+  end;
+  FXOFSizeInBits := AXofSizeInBits;
+  Result := Self;
+end;
+
+function TBlake2XS.NodeOffsetWithXOFDigestLength(AXOFSizeInBytes
+  : UInt64): UInt64;
+begin
+  Result := (UInt64(AXOFSizeInBytes) shl 32);
+end;
+
+function TBlake2XS.ComputeStepLength: Int32;
+var
+  LXofSizeInBytes, LDiff: UInt64;
+begin
+  LXofSizeInBytes := XOFSizeInBits shr 3;
+  LDiff := LXofSizeInBytes - FDigestPosition;
+  if (LXofSizeInBytes = UInt64(UnknownDigestLengthInBytes)) then
+  begin
+    Result := Blake2SHashSize;
+    Exit;
+  end;
+
+  if UInt64(Blake2SHashSize) < LDiff then
+  begin
+    Result := UInt64(Blake2SHashSize)
+  end
+  else
+  begin
+    Result := LDiff;
+  end;
+end;
+
+function TBlake2XS.GetName: String;
+begin
+  Result := Format('%s_%s_%u', [Self.ClassName, 'XOFSizeInBytes',
+    (Self as IXOF).XOFSizeInBits shr 3]);
+end;
+
+function TBlake2XS.Clone(): IHash;
+var
+  LHashInstance: TBlake2XS;
+  LXof: IXOF;
+begin
+  // Xof Cloning
+  LXof := (TBlake2XS.CreateInternal(FRootConfig.Blake2SConfig,
+    FRootConfig.Blake2STreeConfig) as IXOF);
+  LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
+  // Blake2XS Cloning
+  LHashInstance := LXof as TBlake2XS;
+  LHashInstance.FBlake2XSConfig := FBlake2XSConfig.Clone();
+  LHashInstance.FBlake2XSBufferPosition := FBlake2XSBufferPosition;
+  LHashInstance.FDigestPosition := FDigestPosition;
+  LHashInstance.FBlockPosition := FBlockPosition;
+  LHashInstance.FRootConfig := FRootConfig.Clone();
+  LHashInstance.FOutputConfig := FOutputConfig.Clone();
+  LHashInstance.FRootHashDigest := System.Copy(FRootHashDigest);
+  LHashInstance.FBlake2XSBuffer := System.Copy(FBlake2XSBuffer);
+  LHashInstance.FFinalized := FFinalized;
+
+  // Internal Blake2S Cloning
+  System.Move(FM, LHashInstance.FM, System.SizeOf(FM));
+  LHashInstance.FState := System.Copy(FState);
+  LHashInstance.FBuffer := System.Copy(FBuffer);
+{$IFNDEF USE_UNROLLED_VARIANT}
+  System.Move(FV, LHashInstance.FV, System.SizeOf(FV));
+{$ENDIF USE_UNROLLED_VARIANT}
+  LHashInstance.FFilledBufferCount := FFilledBufferCount;
+  LHashInstance.FCounter0 := FCounter0;
+  LHashInstance.FCounter1 := FCounter1;
+  LHashInstance.FFinalizationFlag0 := FFinalizationFlag0;
+  LHashInstance.FFinalizationFlag1 := FFinalizationFlag1;
+
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TBlake2XS.CreateInternal(const AConfig: IBlake2SConfig;
+  const ATreeConfig: IBlake2STreeConfig);
+begin
+  inherited Create(AConfig, ATreeConfig);
+end;
+
+constructor TBlake2XS.Create(const ABlake2XSConfig: TBlake2XSConfig);
+begin
+  FBlake2XSConfig := ABlake2XSConfig;
+  // Create root hash config.
+  FRootConfig := Default (TBlake2XSConfig);
+
+  FRootConfig.Blake2SConfig := FBlake2XSConfig.Blake2SConfig;
+
+  if FRootConfig.Blake2SConfig = Nil then
+  begin
+    FRootConfig.Blake2SConfig := TBlake2SConfig.Create();
+  end
+  else
+  begin
+    FRootConfig.Blake2SConfig.Key := FBlake2XSConfig.Blake2SConfig.Key;
+    FRootConfig.Blake2SConfig.Salt := FBlake2XSConfig.Blake2SConfig.Salt;
+    FRootConfig.Blake2SConfig.Personalisation :=
+      FBlake2XSConfig.Blake2SConfig.Personalisation;
+  end;
+
+  FRootConfig.Blake2STreeConfig := FBlake2XSConfig.Blake2STreeConfig;
+
+  if FRootConfig.Blake2STreeConfig = Nil then
+  begin
+    FRootConfig.Blake2STreeConfig := TBlake2STreeConfig.Create();
+    FRootConfig.Blake2STreeConfig.FanOut := 1;
+    FRootConfig.Blake2STreeConfig.MaxDepth := 1;
+
+    FRootConfig.Blake2STreeConfig.LeafSize := 0;
+    FRootConfig.Blake2STreeConfig.NodeOffset := 0;
+    FRootConfig.Blake2STreeConfig.NodeDepth := 0;
+    FRootConfig.Blake2STreeConfig.InnerHashSize := 0;
+    FRootConfig.Blake2STreeConfig.IsLastNode := False;
+  end;
+
+  // Create initial config for output hashes.
+  FOutputConfig := Default (TBlake2XSConfig);
+
+  FOutputConfig.Blake2SConfig := TBlake2SConfig.Create();
+  FOutputConfig.Blake2SConfig.Salt := FRootConfig.Blake2SConfig.Salt;
+  FOutputConfig.Blake2SConfig.Personalisation :=
+    FRootConfig.Blake2SConfig.Personalisation;
+
+  FOutputConfig.Blake2STreeConfig := TBlake2STreeConfig.Create();
+
+  CreateInternal(FRootConfig.Blake2SConfig, FRootConfig.Blake2STreeConfig);
+  System.SetLength(FBlake2XSBuffer, Blake2SHashSize);
+end;
+
+procedure TBlake2XS.Initialize;
+var
+  LXofSizeInBytes: UInt64;
+begin
+  LXofSizeInBytes := XOFSizeInBits shr 3;
+
+  FRootConfig.Blake2STreeConfig.NodeOffset := NodeOffsetWithXOFDigestLength
+    (LXofSizeInBytes);
+
+  FOutputConfig.Blake2STreeConfig.NodeOffset := NodeOffsetWithXOFDigestLength
+    (LXofSizeInBytes);
+
+  FBlake2XSBufferPosition := Blake2SHashSize;
+  FRootHashDigest := Nil;
+  FBlockPosition := 0;
+  FDigestPosition := 0;
+  FFinalized := False;
+  TArrayUtils.ZeroFill(FBlake2XSBuffer);
+  inherited Initialize();
+end;
+
+procedure TBlake2XS.DoOutput(const ADestination: THashLibByteArray;
+  ADestinationOffset, AOutputLength: UInt64);
+var
+  LDestinationOffset: UInt64;
+begin
+
+  if (UInt64(System.Length(ADestination)) - ADestinationOffset) < AOutputLength
+  then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateRes(@SOutputBufferTooShort);
+  end;
+
+  if ((XOFSizeInBits shr 3) <> UnknownDigestLengthInBytes) then
+  begin
+    if ((FDigestPosition + AOutputLength) > (XOFSizeInBits shr 3)) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateRes
+        (@SOutputLengthInvalid);
+    end;
+  end
+  else if ((FBlockPosition shl 5) >= UnknownMaxDigestLengthInBytes) then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateRes
+      (@SMaximumOutputLengthExceeded);
+  end;
+
+  if not FFinalized then
+  begin
+    Finish();
+    FFinalized := True;
+  end;
+
+  LDestinationOffset := ADestinationOffset;
+
+  if (FRootHashDigest = Nil) then
+  begin
+    // Get root digest
+    System.SetLength(FRootHashDigest, Blake2SHashSize);
+    TConverters.le32_copy(PCardinal(FState), 0, PByte(FRootHashDigest), 0,
+      System.Length(FRootHashDigest));
+  end;
+
+  while AOutputLength > 0 do
+  begin
+    if FBlake2XSBufferPosition >= UInt64(Blake2SHashSize) then
+    begin
+      FOutputConfig.Blake2SConfig.HashSize := ComputeStepLength();
+      FOutputConfig.Blake2STreeConfig.InnerHashSize := Blake2SHashSize;
+
+      FBlake2XSBuffer := (TBlake2S.Create(FOutputConfig.Blake2SConfig,
+        FOutputConfig.Blake2STreeConfig) as IHash).ComputeBytes(FRootHashDigest)
+        .GetBytes();
+      FOutputConfig.Blake2STreeConfig.NodeOffset :=
+        FOutputConfig.Blake2STreeConfig.NodeOffset + 1;
+      FBlake2XSBufferPosition := 0;
+    end;
+
+    ADestination[LDestinationOffset] := FBlake2XSBuffer
+      [FBlake2XSBufferPosition];
+
+    System.Inc(FBlake2XSBufferPosition);
+    System.Dec(AOutputLength);
+    System.Inc(FDigestPosition);
+    System.Inc(LDestinationOffset);
+  end;
+end;
+
+function TBlake2XS.GetResult: THashLibByteArray;
+var
+  LXofSizeInBytes: UInt64;
+begin
+  System.SetLength(Result, XOFSizeInBits shr 3);
+
+  LXofSizeInBytes := XOFSizeInBits shr 3;
+
+  System.SetLength(Result, LXofSizeInBytes);
+
+  DoOutput(Result, 0, LXofSizeInBytes);
+end;
+
+procedure TBlake2XS.TransformBytes(const AData: THashLibByteArray;
+  AIndex, ADataLength: Int32);
+begin
+  if FFinalized then
+  begin
+    raise EInvalidOperationHashLibException.CreateResFmt
+      (@SWritetoXofAfterReadError, [Name]);
+  end;
+  inherited TransformBytes(AData, AIndex, ADataLength);
+end;
+
+function TBlake2XS.TransformFinal: IHashResult;
+var
+  LBuffer: THashLibByteArray;
+begin
+  LBuffer := GetResult();
+{$IFDEF DEBUG}
+  System.Assert(UInt64(System.Length(LBuffer)) = (XOFSizeInBits shr 3));
+{$ENDIF DEBUG}
+  Initialize();
+  Result := THashResult.Create(LBuffer);
+end;
+
+{ TBlake2SMACNotBuildInAdapter }
+
+procedure TBlake2SMACNotBuildInAdapter.Clear();
+begin
+  TArrayUtils.ZeroFill(FKey);
+end;
+
+function TBlake2SMACNotBuildInAdapter.Clone(): IHash;
+var
+  LHashInstance: TBlake2SMACNotBuildInAdapter;
+begin
+  LHashInstance := TBlake2SMACNotBuildInAdapter.Create(FHash.Clone(), FKey);
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TBlake2SMACNotBuildInAdapter.Create(const ABlake2SKey, ASalt,
+  APersonalisation: THashLibByteArray; AOutputLengthInBits: Int32);
+var
+  LConfig: TBlake2SConfig;
+begin
+  LConfig := TBlake2SConfig.Create(AOutputLengthInBits shr 3);
+  LConfig.Key := ABlake2SKey;
+  LConfig.Salt := ASalt;
+  LConfig.Personalisation := APersonalisation;
+  Create(TBlake2S.Create(LConfig, Nil) as IHash, ABlake2SKey);
+end;
+
+constructor TBlake2SMACNotBuildInAdapter.Create(const AHash: IHash;
+  const ABlake2SKey: THashLibByteArray);
+begin
+  Inherited Create(AHash.HashSize, AHash.BlockSize);
+  SetKey(ABlake2SKey);
+  FHash := AHash;
+end;
+
+class function TBlake2SMACNotBuildInAdapter.CreateBlake2SMAC(const ABlake2SKey,
+  ASalt, APersonalisation: THashLibByteArray; AOutputLengthInBits: Int32)
+  : IBlake2SMAC;
+begin
+  Result := TBlake2SMACNotBuildInAdapter.Create(ABlake2SKey, ASalt,
+    APersonalisation, AOutputLengthInBits) as IBlake2SMAC;
+end;
+
+destructor TBlake2SMACNotBuildInAdapter.Destroy;
+begin
+  Clear();
+  inherited Destroy;
+end;
+
+function TBlake2SMACNotBuildInAdapter.GetKey: THashLibByteArray;
+begin
+  Result := System.Copy(FKey);
+end;
+
+function TBlake2SMACNotBuildInAdapter.GetName: String;
+begin
+  Result := Format('%s', ['TBlake2SMAC']);
+end;
+
+procedure TBlake2SMACNotBuildInAdapter.Initialize;
+begin
+  FHash.Initialize;
+end;
+
+procedure TBlake2SMACNotBuildInAdapter.SetKey(const AValue: THashLibByteArray);
+begin
+  if (AValue = Nil) then
+  begin
+    FKey := Nil;
+  end
+  else
+  begin
+    FKey := System.Copy(AValue);
+  end;
+end;
+
+procedure TBlake2SMACNotBuildInAdapter.TransformBytes
+  (const AData: THashLibByteArray; AIndex, ALength: Int32);
+begin
+{$IFDEF DEBUG}
+  System.Assert(AIndex >= 0);
+  System.Assert(ALength >= 0);
+  System.Assert(AIndex + ALength <= System.Length(AData));
+{$ENDIF}
+  FHash.TransformBytes(AData, AIndex, ALength);
+end;
+
+function TBlake2SMACNotBuildInAdapter.TransformFinal: IHashResult;
+begin
+  Result := FHash.TransformFinal();
+end;
+
 end.
 end.

+ 0 - 181
src/libraries/hashlib4pascal/HlpBlake2SConfig.pas

@@ -1,181 +0,0 @@
-unit HlpBlake2SConfig;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-  HlpIBlake2SConfig,
-  HlpHashSize,
-  HlpHashLibTypes;
-
-resourcestring
-  SInvalidHashSize =
-    'BLAKE2S HashSize must be restricted to one of the following [1 .. 32], "%d"';
-  SInvalidKeyLength = '"Key" Length Must Not Be Greater Than 32, "%d"';
-  SInvalidPersonalisationLength =
-    '"Personalisation" Length Must Be Equal To 8, "%d"';
-  SInvalidSaltLength = '"Salt" Length Must Be Equal To 8, "%d"';
-
-type
-
-  TBlake2SConfig = class sealed(TInterfacedObject, IBlake2SConfig)
-
-  strict private
-
-  var
-
-    FHashSize: Int32;
-    FPersonalisation, FSalt, FKey: THashLibByteArray;
-
-    procedure ValidateHashSize(AHashSize: Int32); inline;
-    procedure ValidateKeyLength(const AKey: THashLibByteArray); inline;
-    procedure ValidatePersonalisationLength(const APersonalisation
-      : THashLibByteArray); inline;
-    procedure ValidateSaltLength(const ASalt: THashLibByteArray); inline;
-
-    function GetPersonalisation: THashLibByteArray; inline;
-    procedure SetPersonalisation(const AValue: THashLibByteArray); inline;
-
-    function GetSalt: THashLibByteArray; inline;
-    procedure SetSalt(const AValue: THashLibByteArray); inline;
-
-    function GetKey: THashLibByteArray; inline;
-    procedure SetKey(const AValue: THashLibByteArray); inline;
-
-    function GetHashSize: Int32; inline;
-    procedure SetHashSize(AValue: Int32); inline;
-
-  public
-    constructor Create(AHashSize: THashSize = THashSize.hsHashSize256);
-      overload;
-    constructor Create(AHashSize: Int32); overload;
-    property Personalisation: THashLibByteArray read GetPersonalisation
-      write SetPersonalisation;
-    property Salt: THashLibByteArray read GetSalt write SetSalt;
-    property Key: THashLibByteArray read GetKey write SetKey;
-    property HashSize: Int32 read GetHashSize write SetHashSize;
-
-  end;
-
-implementation
-
-{ TBlake2SConfig }
-
-procedure TBlake2SConfig.ValidateHashSize(AHashSize: Int32);
-begin
-  if not((AHashSize) in [1 .. 32]) or (((AHashSize * 8) and 7) <> 0) then
-  begin
-    raise EArgumentHashLibException.CreateResFmt(@SInvalidHashSize,
-      [AHashSize]);
-  end;
-end;
-
-procedure TBlake2SConfig.ValidateKeyLength(const AKey: THashLibByteArray);
-var
-  KeyLength: Int32;
-begin
-  if (AKey <> Nil) then
-  begin
-    KeyLength := System.Length(AKey);
-    if (KeyLength > 32) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidKeyLength,
-        [KeyLength]);
-    end;
-  end;
-end;
-
-procedure TBlake2SConfig.ValidatePersonalisationLength(const APersonalisation
-  : THashLibByteArray);
-var
-  PersonalisationLength: Int32;
-begin
-  if (APersonalisation <> Nil) then
-  begin
-    PersonalisationLength := System.Length(APersonalisation);
-    if (PersonalisationLength <> 8) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateResFmt
-        (@SInvalidPersonalisationLength, [PersonalisationLength]);
-    end;
-  end;
-end;
-
-procedure TBlake2SConfig.ValidateSaltLength(const ASalt: THashLibByteArray);
-var
-  SaltLength: Int32;
-begin
-  if (ASalt <> Nil) then
-  begin
-    SaltLength := System.Length(ASalt);
-    if (SaltLength <> 8) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateResFmt
-        (@SInvalidSaltLength, [SaltLength]);
-    end;
-  end;
-end;
-
-function TBlake2SConfig.GetHashSize: Int32;
-begin
-  result := FHashSize;
-end;
-
-function TBlake2SConfig.GetKey: THashLibByteArray;
-begin
-  result := FKey;
-end;
-
-function TBlake2SConfig.GetPersonalisation: THashLibByteArray;
-begin
-  result := FPersonalisation;
-end;
-
-function TBlake2SConfig.GetSalt: THashLibByteArray;
-begin
-  result := FSalt;
-end;
-
-procedure TBlake2SConfig.SetHashSize(AValue: Int32);
-begin
-  ValidateHashSize(AValue);
-  FHashSize := AValue;
-end;
-
-procedure TBlake2SConfig.SetKey(const AValue: THashLibByteArray);
-begin
-  ValidateKeyLength(AValue);
-  FKey := AValue;
-end;
-
-procedure TBlake2SConfig.SetPersonalisation(const AValue: THashLibByteArray);
-begin
-  ValidatePersonalisationLength(AValue);
-  FPersonalisation := AValue;
-end;
-
-procedure TBlake2SConfig.SetSalt(const AValue: THashLibByteArray);
-begin
-  ValidateSaltLength(AValue);
-  FSalt := AValue;
-end;
-
-constructor TBlake2SConfig.Create(AHashSize: THashSize);
-var
-  LHashSize: Int32;
-begin
-  Inherited Create();
-  LHashSize := Int32(AHashSize);
-  ValidateHashSize(LHashSize);
-  FHashSize := LHashSize;
-end;
-
-constructor TBlake2SConfig.Create(AHashSize: Int32);
-begin
-  Inherited Create();
-  ValidateHashSize(AHashSize);
-  FHashSize := AHashSize;
-end;
-
-end.

+ 0 - 168
src/libraries/hashlib4pascal/HlpBlake2SIvBuilder.pas

@@ -1,168 +0,0 @@
-unit HlpBlake2SIvBuilder;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
-  HlpConverters,
-  HlpBlake2STreeConfig,
-  HlpIBlake2SConfig,
-  HlpIBlake2STreeConfig,
-  HlpHashLibTypes;
-
-resourcestring
-  SInvalidHashSize =
-    '"HashSize" Must Be Greater Than 0 And Less Than or Equal To 32';
-  SInvalidKeyLength = '"Key" Length Must Not Be Greater Than 32';
-  SInvalidPersonalisationLength = '"Personalisation" Length Must Be Equal To 8';
-  SInvalidSaltLength = '"Salt" Length Must Be Equal To 8';
-  STreeIncorrectInnerHashSize =
-    'Tree Inner Hash Size Must Not Be Greater Than 32';
-
-type
-  TBlake2SIvBuilder = class sealed(TObject)
-
-  strict private
-    class var
-
-      FSequentialTreeConfig: IBlake2STreeConfig;
-
-    class procedure VerifyConfigS(const AConfig: IBlake2SConfig;
-      const ATreeConfig: IBlake2STreeConfig; AIsSequential: Boolean); static;
-
-    class constructor Blake2SIvBuilder();
-
-  public
-    class function ConfigS(const AConfig: IBlake2SConfig;
-      var ATreeConfig: IBlake2STreeConfig): THashLibUInt32Array; static;
-
-  end;
-
-implementation
-
-{ TBlake2SIvBuilder }
-
-class procedure TBlake2SIvBuilder.VerifyConfigS(const AConfig: IBlake2SConfig;
-  const ATreeConfig: IBlake2STreeConfig; AIsSequential: Boolean);
-begin
-
-  // digest length
-  if ((AConfig.HashSize <= 0) or (AConfig.HashSize > 32)) then
-  begin
-    raise EArgumentOutOfRangeHashLibException.CreateRes(@SInvalidHashSize);
-  end;
-
-  // Key length
-  if (AConfig.Key <> Nil) then
-  begin
-    if (System.Length(AConfig.Key) > 32) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes(@SInvalidKeyLength);
-    end;
-  end;
-
-  // Salt length
-  if (AConfig.Salt <> Nil) then
-  begin
-    if (System.Length(AConfig.Salt) <> 8) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes(@SInvalidSaltLength);
-    end;
-  end;
-
-  // Personalisation length
-  if (AConfig.Personalisation <> Nil) then
-  begin
-    if (System.Length(AConfig.Personalisation) <> 8) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes
-        (@SInvalidPersonalisationLength);
-    end;
-  end;
-
-  // Tree InnerHashSize
-  if (ATreeConfig <> Nil) then
-  begin
-
-    if ((not AIsSequential) and ((ATreeConfig.InnerHashSize <= 0))) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.Create
-        ('treeConfig.TreeIntermediateHashSize');
-    end;
-
-    if (ATreeConfig.InnerHashSize > 32) then
-    begin
-      raise EArgumentOutOfRangeHashLibException.CreateRes
-        (@STreeIncorrectInnerHashSize);
-    end;
-  end;
-
-end;
-
-class constructor TBlake2SIvBuilder.Blake2SIvBuilder;
-begin
-  FSequentialTreeConfig := TBlake2STreeConfig.Create();
-  FSequentialTreeConfig.FanOut := 1;
-  FSequentialTreeConfig.MaxDepth := 1;
-  FSequentialTreeConfig.LeafSize := 0;
-  FSequentialTreeConfig.NodeOffset := 0;
-  FSequentialTreeConfig.NodeDepth := 0;
-  FSequentialTreeConfig.InnerHashSize := 0;
-  FSequentialTreeConfig.IsLastNode := False;
-end;
-
-class function TBlake2SIvBuilder.ConfigS(const AConfig: IBlake2SConfig;
-  var ATreeConfig: IBlake2STreeConfig): THashLibUInt32Array;
-var
-  LIsSequential: Boolean;
-  LBuffer: THashLibByteArray;
-begin
-  LIsSequential := ATreeConfig = Nil;
-  if (LIsSequential) then
-  begin
-    ATreeConfig := FSequentialTreeConfig;
-  end;
-
-  VerifyConfigS(AConfig, ATreeConfig, LIsSequential);
-
-  System.SetLength(LBuffer, 32);
-
-  LBuffer[0] := AConfig.HashSize;
-  LBuffer[1] := System.Length(AConfig.Key);
-
-  if ATreeConfig <> Nil then
-  begin
-    LBuffer[2] := ATreeConfig.FanOut;
-    LBuffer[3] := ATreeConfig.MaxDepth;
-    TConverters.ReadUInt32AsBytesLE(ATreeConfig.LeafSize, LBuffer, 4);
-    LBuffer[8] := Byte(ATreeConfig.NodeOffset);
-    LBuffer[9] := Byte(ATreeConfig.NodeOffset shr 8);
-    LBuffer[10] := Byte(ATreeConfig.NodeOffset shr 16);
-    LBuffer[11] := Byte(ATreeConfig.NodeOffset shr 24);
-    LBuffer[12] := Byte(ATreeConfig.NodeOffset shr 32);
-    LBuffer[13] := Byte(ATreeConfig.NodeOffset shr 40);
-    LBuffer[14] := ATreeConfig.NodeDepth;
-    LBuffer[15] := ATreeConfig.InnerHashSize;
-  end;
-
-  if AConfig.Salt <> Nil then
-  begin
-    System.Move(AConfig.Salt[0], LBuffer[16], 8 * System.SizeOf(Byte));
-  end;
-
-  if AConfig.Personalisation <> Nil then
-  begin
-    System.Move(AConfig.Personalisation[0], LBuffer[24],
-      8 * System.SizeOf(Byte));
-  end;
-
-  System.SetLength(Result, 8);
-  TConverters.le32_copy(PByte(LBuffer), 0, PCardinal(Result), 0,
-    System.Length(LBuffer) * System.SizeOf(Byte));
-end;
-
-end.

+ 420 - 0
src/libraries/hashlib4pascal/HlpBlake2SP.pas

@@ -0,0 +1,420 @@
+unit HlpBlake2SP;
+
+{$I HashLib.inc}
+
+interface
+
+uses
+  SysUtils,
+{$IFDEF USE_DELPHI_PPL}
+  System.Classes,
+  System.Threading,
+{$ENDIF USE_DELPHI_PPL}
+{$IFDEF USE_PASMP}
+  PasMP,
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+  MTProcs,
+{$ENDIF USE_MTPROCS}
+  HlpHash,
+  HlpIHashResult,
+  HlpBlake2S,
+  HlpIBlake2SParams,
+  HlpBlake2SParams,
+  HlpIHash,
+  HlpIHashInfo,
+  HlpArrayUtils,
+  HlpHashLibTypes;
+
+type
+  TBlake2SP = class sealed(THash, ICryptoNotBuildIn, ITransformBlock)
+  strict private
+
+  type
+    PDataContainer = ^TDataContainer;
+
+    TDataContainer = record
+      PtrData: PByte;
+      Counter: UInt64;
+    end;
+
+  const
+    BlockSizeInBytes = Int32(64);
+    OutSizeInBytes = Int32(32);
+    ParallelismDegree = Int32(8);
+
+  var
+    // had to use the classes directly for performance purposes
+    FRootHash: TBlake2S;
+    FLeafHashes: THashLibGenericArray<TBlake2S>;
+    FBuffer, FKey: THashLibByteArray;
+    FBufferLength: UInt64;
+
+    /// <summary>
+    /// <br />Blake2S defaults to setting the expected output length <br />
+    /// from the <c>HashSize</c> in the <c>TBlake2SConfig</c> class. <br />In
+    /// some cases, however, we do not want this, as the output length <br />
+    /// of these instances is given by <c>TBlake2STreeConfig.InnerSize</c>
+    /// instead. <br />
+    /// </summary>
+    function Blake2SPCreateLeafParam(const ABlake2SConfig: IBlake2SConfig;
+      const ABlake2STreeConfig: IBlake2STreeConfig): TBlake2S;
+    function Blake2SPCreateLeaf(AOffset: UInt64): TBlake2S;
+    function Blake2SPCreateRoot(): TBlake2S;
+    procedure ParallelComputation(AIdx: Int32; ADataContainer: PDataContainer);
+
+    procedure DoParallelComputation(ADataContainer: PDataContainer);
+
+    function DeepCloneBlake2SInstances(const ALeafHashes
+      : THashLibGenericArray<TBlake2S>): THashLibGenericArray<TBlake2S>;
+
+    procedure Clear();
+
+    constructor CreateInternal(AHashSize: Int32);
+
+{$IFDEF USE_PASMP}
+    procedure PasMPParallelComputationWrapper(const AJob: PPasMPJob;
+      const AThreadIndex: LongInt; const ADataContainer: Pointer;
+      const AFromIndex, AToIndex: TPasMPNativeInt); inline;
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+    procedure MTProcsParallelComputationWrapper(AIdx: PtrInt;
+      ADataContainer: Pointer; AItem: TMultiThreadProcItem); inline;
+{$ENDIF USE_MTPROCS}
+  strict protected
+    function GetName: String; override;
+
+  public
+    constructor Create(AHashSize: Int32; const AKey: THashLibByteArray);
+    destructor Destroy; override;
+    procedure Initialize; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ADataLength: Int32); override;
+    function TransformFinal: IHashResult; override;
+    function Clone(): IHash; override;
+  end;
+
+implementation
+
+{ TBlake2SP }
+
+function TBlake2SP.Blake2SPCreateLeafParam(const ABlake2SConfig: IBlake2SConfig;
+  const ABlake2STreeConfig: IBlake2STreeConfig): TBlake2S;
+begin
+  Result := TBlake2S.Create(ABlake2SConfig, ABlake2STreeConfig);
+end;
+
+function TBlake2SP.Blake2SPCreateLeaf(AOffset: UInt64): TBlake2S;
+var
+  LBlake2SConfig: IBlake2SConfig;
+  LBlake2STreeConfig: IBlake2STreeConfig;
+begin
+  LBlake2SConfig := TBlake2SConfig.Create(HashSize);
+  LBlake2SConfig.Key := FKey;
+  LBlake2STreeConfig := TBlake2STreeConfig.Create();
+  LBlake2STreeConfig.FanOut := ParallelismDegree;
+  LBlake2STreeConfig.MaxDepth := 2;
+  LBlake2STreeConfig.NodeDepth := 0;
+  LBlake2STreeConfig.LeafSize := 0;
+  LBlake2STreeConfig.NodeOffset := AOffset;
+  LBlake2STreeConfig.InnerHashSize := OutSizeInBytes;
+  if AOffset = (ParallelismDegree - 1) then
+  begin
+    LBlake2STreeConfig.IsLastNode := True;
+  end;
+  Result := Blake2SPCreateLeafParam(LBlake2SConfig, LBlake2STreeConfig);
+end;
+
+function TBlake2SP.Blake2SPCreateRoot(): TBlake2S;
+var
+  LBlake2SConfig: IBlake2SConfig;
+  LBlake2STreeConfig: IBlake2STreeConfig;
+begin
+  LBlake2SConfig := TBlake2SConfig.Create(HashSize);
+  LBlake2SConfig.Key := FKey;
+  LBlake2STreeConfig := TBlake2STreeConfig.Create();
+  LBlake2STreeConfig.FanOut := ParallelismDegree;
+  LBlake2STreeConfig.MaxDepth := 2;
+  LBlake2STreeConfig.NodeDepth := 1;
+  LBlake2STreeConfig.LeafSize := 0;
+  LBlake2STreeConfig.NodeOffset := 0;
+  LBlake2STreeConfig.InnerHashSize := OutSizeInBytes;
+  LBlake2STreeConfig.IsLastNode := True;
+  Result := TBlake2S.Create(LBlake2SConfig, LBlake2STreeConfig, False);
+end;
+
+procedure TBlake2SP.Clear;
+begin
+  TArrayUtils.ZeroFill(FKey);
+end;
+
+function TBlake2SP.DeepCloneBlake2SInstances(const ALeafHashes
+  : THashLibGenericArray<TBlake2S>): THashLibGenericArray<TBlake2S>;
+var
+  LIdx: Int32;
+begin
+  System.SetLength(Result, System.Length(ALeafHashes));
+  for LIdx := System.Low(ALeafHashes) to System.High(ALeafHashes) do
+  begin
+    Result[LIdx] := ALeafHashes[LIdx].CloneInternal();
+  end;
+end;
+
+function TBlake2SP.Clone(): IHash;
+var
+  LHashInstance: TBlake2SP;
+begin
+  LHashInstance := TBlake2SP.CreateInternal(HashSize);
+  LHashInstance.FKey := System.Copy(FKey);
+  if FRootHash <> Nil then
+  begin
+    LHashInstance.FRootHash := FRootHash.CloneInternal();
+  end;
+  LHashInstance.FLeafHashes := DeepCloneBlake2SInstances(FLeafHashes);
+  LHashInstance.FBuffer := System.Copy(FBuffer);
+  LHashInstance.FBufferLength := FBufferLength;
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TBlake2SP.CreateInternal(AHashSize: Int32);
+begin
+  Inherited Create(AHashSize, BlockSizeInBytes);
+end;
+
+constructor TBlake2SP.Create(AHashSize: Int32; const AKey: THashLibByteArray);
+var
+  LIdx: Int32;
+begin
+  Inherited Create(AHashSize, BlockSizeInBytes);
+  System.SetLength(FBuffer, ParallelismDegree * BlockSizeInBytes);
+  System.SetLength(FLeafHashes, ParallelismDegree);
+  FKey := System.Copy(AKey);
+  FRootHash := Blake2SPCreateRoot;
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    FLeafHashes[LIdx] := Blake2SPCreateLeaf(LIdx);
+  end;
+end;
+
+destructor TBlake2SP.Destroy;
+var
+  LIdx: Int32;
+begin
+  Clear();
+  FRootHash.Free;
+  FRootHash := Nil;
+  for LIdx := System.Low(FLeafHashes) to System.High(FLeafHashes) do
+  begin
+    FLeafHashes[LIdx].Free;
+    FLeafHashes[LIdx] := Nil;
+  end;
+  FLeafHashes := Nil;
+  inherited Destroy;
+end;
+
+function TBlake2SP.GetName: String;
+begin
+  Result := Format('%s_%u', [Self.ClassName, Self.HashSize * 8]);
+end;
+
+procedure TBlake2SP.Initialize;
+var
+  LIdx: Int32;
+begin
+  FRootHash.Initialize;
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    FLeafHashes[LIdx].Initialize;
+    FLeafHashes[LIdx].HashSize := OutSizeInBytes;
+  end;
+  TArrayUtils.ZeroFill(FBuffer);
+  FBufferLength := 0;
+end;
+
+procedure TBlake2SP.ParallelComputation(AIdx: Int32;
+  ADataContainer: PDataContainer);
+var
+  LLeafHashes: THashLibGenericArray<TBlake2S>;
+  LTemp: THashLibByteArray;
+  LCounter: UInt64;
+  LPtrData: PByte;
+begin
+  System.SetLength(LTemp, BlockSizeInBytes);
+  LPtrData := ADataContainer^.PtrData;
+  LCounter := ADataContainer^.Counter;
+  System.Inc(LPtrData, AIdx * BlockSizeInBytes);
+  LLeafHashes := FLeafHashes;
+  while (LCounter >= (ParallelismDegree * BlockSizeInBytes)) do
+  begin
+    System.Move(LPtrData^, LTemp[0], BlockSizeInBytes);
+    LLeafHashes[AIdx].TransformBytes(LTemp, 0, BlockSizeInBytes);
+    System.Inc(LPtrData, UInt64(ParallelismDegree * BlockSizeInBytes));
+    LCounter := LCounter - UInt64(ParallelismDegree * BlockSizeInBytes);
+  end;
+end;
+
+{$IFDEF USE_PASMP}
+
+procedure TBlake2SP.PasMPParallelComputationWrapper(const AJob: PPasMPJob;
+  const AThreadIndex: LongInt; const ADataContainer: Pointer;
+  const AFromIndex, AToIndex: TPasMPNativeInt);
+begin
+  ParallelComputation(AFromIndex, ADataContainer);
+end;
+{$ENDIF}
+{$IFDEF USE_MTPROCS}
+
+procedure TBlake2SP.MTProcsParallelComputationWrapper(AIdx: PtrInt;
+  ADataContainer: Pointer; AItem: TMultiThreadProcItem);
+begin
+  ParallelComputation(AIdx, ADataContainer);
+end;
+{$ENDIF}
+{$IF DEFINED(USE_DELPHI_PPL)}
+
+procedure TBlake2SP.DoParallelComputation(ADataContainer: PDataContainer);
+
+  function CreateTask(AIdx: Int32; ADataContainer: PDataContainer): ITask;
+  begin
+    Result := TTask.Create(
+      procedure()
+      begin
+        ParallelComputation(AIdx, ADataContainer);
+      end);
+  end;
+
+var
+  LArrayTasks: array of ITask;
+  LIdx: Int32;
+begin
+  System.SetLength(LArrayTasks, ParallelismDegree);
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    LArrayTasks[LIdx] := CreateTask(LIdx, ADataContainer);
+    LArrayTasks[LIdx].Start;
+  end;
+  TTask.WaitForAll(LArrayTasks);
+end;
+
+{$ELSEIF DEFINED(USE_PASMP) OR DEFINED(USE_MTPROCS)}
+
+procedure TBlake2SP.DoParallelComputation(ADataContainer: PDataContainer);
+begin
+{$IF DEFINED(USE_PASMP)}
+  TPasMP.CreateGlobalInstance;
+  GlobalPasMP.Invoke(GlobalPasMP.ParallelFor(ADataContainer, 0,
+    ParallelismDegree - 1, PasMPParallelComputationWrapper));
+{$ELSEIF DEFINED(USE_MTPROCS)}
+  ProcThreadPool.DoParallel(MTProcsParallelComputationWrapper, 0,
+    ParallelismDegree - 1, ADataContainer);
+{$ELSE}
+{$MESSAGE ERROR 'Unsupported Threading Library.'}
+{$IFEND USE_PASMP}
+end;
+
+{$ELSE}
+
+procedure TBlake2SP.DoParallelComputation(ADataContainer: PDataContainer);
+var
+  LIdx: Int32;
+begin
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    ParallelComputation(LIdx, ADataContainer);
+  end;
+end;
+{$IFEND USE_DELPHI_PPL}
+
+procedure TBlake2SP.TransformBytes(const AData: THashLibByteArray;
+AIndex, ADataLength: Int32);
+var
+  LLeft, LFill, LDataLength: UInt64;
+  LPtrData: PByte;
+  LIdx: Int32;
+  LLeafHashes: THashLibGenericArray<TBlake2S>;
+  LPtrDataContainer: PDataContainer;
+begin
+  LLeafHashes := FLeafHashes;
+  LDataLength := UInt64(ADataLength);
+  LPtrData := PByte(AData) + AIndex;
+  LLeft := FBufferLength;
+  LFill := UInt64(System.Length(FBuffer)) - LLeft;
+
+  if (LLeft > 0) and (LDataLength >= LFill) then
+  begin
+    System.Move(LPtrData^, FBuffer[LLeft], LFill);
+
+    for LIdx := 0 to System.Pred(ParallelismDegree) do
+    begin
+      LLeafHashes[LIdx].TransformBytes(FBuffer, LIdx * BlockSizeInBytes,
+        BlockSizeInBytes);
+    end;
+
+    System.Inc(LPtrData, LFill);
+    LDataLength := LDataLength - LFill;
+    LLeft := 0;
+  end;
+
+  LPtrDataContainer := New(PDataContainer);
+  try
+    LPtrDataContainer^.PtrData := LPtrData;
+    LPtrDataContainer^.Counter := LDataLength;
+    DoParallelComputation(LPtrDataContainer);
+  finally
+    Dispose(LPtrDataContainer);
+  end;
+
+  System.Inc(LPtrData, LDataLength - (LDataLength mod UInt64(ParallelismDegree *
+    BlockSizeInBytes)));
+  LDataLength := LDataLength mod UInt64(ParallelismDegree * BlockSizeInBytes);
+
+  if (LDataLength > 0) then
+  begin
+    System.Move(LPtrData^, FBuffer[LLeft], LDataLength);
+  end;
+
+  FBufferLength := UInt32(LLeft) + UInt32(LDataLength);
+end;
+
+function TBlake2SP.TransformFinal: IHashResult;
+var
+  LHash: THashLibMatrixByteArray;
+  LIdx: Int32;
+  LLeft: UInt64;
+  LLeafHashes: THashLibGenericArray<TBlake2S>;
+  LRootHash: TBlake2S;
+begin
+  LLeafHashes := FLeafHashes;
+  LRootHash := FRootHash;
+  System.SetLength(LHash, ParallelismDegree);
+  for LIdx := System.Low(LHash) to System.High(LHash) do
+  begin
+    System.SetLength(LHash[LIdx], OutSizeInBytes);
+  end;
+
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    if (FBufferLength > (LIdx * BlockSizeInBytes)) then
+    begin
+      LLeft := FBufferLength - UInt64(LIdx * BlockSizeInBytes);
+      if (LLeft > BlockSizeInBytes) then
+      begin
+        LLeft := BlockSizeInBytes;
+      end;
+      LLeafHashes[LIdx].TransformBytes(FBuffer, LIdx * BlockSizeInBytes,
+        Int32(LLeft));
+    end;
+
+    LHash[LIdx] := LLeafHashes[LIdx].TransformFinal().GetBytes();
+  end;
+
+  for LIdx := 0 to System.Pred(ParallelismDegree) do
+  begin
+    LRootHash.TransformBytes(LHash[LIdx], 0, OutSizeInBytes);
+  end;
+  Result := LRootHash.TransformFinal();
+  Initialize();
+end;
+
+end.

+ 579 - 0
src/libraries/hashlib4pascal/HlpBlake2SParams.pas

@@ -0,0 +1,579 @@
+unit HlpBlake2SParams;
+
+{$I HashLib.inc}
+
+interface
+
+uses
+  HlpIBlake2SParams,
+  HlpHashSize,
+  HlpArrayUtils,
+  HlpHashLibTypes,
+  HlpConverters;
+
+resourcestring
+  SInvalidHashSize =
+    'BLAKE2S HashSize must be restricted to one of the following [1 .. 32], "%d"';
+  SInvalidKeyLength = '"Key" Length Must Not Be Greater Than 32, "%d"';
+  SInvalidPersonalisationLength =
+    '"Personalisation" Length Must Be Equal To 8, "%d"';
+  SInvalidSaltLength = '"Salt" Length Must Be Equal To 8, "%d"';
+
+  SInvalidFanOutParameter =
+    'FanOut Value Should be Between [0 .. 255] for Blake2S';
+  SInvalidMaxDepthParameter =
+    'MaxDepth Value Should be Between [1 .. 255] for Blake2S';
+  SInvalidNodeDepthParameter =
+    'NodeDepth Value Should be Between [0 .. 255] for Blake2S';
+  SInvalidInnerHashSizeParameter =
+    'InnerHashSize Value Should be Between [0 .. 32] for Blake2S';
+  SInvalidNodeOffsetParameter =
+    'NodeOffset Value Should be Between [0 .. (2^48-1)] for Blake2S';
+
+  STreeIncorrectInnerHashSize =
+    'Tree Inner Hash Size Must Not Be Greater Than 32, "%d"';
+
+type
+  TBlake2SConfig = class sealed(TInterfacedObject, IBlake2SConfig)
+
+  strict private
+
+  var
+
+    FHashSize: Int32;
+    FPersonalisation, FSalt, FKey: THashLibByteArray;
+
+    class function GetDefaultConfig: IBlake2SConfig; static;
+
+    procedure ValidateHashSize(AHashSize: Int32); inline;
+    procedure ValidateKeyLength(const AKey: THashLibByteArray); inline;
+    procedure ValidatePersonalisationLength(const APersonalisation
+      : THashLibByteArray); inline;
+    procedure ValidateSaltLength(const ASalt: THashLibByteArray); inline;
+
+    function GetPersonalisation: THashLibByteArray; inline;
+    procedure SetPersonalisation(const AValue: THashLibByteArray); inline;
+
+    function GetSalt: THashLibByteArray; inline;
+    procedure SetSalt(const AValue: THashLibByteArray); inline;
+
+    function GetKey: THashLibByteArray; inline;
+    procedure SetKey(const AValue: THashLibByteArray); inline;
+
+    function GetHashSize: Int32; inline;
+    procedure SetHashSize(AValue: Int32); inline;
+
+  public
+    constructor Create(AHashSize: THashSize = THashSize.hsHashSize256);
+      overload;
+    constructor Create(AHashSize: Int32); overload;
+    destructor Destroy; override;
+    property Personalisation: THashLibByteArray read GetPersonalisation
+      write SetPersonalisation;
+    property Salt: THashLibByteArray read GetSalt write SetSalt;
+    property Key: THashLibByteArray read GetKey write SetKey;
+    property HashSize: Int32 read GetHashSize write SetHashSize;
+
+    class property DefaultConfig: IBlake2SConfig read GetDefaultConfig;
+
+    function Clone(): IBlake2SConfig;
+
+    procedure Clear();
+
+  end;
+
+type
+  TBlake2STreeConfig = class sealed(TInterfacedObject, IBlake2STreeConfig)
+
+  strict private
+  var
+    FFanOut, FMaxDepth, FNodeDepth, FInnerHashSize: Byte;
+    FLeafSize: UInt32;
+    FNodeOffset: UInt64;
+    FIsLastNode: Boolean;
+
+    procedure ValidateFanOut(AFanOut: Byte); inline;
+    procedure ValidateInnerHashSize(AInnerHashSize: Byte); inline;
+    procedure ValidateMaxDepth(AMaxDepth: Byte); inline;
+    procedure ValidateNodeDepth(ANodeDepth: Byte); inline;
+    procedure ValidateNodeOffset(ANodeOffset: UInt64); inline;
+
+    function GetFanOut: Byte; inline;
+    procedure SetFanOut(AValue: Byte); inline;
+
+    function GetMaxDepth: Byte; inline;
+    procedure SetMaxDepth(AValue: Byte); inline;
+
+    function GetNodeDepth: Byte; inline;
+    procedure SetNodeDepth(AValue: Byte); inline;
+
+    function GetInnerHashSize: Byte; inline;
+    procedure SetInnerHashSize(AValue: Byte); inline;
+
+    function GetLeafSize: UInt32; inline;
+    procedure SetLeafSize(AValue: UInt32); inline;
+
+    function GetNodeOffset: UInt64; inline;
+    procedure SetNodeOffset(AValue: UInt64); inline;
+
+    function GetIsLastNode: Boolean; inline;
+    procedure SetIsLastNode(AValue: Boolean); inline;
+
+    class function GetSequentialTreeConfig: IBlake2STreeConfig; static;
+
+  public
+    constructor Create();
+
+    property FanOut: Byte read GetFanOut write SetFanOut;
+
+    property MaxDepth: Byte read GetMaxDepth write SetMaxDepth;
+
+    property NodeDepth: Byte read GetNodeDepth write SetNodeDepth;
+
+    property InnerHashSize: Byte read GetInnerHashSize write SetInnerHashSize;
+
+    property LeafSize: UInt32 read GetLeafSize write SetLeafSize;
+
+    property NodeOffset: UInt64 read GetNodeOffset write SetNodeOffset;
+
+    property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
+
+    function Clone(): IBlake2STreeConfig;
+
+    class property SequentialTreeConfig: IBlake2STreeConfig
+      read GetSequentialTreeConfig;
+
+  end;
+
+type
+  TBlake2SIvBuilder = class sealed(TObject)
+
+  strict private
+
+    class procedure VerifyConfigS(const AConfig: IBlake2SConfig;
+      const ATreeConfig: IBlake2STreeConfig; AIsSequential: Boolean); static;
+
+  public
+    class function ConfigS(const AConfig: IBlake2SConfig;
+      var ATreeConfig: IBlake2STreeConfig): THashLibUInt32Array; static;
+
+  end;
+
+implementation
+
+{ TBlake2SConfig }
+
+class function TBlake2SConfig.GetDefaultConfig: IBlake2SConfig;
+begin
+  Result := TBlake2SConfig.Create();
+end;
+
+procedure TBlake2SConfig.ValidateHashSize(AHashSize: Int32);
+begin
+  if not((AHashSize) in [1 .. 32]) or (((AHashSize * 8) and 7) <> 0) then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidHashSize,
+      [AHashSize]);
+  end;
+end;
+
+procedure TBlake2SConfig.ValidateKeyLength(const AKey: THashLibByteArray);
+var
+  KeyLength: Int32;
+begin
+  if (AKey <> Nil) then
+  begin
+    KeyLength := System.Length(AKey);
+    if (KeyLength > 32) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidKeyLength,
+        [KeyLength]);
+    end;
+  end;
+end;
+
+procedure TBlake2SConfig.ValidatePersonalisationLength(const APersonalisation
+  : THashLibByteArray);
+var
+  PersonalisationLength: Int32;
+begin
+  if (APersonalisation <> Nil) then
+  begin
+    PersonalisationLength := System.Length(APersonalisation);
+    if (PersonalisationLength <> 8) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidPersonalisationLength, [PersonalisationLength]);
+    end;
+  end;
+end;
+
+procedure TBlake2SConfig.ValidateSaltLength(const ASalt: THashLibByteArray);
+var
+  SaltLength: Int32;
+begin
+  if (ASalt <> Nil) then
+  begin
+    SaltLength := System.Length(ASalt);
+    if (SaltLength <> 8) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidSaltLength, [SaltLength]);
+    end;
+  end;
+end;
+
+function TBlake2SConfig.GetHashSize: Int32;
+begin
+  Result := FHashSize;
+end;
+
+function TBlake2SConfig.GetKey: THashLibByteArray;
+begin
+  Result := FKey;
+end;
+
+function TBlake2SConfig.GetPersonalisation: THashLibByteArray;
+begin
+  Result := FPersonalisation;
+end;
+
+function TBlake2SConfig.GetSalt: THashLibByteArray;
+begin
+  Result := FSalt;
+end;
+
+procedure TBlake2SConfig.SetHashSize(AValue: Int32);
+begin
+  ValidateHashSize(AValue);
+  FHashSize := AValue;
+end;
+
+procedure TBlake2SConfig.SetKey(const AValue: THashLibByteArray);
+begin
+  ValidateKeyLength(AValue);
+  FKey := System.Copy(AValue);
+end;
+
+procedure TBlake2SConfig.SetPersonalisation(const AValue: THashLibByteArray);
+begin
+  ValidatePersonalisationLength(AValue);
+  FPersonalisation := System.Copy(AValue);
+end;
+
+procedure TBlake2SConfig.SetSalt(const AValue: THashLibByteArray);
+begin
+  ValidateSaltLength(AValue);
+  FSalt := System.Copy(AValue);
+end;
+
+constructor TBlake2SConfig.Create(AHashSize: THashSize);
+var
+  LHashSize: Int32;
+begin
+  Inherited Create();
+  LHashSize := Int32(AHashSize);
+  ValidateHashSize(LHashSize);
+  FHashSize := LHashSize;
+end;
+
+constructor TBlake2SConfig.Create(AHashSize: Int32);
+begin
+  Inherited Create();
+  ValidateHashSize(AHashSize);
+  FHashSize := AHashSize;
+end;
+
+procedure TBlake2SConfig.Clear;
+begin
+  TArrayUtils.ZeroFill(FKey);
+end;
+
+destructor TBlake2SConfig.Destroy;
+begin
+  Clear();
+  inherited Destroy;
+end;
+
+function TBlake2SConfig.Clone(): IBlake2SConfig;
+begin
+  Result := TBlake2SConfig.Create(FHashSize);
+  Result.Key := System.Copy(FKey);
+  Result.Personalisation := System.Copy(FPersonalisation);
+  Result.Salt := System.Copy(FSalt);
+end;
+
+{ TBlake2STreeConfig }
+
+procedure TBlake2STreeConfig.ValidateFanOut(AFanOut: Byte);
+begin
+  if not(AFanOut in [0 .. 255]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes(@SInvalidFanOutParameter);
+  end;
+end;
+
+procedure TBlake2STreeConfig.ValidateInnerHashSize(AInnerHashSize: Byte);
+begin
+  if not(AInnerHashSize in [0 .. 32]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidInnerHashSizeParameter);
+  end;
+end;
+
+procedure TBlake2STreeConfig.ValidateMaxDepth(AMaxDepth: Byte);
+begin
+  if not(AMaxDepth in [1 .. 255]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidMaxDepthParameter);
+  end;
+end;
+
+procedure TBlake2STreeConfig.ValidateNodeDepth(ANodeDepth: Byte);
+begin
+  if not(ANodeDepth in [0 .. 255]) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidNodeDepthParameter);
+  end;
+end;
+
+procedure TBlake2STreeConfig.ValidateNodeOffset(ANodeOffset: UInt64);
+begin
+  if ANodeOffset > UInt64((UInt64(1) shl 48) - 1) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes
+      (@SInvalidNodeOffsetParameter);
+  end;
+end;
+
+function TBlake2STreeConfig.GetFanOut: Byte;
+begin
+  Result := FFanOut;
+end;
+
+function TBlake2STreeConfig.GetInnerHashSize: Byte;
+begin
+  Result := FInnerHashSize;
+end;
+
+function TBlake2STreeConfig.GetIsLastNode: Boolean;
+begin
+  Result := FIsLastNode;
+end;
+
+function TBlake2STreeConfig.GetLeafSize: UInt32;
+begin
+  Result := FLeafSize;
+end;
+
+function TBlake2STreeConfig.GetMaxDepth: Byte;
+begin
+  Result := FMaxDepth;
+end;
+
+function TBlake2STreeConfig.GetNodeDepth: Byte;
+begin
+  Result := FNodeDepth;
+end;
+
+function TBlake2STreeConfig.GetNodeOffset: UInt64;
+begin
+  Result := FNodeOffset;
+end;
+
+procedure TBlake2STreeConfig.SetFanOut(AValue: Byte);
+begin
+  ValidateFanOut(AValue);
+  FFanOut := AValue;
+end;
+
+procedure TBlake2STreeConfig.SetInnerHashSize(AValue: Byte);
+begin
+  ValidateInnerHashSize(AValue);
+  FInnerHashSize := AValue;
+end;
+
+procedure TBlake2STreeConfig.SetIsLastNode(AValue: Boolean);
+begin
+  FIsLastNode := AValue;
+end;
+
+procedure TBlake2STreeConfig.SetLeafSize(AValue: UInt32);
+begin
+  FLeafSize := AValue;
+end;
+
+procedure TBlake2STreeConfig.SetMaxDepth(AValue: Byte);
+begin
+  ValidateMaxDepth(AValue);
+  FMaxDepth := AValue;
+end;
+
+procedure TBlake2STreeConfig.SetNodeDepth(AValue: Byte);
+begin
+  ValidateNodeDepth(AValue);
+  FNodeDepth := AValue;
+end;
+
+procedure TBlake2STreeConfig.SetNodeOffset(AValue: UInt64);
+begin
+  ValidateNodeOffset(AValue);
+  FNodeOffset := AValue;
+end;
+
+constructor TBlake2STreeConfig.Create;
+begin
+  Inherited Create();
+  FFanOut := 0;
+  FMaxDepth := 0;
+  FLeafSize := 32;
+  FNodeOffset := 0;
+  FNodeDepth := 0;
+  FInnerHashSize := 32;
+  FIsLastNode := False;
+end;
+
+function TBlake2STreeConfig.Clone(): IBlake2STreeConfig;
+var
+  LResult: TBlake2STreeConfig;
+begin
+  LResult := TBlake2STreeConfig.Create();
+  LResult.FFanOut := FFanOut;
+  LResult.FInnerHashSize := FInnerHashSize;
+  LResult.FMaxDepth := FMaxDepth;
+  LResult.FNodeDepth := FNodeDepth;
+  LResult.FLeafSize := FLeafSize;
+  LResult.FNodeOffset := FNodeOffset;
+  LResult.FIsLastNode := FIsLastNode;
+  Result := LResult as IBlake2STreeConfig;
+end;
+
+class function TBlake2STreeConfig.GetSequentialTreeConfig: IBlake2STreeConfig;
+begin
+  Result := TBlake2STreeConfig.Create();
+  Result.FanOut := 1;
+  Result.MaxDepth := 1;
+  Result.LeafSize := 0;
+  Result.NodeOffset := 0;
+  Result.NodeDepth := 0;
+  Result.InnerHashSize := 0;
+  Result.IsLastNode := False;
+end;
+
+{ TBlake2SIvBuilder }
+
+class procedure TBlake2SIvBuilder.VerifyConfigS(const AConfig: IBlake2SConfig;
+  const ATreeConfig: IBlake2STreeConfig; AIsSequential: Boolean);
+begin
+
+  // digest length
+  if ((AConfig.HashSize <= 0) or (AConfig.HashSize > 32)) then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidHashSize,
+      [AConfig.HashSize]);
+  end;
+
+  // Key length
+  if (AConfig.Key <> Nil) then
+  begin
+    if (System.Length(AConfig.Key) > 32) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt(@SInvalidKeyLength,
+        [System.Length(AConfig.Key)]);
+    end;
+  end;
+
+  // Personalisation length
+  if (AConfig.Personalisation <> Nil) then
+  begin
+    if (System.Length(AConfig.Personalisation) <> 8) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidPersonalisationLength,
+        [System.Length(AConfig.Personalisation)]);
+    end;
+  end;
+
+  // Salt length
+  if (AConfig.Salt <> Nil) then
+  begin
+    if (System.Length(AConfig.Salt) <> 8) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@SInvalidSaltLength, [System.Length(AConfig.Salt)]);
+    end;
+  end;
+
+  // Tree InnerHashSize
+  if (ATreeConfig <> Nil) then
+  begin
+
+    if ((AIsSequential) and ((ATreeConfig.InnerHashSize <> 0))) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.Create
+        ('treeConfig.TreeIntermediateHashSize');
+    end;
+
+    if (ATreeConfig.InnerHashSize > 32) then
+    begin
+      raise EArgumentOutOfRangeHashLibException.CreateResFmt
+        (@STreeIncorrectInnerHashSize, [ATreeConfig.InnerHashSize]);
+    end;
+  end;
+
+end;
+
+class function TBlake2SIvBuilder.ConfigS(const AConfig: IBlake2SConfig;
+  var ATreeConfig: IBlake2STreeConfig): THashLibUInt32Array;
+var
+  LIsSequential: Boolean;
+  LBuffer: THashLibByteArray;
+begin
+  LIsSequential := ATreeConfig = Nil;
+  if (LIsSequential) then
+  begin
+    ATreeConfig := TBlake2STreeConfig.SequentialTreeConfig;
+  end;
+
+  VerifyConfigS(AConfig, ATreeConfig, LIsSequential);
+
+  System.SetLength(LBuffer, 32);
+
+  LBuffer[0] := AConfig.HashSize;
+  LBuffer[1] := System.Length(AConfig.Key);
+
+  if ATreeConfig <> Nil then
+  begin
+    LBuffer[2] := ATreeConfig.FanOut;
+    LBuffer[3] := ATreeConfig.MaxDepth;
+    TConverters.ReadUInt32AsBytesLE(ATreeConfig.LeafSize, LBuffer, 4);
+    LBuffer[8] := Byte(ATreeConfig.NodeOffset);
+    LBuffer[9] := Byte(ATreeConfig.NodeOffset shr 8);
+    LBuffer[10] := Byte(ATreeConfig.NodeOffset shr 16);
+    LBuffer[11] := Byte(ATreeConfig.NodeOffset shr 24);
+    LBuffer[12] := Byte(ATreeConfig.NodeOffset shr 32);
+    LBuffer[13] := Byte(ATreeConfig.NodeOffset shr 40);
+    LBuffer[14] := ATreeConfig.NodeDepth;
+    LBuffer[15] := ATreeConfig.InnerHashSize;
+  end;
+
+  if AConfig.Salt <> Nil then
+  begin
+    System.Move(AConfig.Salt[0], LBuffer[16], 8 * System.SizeOf(Byte));
+  end;
+
+  if AConfig.Personalisation <> Nil then
+  begin
+    System.Move(AConfig.Personalisation[0], LBuffer[24],
+      8 * System.SizeOf(Byte));
+  end;
+
+  System.SetLength(Result, 8);
+  TConverters.le32_copy(PByte(LBuffer), 0, PCardinal(Result), 0,
+    System.Length(LBuffer) * System.SizeOf(Byte));
+end;
+
+end.

+ 0 - 210
src/libraries/hashlib4pascal/HlpBlake2STreeConfig.pas

@@ -1,210 +0,0 @@
-unit HlpBlake2STreeConfig;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-  HlpIBlake2STreeConfig,
-  HlpHashLibTypes;
-
-resourcestring
-  SInvalidFanOutParameter =
-    'FanOut Value Should be Between [0 .. 255] for Blake2S';
-  SInvalidMaxDepthParameter =
-    'FanOut Value Should be Between [1 .. 255] for Blake2S';
-  SInvalidNodeDepthParameter =
-    'NodeDepth Value Should be Between [0 .. 255] for Blake2S';
-  SInvalidInnerHashSizeParameter =
-    'InnerHashSize Value Should be Between [0 .. 32] for Blake2S';
-  SInvalidNodeOffsetParameter =
-    'NodeOffset Value Should be Between [0 .. (2^48-1)] for Blake2S';
-
-type
-
-  TBlake2STreeConfig = class sealed(TInterfacedObject, IBlake2STreeConfig)
-
-  strict private
-  var
-    FFanOut, FMaxDepth, FNodeDepth, FInnerHashSize: Byte;
-    FLeafSize: UInt32;
-    FNodeOffset: UInt64;
-    FIsLastNode: Boolean;
-
-    procedure ValidateFanOut(AFanOut: Byte); inline;
-    procedure ValidateInnerHashSize(AInnerHashSize: Byte); inline;
-    procedure ValidateMaxDepth(AMaxDepth: Byte); inline;
-    procedure ValidateNodeDepth(ANodeDepth: Byte); inline;
-    procedure ValidateNodeOffset(ANodeOffset: UInt64); inline;
-
-    function GetFanOut: Byte; inline;
-    procedure SetFanOut(AValue: Byte); inline;
-
-    function GetMaxDepth: Byte; inline;
-    procedure SetMaxDepth(AValue: Byte); inline;
-
-    function GetNodeDepth: Byte; inline;
-    procedure SetNodeDepth(AValue: Byte); inline;
-
-    function GetInnerHashSize: Byte; inline;
-    procedure SetInnerHashSize(AValue: Byte); inline;
-
-    function GetLeafSize: UInt32; inline;
-    procedure SetLeafSize(AValue: UInt32); inline;
-
-    function GetNodeOffset: UInt64; inline;
-    procedure SetNodeOffset(AValue: UInt64); inline;
-
-    function GetIsLastNode: Boolean; inline;
-    procedure SetIsLastNode(AValue: Boolean); inline;
-
-  public
-    constructor Create();
-
-    property FanOut: Byte read GetFanOut write SetFanOut;
-
-    property MaxDepth: Byte read GetMaxDepth write SetMaxDepth;
-
-    property NodeDepth: Byte read GetNodeDepth write SetNodeDepth;
-
-    property InnerHashSize: Byte read GetInnerHashSize write SetInnerHashSize;
-
-    property LeafSize: UInt32 read GetLeafSize write SetLeafSize;
-
-    property NodeOffset: UInt64 read GetNodeOffset write SetNodeOffset;
-
-    property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
-
-  end;
-
-implementation
-
-{ TBlake2STreeConfig }
-
-procedure TBlake2STreeConfig.ValidateFanOut(AFanOut: Byte);
-begin
-  if not(AFanOut in [0 .. 255]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes(@SInvalidFanOutParameter);
-  end;
-end;
-
-procedure TBlake2STreeConfig.ValidateInnerHashSize(AInnerHashSize: Byte);
-begin
-  if not(AInnerHashSize in [0 .. 32]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes
-      (@SInvalidInnerHashSizeParameter);
-  end;
-end;
-
-procedure TBlake2STreeConfig.ValidateMaxDepth(AMaxDepth: Byte);
-begin
-  if not(AMaxDepth in [1 .. 255]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes
-      (@SInvalidMaxDepthParameter);
-  end;
-end;
-
-procedure TBlake2STreeConfig.ValidateNodeDepth(ANodeDepth: Byte);
-begin
-  if not(ANodeDepth in [0 .. 255]) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes
-      (@SInvalidNodeDepthParameter);
-  end;
-end;
-
-procedure TBlake2STreeConfig.ValidateNodeOffset(ANodeOffset: UInt64);
-begin
-  if ANodeOffset > UInt64((UInt64(1) shl 48) - 1) then
-  begin
-    raise EArgumentInvalidHashLibException.CreateRes
-      (@SInvalidNodeOffsetParameter);
-  end;
-end;
-
-function TBlake2STreeConfig.GetFanOut: Byte;
-begin
-  result := FFanOut;
-end;
-
-function TBlake2STreeConfig.GetInnerHashSize: Byte;
-begin
-  result := FInnerHashSize;
-end;
-
-function TBlake2STreeConfig.GetIsLastNode: Boolean;
-begin
-  result := FIsLastNode;
-end;
-
-function TBlake2STreeConfig.GetLeafSize: UInt32;
-begin
-  result := FLeafSize;
-end;
-
-function TBlake2STreeConfig.GetMaxDepth: Byte;
-begin
-  result := FMaxDepth;
-end;
-
-function TBlake2STreeConfig.GetNodeDepth: Byte;
-begin
-  result := FNodeDepth;
-end;
-
-function TBlake2STreeConfig.GetNodeOffset: UInt64;
-begin
-  result := FNodeOffset;
-end;
-
-procedure TBlake2STreeConfig.SetFanOut(AValue: Byte);
-begin
-  ValidateFanOut(AValue);
-  FFanOut := AValue;
-end;
-
-procedure TBlake2STreeConfig.SetInnerHashSize(AValue: Byte);
-begin
-  ValidateInnerHashSize(AValue);
-  FInnerHashSize := AValue;
-end;
-
-procedure TBlake2STreeConfig.SetIsLastNode(AValue: Boolean);
-begin
-  FIsLastNode := AValue;
-end;
-
-procedure TBlake2STreeConfig.SetLeafSize(AValue: UInt32);
-begin
-  FLeafSize := AValue;
-end;
-
-procedure TBlake2STreeConfig.SetMaxDepth(AValue: Byte);
-begin
-  ValidateMaxDepth(AValue);
-  FMaxDepth := AValue;
-end;
-
-procedure TBlake2STreeConfig.SetNodeDepth(AValue: Byte);
-begin
-  ValidateNodeDepth(AValue);
-  FNodeDepth := AValue;
-end;
-
-procedure TBlake2STreeConfig.SetNodeOffset(AValue: UInt64);
-begin
-  ValidateNodeOffset(AValue);
-  FNodeOffset := AValue;
-end;
-
-constructor TBlake2STreeConfig.Create;
-begin
-  Inherited Create();
-  ValidateInnerHashSize(32);
-  FInnerHashSize := 32;
-end;
-
-end.

+ 111 - 37
src/libraries/hashlib4pascal/HlpCRC.pas

@@ -190,6 +190,16 @@ type
     /// </summary>
     /// </summary>
     CRC8_WCDMA,
     CRC8_WCDMA,
 
 
+    /// <summary>
+    /// CRC standard named "CRC8_MIFAREMAD".
+    /// </summary>
+    CRC8_MIFAREMAD,
+
+    /// <summary>
+    /// CRC standard named "CRC8_NRSC5".
+    /// </summary>
+    CRC8_NRSC5,
+
     /// <summary>
     /// <summary>
     /// CRC standard named "CRC10".
     /// CRC standard named "CRC10".
     /// </summary>
     /// </summary>
@@ -405,6 +415,11 @@ type
     /// </summary>
     /// </summary>
     XMODEM,
     XMODEM,
 
 
+    /// <summary>
+    /// CRC standard named "CRC16_NRSC5".
+    /// </summary>
+    CRC16_NRSC5,
+
     /// <summary>
     /// <summary>
     /// CRC standard named "CRC17_CANFD".
     /// CRC standard named "CRC17_CANFD".
     /// </summary>
     /// </summary>
@@ -450,6 +465,11 @@ type
     /// </summary>
     /// </summary>
     CRC24_LTEB,
     CRC24_LTEB,
 
 
+    /// <summary>
+    /// CRC standard named "CRC24_OS9".
+    /// </summary>
+    CRC24_OS9,
+
     /// <summary>
     /// <summary>
     /// CRC standard named "CRC30_CDMA".
     /// CRC standard named "CRC30_CDMA".
     /// </summary>
     /// </summary>
@@ -510,6 +530,11 @@ type
     /// </summary>
     /// </summary>
     XFER,
     XFER,
 
 
+    /// <summary>
+    /// CRC standard named "CRC32_CDROMEDC".
+    /// </summary>
+    CRC32_CDROMEDC,
+
     /// <summary>
     /// <summary>
     /// CRC standard named "CRC40_GSM".
     /// CRC standard named "CRC40_GSM".
     /// </summary>
     /// </summary>
@@ -533,7 +558,17 @@ type
     /// <summary>
     /// <summary>
     /// CRC standard named "CRC64_XZ".
     /// CRC standard named "CRC64_XZ".
     /// </summary>
     /// </summary>
-    CRC64_XZ);
+    CRC64_XZ,
+
+    /// <summary>
+    /// CRC standard named "CRC64_1B".
+    /// </summary>
+    CRC64_1B,
+
+    /// <summary>
+    /// CRC standard named "CRC64_Jones".
+    /// </summary>
+    CRC64_Jones);
 
 
 {$ENDREGION}
 {$ENDREGION}
 
 
@@ -704,16 +739,18 @@ procedure TCRC.CalculateCRCbyTable(AData: PByte; ADataLength, AIndex: Int32);
 var
 var
   LLength, LIndex: Int32;
   LLength, LIndex: Int32;
   LTemp: UInt64;
   LTemp: UInt64;
+  LCRCTable: THashLibUInt64Array;
 begin
 begin
   LLength := ADataLength;
   LLength := ADataLength;
   LIndex := AIndex;
   LIndex := AIndex;
   LTemp := FHash;
   LTemp := FHash;
+  LCRCTable := FCRCTable;
 
 
   if (IsInputReflected) then
   if (IsInputReflected) then
   begin
   begin
     while LLength > 0 do
     while LLength > 0 do
     begin
     begin
-      LTemp := (LTemp shr 8) xor FCRCTable[Byte(LTemp xor AData[LIndex])];
+      LTemp := (LTemp shr 8) xor LCRCTable[Byte(LTemp xor AData[LIndex])];
       System.Inc(LIndex);
       System.Inc(LIndex);
       System.Dec(LLength);
       System.Dec(LLength);
     end;
     end;
@@ -722,7 +759,7 @@ begin
   begin
   begin
     while LLength > 0 do
     while LLength > 0 do
     begin
     begin
-      LTemp := (LTemp shl 8) xor FCRCTable
+      LTemp := (LTemp shl 8) xor LCRCTable
         [Byte((LTemp shr (Width - 8)) xor AData[LIndex])];
         [Byte((LTemp shr (Width - 8)) xor AData[LIndex])];
       System.Inc(LIndex);
       System.Inc(LIndex);
       System.Dec(LLength);
       System.Dec(LLength);
@@ -735,7 +772,7 @@ end;
 procedure TCRC.CalculateCRCdirect(AData: PByte; ADataLength, AIndex: Int32);
 procedure TCRC.CalculateCRCdirect(AData: PByte; ADataLength, AIndex: Int32);
 var
 var
   LLength, LIdx: Int32;
   LLength, LIdx: Int32;
-  LTemp, LBit, LJdx: UInt64;
+  LTemp, LBit, LJdx, LHash: UInt64;
 begin
 begin
 
 
   LLength := ADataLength;
   LLength := ADataLength;
@@ -749,16 +786,18 @@ begin
     end;
     end;
 
 
     LJdx := $80;
     LJdx := $80;
+    LHash := FHash;
     while LJdx > 0 do
     while LJdx > 0 do
     begin
     begin
-      LBit := FHash and FCRCHighBitMask;
-      FHash := FHash shl 1;
+      LBit := LHash and FCRCHighBitMask;
+      LHash := LHash shl 1;
       if ((LTemp and LJdx) > 0) then
       if ((LTemp and LJdx) > 0) then
         LBit := LBit xor FCRCHighBitMask;
         LBit := LBit xor FCRCHighBitMask;
       if (LBit > 0) then
       if (LBit > 0) then
-        FHash := FHash xor Polynomial;
+        LHash := LHash xor Polynomial;
       LJdx := LJdx shr 1;
       LJdx := LJdx shr 1;
     end;
     end;
+    FHash := LHash;
     System.Inc(LIdx);
     System.Inc(LIdx);
     System.Dec(LLength);
     System.Dec(LLength);
   end;
   end;
@@ -854,15 +893,15 @@ begin
 
 
     TCRCStandard.CRC4_ITU:
     TCRCStandard.CRC4_ITU:
       result := TCRC.Create(4, $3, $0, True, True, $0, $7,
       result := TCRC.Create(4, $3, $0, True, True, $0, $7,
-        THashLibStringArray.Create('CRC-4/ITU'));
+        THashLibStringArray.Create('CRC-4/ITU', 'CRC-4/G-704'));
 
 
     TCRCStandard.CRC5_EPC:
     TCRCStandard.CRC5_EPC:
       result := TCRC.Create(5, $9, $9, False, False, $00, $00,
       result := TCRC.Create(5, $9, $9, False, False, $00, $00,
-        THashLibStringArray.Create('CRC-5/EPC'));
+        THashLibStringArray.Create('CRC-5/EPC', 'CRC-5/EPC-C1G2'));
 
 
     TCRCStandard.CRC5_ITU:
     TCRCStandard.CRC5_ITU:
       result := TCRC.Create(5, $15, $00, True, True, $00, $07,
       result := TCRC.Create(5, $15, $00, True, True, $00, $07,
-        THashLibStringArray.Create('CRC-5/ITU'));
+        THashLibStringArray.Create('CRC-5/ITU', 'CRC-5/G-704'));
 
 
     TCRCStandard.CRC5_USB:
     TCRCStandard.CRC5_USB:
       result := TCRC.Create(5, $05, $1F, True, True, $1F, $19,
       result := TCRC.Create(5, $05, $1F, True, True, $1F, $19,
@@ -886,11 +925,11 @@ begin
 
 
     TCRCStandard.CRC6_ITU:
     TCRCStandard.CRC6_ITU:
       result := TCRC.Create(6, $03, $00, True, True, $00, $06,
       result := TCRC.Create(6, $03, $00, True, True, $00, $06,
-        THashLibStringArray.Create('CRC-6/ITU'));
+        THashLibStringArray.Create('CRC-6/ITU', 'CRC-6/G-704'));
 
 
     TCRCStandard.CRC7:
     TCRCStandard.CRC7:
       result := TCRC.Create(7, $09, $00, False, False, $00, $75,
       result := TCRC.Create(7, $09, $00, False, False, $00, $75,
-        THashLibStringArray.Create('CRC-7'));
+        THashLibStringArray.Create('CRC-7', 'CRC-7/MMC'));
 
 
     TCRCStandard.CRC7_ROHC:
     TCRCStandard.CRC7_ROHC:
       result := TCRC.Create(7, $4F, $7F, True, True, $00, $53,
       result := TCRC.Create(7, $4F, $7F, True, True, $00, $53,
@@ -902,7 +941,7 @@ begin
 
 
     TCRCStandard.CRC8:
     TCRCStandard.CRC8:
       result := TCRC.Create(8, $07, $00, False, False, $00, $F4,
       result := TCRC.Create(8, $07, $00, False, False, $00, $F4,
-        THashLibStringArray.Create('CRC-8'));
+        THashLibStringArray.Create('CRC-8', 'CRC-8/SMBUS'));
 
 
     TCRCStandard.CRC8_AUTOSAR:
     TCRCStandard.CRC8_AUTOSAR:
       result := TCRC.Create(8, $2F, $FF, False, False, $FF, $DF,
       result := TCRC.Create(8, $2F, $FF, False, False, $FF, $DF,
@@ -926,7 +965,8 @@ begin
 
 
     TCRCStandard.CRC8_EBU:
     TCRCStandard.CRC8_EBU:
       result := TCRC.Create(8, $1D, $FF, True, True, $00, $97,
       result := TCRC.Create(8, $1D, $FF, True, True, $00, $97,
-        THashLibStringArray.Create('CRC-8/EBU', 'CRC-8/AES'));
+        THashLibStringArray.Create('CRC-8/EBU', 'CRC-8/AES',
+        'CRC-8/TECH-3250'));
 
 
     TCRCStandard.CRC8_GSMA:
     TCRCStandard.CRC8_GSMA:
       result := TCRC.Create(8, $1D, $00, False, False, $00, $37,
       result := TCRC.Create(8, $1D, $00, False, False, $00, $37,
@@ -942,7 +982,7 @@ begin
 
 
     TCRCStandard.CRC8_ITU:
     TCRCStandard.CRC8_ITU:
       result := TCRC.Create(8, $07, $00, False, False, $55, $A1,
       result := TCRC.Create(8, $07, $00, False, False, $55, $A1,
-        THashLibStringArray.Create('CRC-8/ITU'));
+        THashLibStringArray.Create('CRC-8/ITU', 'CRC-8/I-432-1'));
 
 
     TCRCStandard.CRC8_LTE:
     TCRCStandard.CRC8_LTE:
       result := TCRC.Create(8, $9B, $00, False, False, $00, $EA,
       result := TCRC.Create(8, $9B, $00, False, False, $00, $EA,
@@ -950,7 +990,8 @@ begin
 
 
     TCRCStandard.CRC8_MAXIM:
     TCRCStandard.CRC8_MAXIM:
       result := TCRC.Create(8, $31, $00, True, True, $00, $A1,
       result := TCRC.Create(8, $31, $00, True, True, $00, $A1,
-        THashLibStringArray.Create('CRC-8/MAXIM', 'DOW-CRC'));
+        THashLibStringArray.Create('CRC-8/MAXIM', 'DOW-CRC',
+        'CRC-8/MAXIM-DOW'));
 
 
     TCRCStandard.CRC8_OPENSAFETY:
     TCRCStandard.CRC8_OPENSAFETY:
       result := TCRC.Create(8, $2F, $00, False, False, $00, $3E,
       result := TCRC.Create(8, $2F, $00, False, False, $00, $3E,
@@ -968,9 +1009,17 @@ begin
       result := TCRC.Create(8, $9B, $00, True, True, $00, $25,
       result := TCRC.Create(8, $9B, $00, True, True, $00, $25,
         THashLibStringArray.Create('CRC-8/WCDMA'));
         THashLibStringArray.Create('CRC-8/WCDMA'));
 
 
+    TCRCStandard.CRC8_MIFAREMAD:
+      result := TCRC.Create(8, $1D, $C7, False, False, $00, $99,
+        THashLibStringArray.Create('CRC-8/MIFARE-MAD'));
+
+    TCRCStandard.CRC8_NRSC5:
+      result := TCRC.Create(8, $31, $FF, False, False, $00, $F7,
+        THashLibStringArray.Create('CRC-8/NRSC-5'));
+
     TCRCStandard.CRC10:
     TCRCStandard.CRC10:
       result := TCRC.Create(10, $233, $000, False, False, $000, $199,
       result := TCRC.Create(10, $233, $000, False, False, $000, $199,
-        THashLibStringArray.Create('CRC-10'));
+        THashLibStringArray.Create('CRC-10', 'CRC-10/ATM', 'CRC-10/I-610'));
 
 
     TCRCStandard.CRC10_CDMA2000:
     TCRCStandard.CRC10_CDMA2000:
       result := TCRC.Create(10, $3D9, $3FF, False, False, $000, $233,
       result := TCRC.Create(10, $3D9, $3FF, False, False, $000, $233,
@@ -982,7 +1031,7 @@ begin
 
 
     TCRCStandard.CRC11:
     TCRCStandard.CRC11:
       result := TCRC.Create(11, $385, $01A, False, False, $000, $5A3,
       result := TCRC.Create(11, $385, $01A, False, False, $000, $5A3,
-        THashLibStringArray.Create('CRC-11'));
+        THashLibStringArray.Create('CRC-11', 'CRC-11/FLEXRAY'));
 
 
     TCRCStandard.CRC11_UMTS:
     TCRCStandard.CRC11_UMTS:
       result := TCRC.Create(11, $307, $000, False, False, $000, $061,
       result := TCRC.Create(11, $307, $000, False, False, $000, $061,
@@ -1018,7 +1067,7 @@ begin
 
 
     TCRCStandard.CRC15:
     TCRCStandard.CRC15:
       result := TCRC.Create(15, $4599, $0000, False, False, $0000, $059E,
       result := TCRC.Create(15, $4599, $0000, False, False, $0000, $059E,
-        THashLibStringArray.Create('CRC-15'));
+        THashLibStringArray.Create('CRC-15', 'CRC-15/CAN'));
 
 
     TCRCStandard.CRC15_MPT1327:
     TCRCStandard.CRC15_MPT1327:
       result := TCRC.Create(15, $6815, $0000, False, False, $0001, $2566,
       result := TCRC.Create(15, $6815, $0000, False, False, $0001, $2566,
@@ -1035,11 +1084,13 @@ begin
 
 
     TCRCStandard.CRC16_BUYPASS:
     TCRCStandard.CRC16_BUYPASS:
       result := TCRC.Create(16, $8005, $0000, False, False, $0000, $FEE8,
       result := TCRC.Create(16, $8005, $0000, False, False, $0000, $FEE8,
-        THashLibStringArray.Create('CRC-16/BUYPASS', 'CRC-16/VERIFONE'));
+        THashLibStringArray.Create('CRC-16/BUYPASS', 'CRC-16/VERIFONE',
+        'CRC-16/UMTS'));
 
 
     TCRCStandard.CRC16_CCITTFALSE:
     TCRCStandard.CRC16_CCITTFALSE:
       result := TCRC.Create(16, $1021, $FFFF, False, False, $0000, $29B1,
       result := TCRC.Create(16, $1021, $FFFF, False, False, $0000, $29B1,
-        THashLibStringArray.Create('CRC-16/CCITT-FALSE'));
+        THashLibStringArray.Create('CRC-16/CCITT-FALSE', 'CRC-16/AUTOSAR',
+        'CRC-16/IBM-3740'));
 
 
     TCRCStandard.CRC16_CDMA2000:
     TCRCStandard.CRC16_CDMA2000:
       result := TCRC.Create(16, $C867, $FFFF, False, False, $0000, $4C06,
       result := TCRC.Create(16, $C867, $FFFF, False, False, $0000, $4C06,
@@ -1072,7 +1123,7 @@ begin
     TCRCStandard.CRC16_GENIBUS:
     TCRCStandard.CRC16_GENIBUS:
       result := TCRC.Create(16, $1021, $FFFF, False, False, $FFFF, $D64E,
       result := TCRC.Create(16, $1021, $FFFF, False, False, $FFFF, $D64E,
         THashLibStringArray.Create('CRC-16/GENIBUS', 'CRC-16/EPC',
         THashLibStringArray.Create('CRC-16/GENIBUS', 'CRC-16/EPC',
-        'CRC-16/I-CODE', 'CRC-16/DARC'));
+        'CRC-16/I-CODE', 'CRC-16/DARC', 'CRC-16/EPC-C1G2'));
 
 
     TCRCStandard.CRC16_GSM:
     TCRCStandard.CRC16_GSM:
       result := TCRC.Create(16, $1021, $0000, False, False, $FFFF, $CE3C,
       result := TCRC.Create(16, $1021, $0000, False, False, $FFFF, $CE3C,
@@ -1084,7 +1135,7 @@ begin
 
 
     TCRCStandard.CRC16_MAXIM:
     TCRCStandard.CRC16_MAXIM:
       result := TCRC.Create(16, $8005, $0000, True, True, $FFFF, $44C2,
       result := TCRC.Create(16, $8005, $0000, True, True, $FFFF, $44C2,
-        THashLibStringArray.Create('CRC-16/MAXIM'));
+        THashLibStringArray.Create('CRC-16/MAXIM', 'CRC-16/MAXIM-DOW'));
 
 
     TCRCStandard.CRC16_MCRF4XX:
     TCRCStandard.CRC16_MCRF4XX:
       result := TCRC.Create(16, $1021, $FFFF, True, True, $0000, $6F91,
       result := TCRC.Create(16, $1021, $FFFF, True, True, $0000, $6F91,
@@ -1124,25 +1175,30 @@ begin
 
 
     TCRCStandard.CRCA:
     TCRCStandard.CRCA:
       result := TCRC.Create(16, $1021, $C6C6, True, True, $0000, $BF05,
       result := TCRC.Create(16, $1021, $C6C6, True, True, $0000, $BF05,
-        THashLibStringArray.Create('CRC-A'));
+        THashLibStringArray.Create('CRC-A', 'CRC-16/ISO-IEC-14443-3-A'));
 
 
     TCRCStandard.KERMIT:
     TCRCStandard.KERMIT:
       result := TCRC.Create(16, $1021, $0000, True, True, $0000, $2189,
       result := TCRC.Create(16, $1021, $0000, True, True, $0000, $2189,
         THashLibStringArray.Create('KERMIT', 'CRC-16/CCITT',
         THashLibStringArray.Create('KERMIT', 'CRC-16/CCITT',
-        'CRC-16/CCITT-TRUE', 'CRC-CCITT'));
+        'CRC-16/CCITT-TRUE', 'CRC-CCITT', 'CRC-16/KERMIT', 'CRC-16/V-41-LSB'));
 
 
     TCRCStandard.MODBUS:
     TCRCStandard.MODBUS:
       result := TCRC.Create(16, $8005, $FFFF, True, True, $0000, $4B37,
       result := TCRC.Create(16, $8005, $FFFF, True, True, $0000, $4B37,
-        THashLibStringArray.Create('MODBUS'));
+        THashLibStringArray.Create('MODBUS', 'CRC-16/MODBUS'));
 
 
     TCRCStandard.X25:
     TCRCStandard.X25:
       result := TCRC.Create(16, $1021, $FFFF, True, True, $FFFF, $906E,
       result := TCRC.Create(16, $1021, $FFFF, True, True, $FFFF, $906E,
         THashLibStringArray.Create('X-25', 'CRC-16/IBM-SDLC', 'CRC-16/ISO-HDLC',
         THashLibStringArray.Create('X-25', 'CRC-16/IBM-SDLC', 'CRC-16/ISO-HDLC',
-        'CRC-B'));
+        'CRC-16/ISO-IEC-14443-3-B', 'CRC-B', 'CRC-16/X-25'));
 
 
     TCRCStandard.XMODEM:
     TCRCStandard.XMODEM:
       result := TCRC.Create(16, $1021, $0000, False, False, $0000, $31C3,
       result := TCRC.Create(16, $1021, $0000, False, False, $0000, $31C3,
-        THashLibStringArray.Create('XMODEM', 'ZMODEM', 'CRC-16/ACORN'));
+        THashLibStringArray.Create('XMODEM', 'ZMODEM', 'CRC-16/ACORN',
+        'CRC-16/XMODEM', 'CRC-16/V-41-MSB'));
+
+    TCRCStandard.CRC16_NRSC5:
+      result := TCRC.Create(16, $080B, $FFFF, True, True, $0000, $A066,
+        THashLibStringArray.Create('CRC-16/NRSC-5'));
 
 
     TCRCStandard.CRC17_CANFD:
     TCRCStandard.CRC17_CANFD:
       result := TCRC.Create(17, $1685B, $00000, False, False, $00000, $04F03,
       result := TCRC.Create(17, $1685B, $00000, False, False, $00000, $04F03,
@@ -1180,6 +1236,10 @@ begin
       result := TCRC.Create(24, $800063, $000000, False, False, $000000,
       result := TCRC.Create(24, $800063, $000000, False, False, $000000,
         $23EF52, THashLibStringArray.Create('CRC-24/LTE-B'));
         $23EF52, THashLibStringArray.Create('CRC-24/LTE-B'));
 
 
+    TCRCStandard.CRC24_OS9:
+      result := TCRC.Create(24, $800063, $FFFFFF, False, False, $FFFFFF,
+        $200FA5, THashLibStringArray.Create('CRC-24/OS-9'));
+
     TCRCStandard.CRC30_CDMA:
     TCRCStandard.CRC30_CDMA:
       result := TCRC.Create(30, $2030B9C7, $3FFFFFFF, False, False, $3FFFFFFF,
       result := TCRC.Create(30, $2030B9C7, $3FFFFFFF, False, False, $3FFFFFFF,
         $04C34ABF, THashLibStringArray.Create('CRC-30/CDMA'));
         $04C34ABF, THashLibStringArray.Create('CRC-30/CDMA'));
@@ -1191,7 +1251,7 @@ begin
     TCRCStandard.CRC32:
     TCRCStandard.CRC32:
       result := TCRC.Create(32, $04C11DB7, $FFFFFFFF, True, True, $FFFFFFFF,
       result := TCRC.Create(32, $04C11DB7, $FFFFFFFF, True, True, $FFFFFFFF,
         $CBF43926, THashLibStringArray.Create('CRC-32', 'CRC-32/ADCCP',
         $CBF43926, THashLibStringArray.Create('CRC-32', 'CRC-32/ADCCP',
-        'PKZIP'));
+        'CRC-32/V-42', 'CRC-32/XZ', 'PKZIP', 'CRC-32/ISO-HDLC'));
 
 
     TCRCStandard.CRC32_AUTOSAR:
     TCRCStandard.CRC32_AUTOSAR:
       result := TCRC.Create(32, $F4ACFB13, $FFFFFFFF, True, True, $FFFFFFFF,
       result := TCRC.Create(32, $F4ACFB13, $FFFFFFFF, True, True, $FFFFFFFF,
@@ -1204,12 +1264,12 @@ begin
 
 
     TCRCStandard.CRC32C:
     TCRCStandard.CRC32C:
       result := TCRC.Create(32, $1EDC6F41, $FFFFFFFF, True, True, $FFFFFFFF,
       result := TCRC.Create(32, $1EDC6F41, $FFFFFFFF, True, True, $FFFFFFFF,
-        $E3069283, THashLibStringArray.Create('CRC-32C', 'CRC-32/ISCSI',
-        'CRC-32/CASTAGNOLI', 'CRC-32/INTERLAKEN'));
+        $E3069283, THashLibStringArray.Create('CRC-32C', 'CRC-32/BASE91-C',
+        'CRC-32/CASTAGNOLI', 'CRC-32/INTERLAKEN', 'CRC-32/ISCSI'));
 
 
     TCRCStandard.CRC32D:
     TCRCStandard.CRC32D:
       result := TCRC.Create(32, $A833982B, $FFFFFFFF, True, True, $FFFFFFFF,
       result := TCRC.Create(32, $A833982B, $FFFFFFFF, True, True, $FFFFFFFF,
-        $87315576, THashLibStringArray.Create('CRC-32D'));
+        $87315576, THashLibStringArray.Create('CRC-32D', 'CRC-32/BASE91-D'));
 
 
     TCRCStandard.CRC32_MPEG2:
     TCRCStandard.CRC32_MPEG2:
       result := TCRC.Create(32, $04C11DB7, $FFFFFFFF, False, False, $00000000,
       result := TCRC.Create(32, $04C11DB7, $FFFFFFFF, False, False, $00000000,
@@ -1221,15 +1281,19 @@ begin
 
 
     TCRCStandard.CRC32Q:
     TCRCStandard.CRC32Q:
       result := TCRC.Create(32, $814141AB, $00000000, False, False, $00000000,
       result := TCRC.Create(32, $814141AB, $00000000, False, False, $00000000,
-        $3010BF7F, THashLibStringArray.Create('CRC-32Q'));
+        $3010BF7F, THashLibStringArray.Create('CRC-32Q', 'CRC-32/AIXM'));
 
 
     TCRCStandard.JAMCRC:
     TCRCStandard.JAMCRC:
       result := TCRC.Create(32, $04C11DB7, $FFFFFFFF, True, True, $00000000,
       result := TCRC.Create(32, $04C11DB7, $FFFFFFFF, True, True, $00000000,
-        $340BC6D9, THashLibStringArray.Create('JAMCRC'));
+        $340BC6D9, THashLibStringArray.Create('JAMCRC', 'CRC-32/JAMCRC'));
 
 
     TCRCStandard.XFER:
     TCRCStandard.XFER:
       result := TCRC.Create(32, $000000AF, $00000000, False, False, $00000000,
       result := TCRC.Create(32, $000000AF, $00000000, False, False, $00000000,
-        $BD0BE338, THashLibStringArray.Create('XFER'));
+        $BD0BE338, THashLibStringArray.Create('XFER', 'CRC-32/XFER'));
+
+    TCRCStandard.CRC32_CDROMEDC:
+      result := TCRC.Create(32, $8001801B, $00000000, True, True, $00000000,
+        $6EC2EDC4, THashLibStringArray.Create('CRC-32/CD-ROM-EDC'));
 
 
     TCRCStandard.CRC40_GSM:
     TCRCStandard.CRC40_GSM:
       result := TCRC.Create(40, $0004820009, $0000000000, False, False,
       result := TCRC.Create(40, $0004820009, $0000000000, False, False,
@@ -1253,7 +1317,17 @@ begin
     TCRCStandard.CRC64_XZ:
     TCRCStandard.CRC64_XZ:
       result := TCRC.Create(64, $42F0E1EBA9EA3693, UInt64($FFFFFFFFFFFFFFFF),
       result := TCRC.Create(64, $42F0E1EBA9EA3693, UInt64($FFFFFFFFFFFFFFFF),
         True, True, UInt64($FFFFFFFFFFFFFFFF), UInt64($995DC9BBDF1939FA),
         True, True, UInt64($FFFFFFFFFFFFFFFF), UInt64($995DC9BBDF1939FA),
-        THashLibStringArray.Create('CRC-64/XZ', 'CRC-64/GO-ECMA'))
+        THashLibStringArray.Create('CRC-64/XZ', 'CRC-64/GO-ECMA'));
+
+    TCRCStandard.CRC64_1B:
+      result := TCRC.Create(64, $000000000000001B, UInt64($0000000000000000),
+        True, True, UInt64($0000000000000000), $46A5A9388A5BEFFE,
+        THashLibStringArray.Create('CRC-64/1B'));
+
+    TCRCStandard.CRC64_Jones:
+      result := TCRC.Create(64, UInt64($AD93D23594C935A9),
+        UInt64($FFFFFFFFFFFFFFFF), True, True, UInt64($0000000000000000),
+        UInt64($CAA717168609F281), THashLibStringArray.Create('CRC-64/Jones'))
 
 
   else
   else
     raise EArgumentInvalidHashLibException.CreateResFmt(@SUnSupportedCRCType,
     raise EArgumentInvalidHashLibException.CreateResFmt(@SUnSupportedCRCType,
@@ -1305,8 +1379,8 @@ end;
 procedure TCRC.Initialize;
 procedure TCRC.Initialize;
 begin
 begin
   // initialize some bitmasks
   // initialize some bitmasks
-  FCRCMask := (((UInt64(1) shl (Width - 1)) - 1) shl 1) or 1;
   FCRCHighBitMask := UInt64(1) shl (Width - 1);
   FCRCHighBitMask := UInt64(1) shl (Width - 1);
+  FCRCMask := ((FCRCHighBitMask - 1) shl 1) or 1;
   FHash := InitialValue;
   FHash := InitialValue;
 
 
   if (Width > Delta) then // then use table
   if (Width > Delta) then // then use table

+ 3 - 2
src/libraries/hashlib4pascal/HlpCRC16.pas

@@ -27,7 +27,7 @@ type
   TCRC16 = class(THash, IChecksum, IHash16, ITransformBlock)
   TCRC16 = class(THash, IChecksum, IHash16, ITransformBlock)
 
 
   strict private
   strict private
-
+  var
     FCRCAlgorithm: ICRC;
     FCRCAlgorithm: ICRC;
 
 
   public
   public
@@ -83,7 +83,8 @@ end;
 constructor TCRC16_BUYPASS.Create;
 constructor TCRC16_BUYPASS.Create;
 begin
 begin
   Inherited Create(TCRC16Polynomials.BUYPASS, $0000, false, false, $0000, $FEE8,
   Inherited Create(TCRC16Polynomials.BUYPASS, $0000, false, false, $0000, $FEE8,
-    THashLibStringArray.Create('CRC-16/BUYPASS', 'CRC-16/VERIFONE'));
+    THashLibStringArray.Create('CRC-16/BUYPASS', 'CRC-16/VERIFONE',
+    'CRC-16/UMTS'));
 end;
 end;
 
 
 end.
 end.

+ 6 - 4
src/libraries/hashlib4pascal/HlpCRC32.pas

@@ -30,7 +30,7 @@ type
   TCRC32 = class(THash, IChecksum, IHash32, ITransformBlock)
   TCRC32 = class(THash, IChecksum, IHash32, ITransformBlock)
 
 
   strict private
   strict private
-
+  var
     FCRCAlgorithm: ICRC;
     FCRCAlgorithm: ICRC;
 
 
   public
   public
@@ -100,7 +100,8 @@ end;
 constructor TCRC32_PKZIP.Create;
 constructor TCRC32_PKZIP.Create;
 begin
 begin
   Inherited Create(TCRC32Polynomials.PKZIP, $FFFFFFFF, true, true, $FFFFFFFF,
   Inherited Create(TCRC32Polynomials.PKZIP, $FFFFFFFF, true, true, $FFFFFFFF,
-    $CBF43926, THashLibStringArray.Create('CRC-32', 'CRC-32/ADCCP', 'PKZIP'));
+    $CBF43926, THashLibStringArray.Create('CRC-32', 'CRC-32/ADCCP',
+    'CRC-32/V-42', 'CRC-32/XZ', 'PKZIP', 'CRC-32/ISO-HDLC'));
 
 
 end;
 end;
 
 
@@ -109,8 +110,9 @@ end;
 constructor TCRC32_CASTAGNOLI.Create;
 constructor TCRC32_CASTAGNOLI.Create;
 begin
 begin
   Inherited Create(TCRC32Polynomials.Castagnoli, $FFFFFFFF, true, true,
   Inherited Create(TCRC32Polynomials.Castagnoli, $FFFFFFFF, true, true,
-    $FFFFFFFF, $E3069283, THashLibStringArray.Create('CRC-32C', 'CRC-32/ISCSI',
-    'CRC-32/CASTAGNOLI'));
+    $FFFFFFFF, $E3069283, THashLibStringArray.Create('CRC-32C',
+    'CRC-32/BASE91-C', 'CRC-32/CASTAGNOLI', 'CRC-32/INTERLAKEN',
+    'CRC-32/ISCSI'));
 
 
 end;
 end;
 
 

+ 75 - 41
src/libraries/hashlib4pascal/HlpCRC32Fast.pas

@@ -10,7 +10,8 @@ uses
   HlpIHash,
   HlpIHash,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpHashResult,
   HlpHashResult,
-  HlpIHashResult;
+  HlpIHashResult,
+  HlpConverters;
 
 
 type
 type
 
 
@@ -20,11 +21,11 @@ type
   var
   var
     FCurrentCRC: UInt32;
     FCurrentCRC: UInt32;
 
 
-    procedure LocalCRCCompute(const ACRCTable: THashLibUInt32Array;
+    procedure LocalCRCCompute(const ACRCTable: THashLibMatrixUInt32Array;
       const AData: THashLibByteArray; AIndex, ALength: Int32);
       const AData: THashLibByteArray; AIndex, ALength: Int32);
 
 
     class function Init_CRC_Table(APolynomial: UInt32)
     class function Init_CRC_Table(APolynomial: UInt32)
-      : THashLibUInt32Array; static;
+      : THashLibMatrixUInt32Array; static;
 
 
   public
   public
 
 
@@ -44,7 +45,7 @@ type
     CRC32_PKZIP_Polynomial = UInt32($EDB88320);
     CRC32_PKZIP_Polynomial = UInt32($EDB88320);
     class var
     class var
 
 
-      FCRC32_PKZIP_Table: THashLibUInt32Array;
+      FCRC32_PKZIP_Table: THashLibMatrixUInt32Array;
 
 
     class constructor CRC32_PKZIP();
     class constructor CRC32_PKZIP();
 
 
@@ -64,7 +65,7 @@ type
     CRC32_CASTAGNOLI_Polynomial = UInt32($82F63B78); // Polynomial Reversed
     CRC32_CASTAGNOLI_Polynomial = UInt32($82F63B78); // Polynomial Reversed
     class var
     class var
 
 
-      FCRC32_CASTAGNOLI_Table: THashLibUInt32Array;
+      FCRC32_CASTAGNOLI_Table: THashLibMatrixUInt32Array;
 
 
     class constructor CRC32_CASTAGNOLI();
     class constructor CRC32_CASTAGNOLI();
 
 
@@ -81,12 +82,16 @@ implementation
 { TCRC32Fast }
 { TCRC32Fast }
 
 
 class function TCRC32Fast.Init_CRC_Table(APolynomial: UInt32)
 class function TCRC32Fast.Init_CRC_Table(APolynomial: UInt32)
-  : THashLibUInt32Array;
+  : THashLibMatrixUInt32Array;
 var
 var
   LIdx, LJIdx, LKIdx: Int32;
   LIdx, LJIdx, LKIdx: Int32;
   LRes: UInt32;
   LRes: UInt32;
 begin
 begin
-  System.SetLength(Result, 16 * 256);
+  System.SetLength(Result, 16);
+  for LIdx := System.Low(Result) to System.High(Result) do
+  begin
+    System.SetLength(Result[LIdx], 256);
+  end;
   for LIdx := 0 to System.Pred(256) do
   for LIdx := 0 to System.Pred(256) do
   begin
   begin
     LRes := LIdx;
     LRes := LIdx;
@@ -112,55 +117,79 @@ begin
           * }
           * }
         // faster branchless variant
         // faster branchless variant
         LRes := (LRes shr 1) xor (-Int32(LRes and 1) and APolynomial);
         LRes := (LRes shr 1) xor (-Int32(LRes and 1) and APolynomial);
-        Result[(LJIdx * 256) + LIdx] := LRes;
+        Result[LJIdx][LIdx] := LRes;
         System.Inc(LKIdx);
         System.Inc(LKIdx);
       end;
       end;
     end;
     end;
   end;
   end;
 end;
 end;
 
 
-procedure TCRC32Fast.LocalCRCCompute(const ACRCTable: THashLibUInt32Array;
+procedure TCRC32Fast.LocalCRCCompute(const ACRCTable: THashLibMatrixUInt32Array;
   const AData: THashLibByteArray; AIndex, ALength: Int32);
   const AData: THashLibByteArray; AIndex, ALength: Int32);
+const
+  Unroll = Int32(4);
+  BytesAtOnce = Int32(16 * Unroll);
 var
 var
-  LCRC, LA, LB, LC, LD: UInt32;
-  LCRCTable: THashLibUInt32Array;
+  LCRC, LOne, LTwo, LThree, LFour: UInt32;
+  LCRCTable: THashLibMatrixUInt32Array;
+  LCurrent: PCardinal;
+  LUnrolling: Int32;
+  LCurrentPtr: PByte;
 begin
 begin
   LCRC := not FCurrentCRC; // LCRC := System.High(UInt32) xor FCurrentCRC;
   LCRC := not FCurrentCRC; // LCRC := System.High(UInt32) xor FCurrentCRC;
   LCRCTable := ACRCTable;
   LCRCTable := ACRCTable;
-  while ALength >= 16 do
+  LCurrent := PCardinal(PByte(AData) + AIndex);
+  while ALength >= BytesAtOnce do
   begin
   begin
+    LUnrolling := 0;
 
 
-    LA := LCRCTable[(3 * 256) + AData[AIndex + 12]] xor LCRCTable
-      [(2 * 256) + AData[AIndex + 13]] xor LCRCTable
-      [(1 * 256) + AData[AIndex + 14]] xor LCRCTable
-      [(0 * 256) + AData[AIndex + 15]];
-
-    LB := LCRCTable[(7 * 256) + AData[AIndex + 8]] xor LCRCTable
-      [(6 * 256) + AData[AIndex + 9]] xor LCRCTable
-      [(5 * 256) + AData[AIndex + 10]] xor LCRCTable
-      [(4 * 256) + AData[AIndex + 11]];
-
-    LC := LCRCTable[(11 * 256) + AData[AIndex + 4]] xor LCRCTable
-      [(10 * 256) + AData[AIndex + 5]] xor LCRCTable
-      [(9 * 256) + AData[AIndex + 6]] xor LCRCTable
-      [(8 * 256) + AData[AIndex + 7]];
-
-    LD := LCRCTable[(15 * 256) + ((LCRC and $FF) xor AData[AIndex])
-      ] xor LCRCTable[(14 * 256) + (((LCRC shr 8) and $FF) xor AData[AIndex + 1]
-      )] xor LCRCTable[(13 * 256) + (((LCRC shr 16) and $FF) xor AData
-      [AIndex + 2])] xor LCRCTable
-      [(12 * 256) + ((LCRC shr 24) xor AData[AIndex + 3])];
-
-    LCRC := LD xor LC xor LB xor LA;
-    System.Inc(AIndex, 16);
-    System.Dec(ALength, 16);
+    while LUnrolling < Unroll do
+    begin
+      LOne := TConverters.ReadPCardinalAsUInt32(LCurrent)
+        xor TConverters.le2me_32(LCRC);
+      System.Inc(LCurrent);
+      LTwo := TConverters.ReadPCardinalAsUInt32(LCurrent);
+      System.Inc(LCurrent);
+      LThree := TConverters.ReadPCardinalAsUInt32(LCurrent);
+      System.Inc(LCurrent);
+      LFour := TConverters.ReadPCardinalAsUInt32(LCurrent);
+      System.Inc(LCurrent);
+
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+      LCRC := LCRCTable[0][(LFour shr 24) and $FF] xor LCRCTable[1]
+        [(LFour shr 16) and $FF] xor LCRCTable[2][(LFour shr 8) and $FF]
+        xor LCRCTable[3][LFour and $FF] xor LCRCTable[4]
+        [(LThree shr 24) and $FF] xor LCRCTable[5][(LThree shr 16) and $FF]
+        xor LCRCTable[6][(LThree shr 8) and $FF] xor LCRCTable[7]
+        [LThree and $FF] xor LCRCTable[8][(LTwo shr 24) and $FF] xor LCRCTable
+        [9][(LTwo shr 16) and $FF] xor LCRCTable[10][(LTwo shr 8) and $FF]
+        xor LCRCTable[11][LTwo and $FF] xor LCRCTable[12][(LOne shr 24) and $FF]
+        xor LCRCTable[13][(LOne shr 16) and $FF] xor LCRCTable[14]
+        [(LOne shr 8) and $FF] xor LCRCTable[15][LOne and $FF];
+{$ELSE}
+      LCRC := LCRCTable[0][LFour and $FF] xor LCRCTable[1]
+        [(LFour shr 8) and $FF] xor LCRCTable[2][(LFour shr 16) and $FF]
+        xor LCRCTable[3][(LFour shr 24) and $FF] xor LCRCTable[4]
+        [LThree and $FF] xor LCRCTable[5][(LThree shr 8) and $FF] xor LCRCTable
+        [6][(LThree shr 16) and $FF] xor LCRCTable[7][(LThree shr 24) and $FF]
+        xor LCRCTable[8][LTwo and $FF] xor LCRCTable[9][(LTwo shr 8) and $FF]
+        xor LCRCTable[10][(LTwo shr 16) and $FF] xor LCRCTable[11]
+        [(LTwo shr 24) and $FF] xor LCRCTable[12][LOne and $FF] xor LCRCTable
+        [13][(LOne shr 8) and $FF] xor LCRCTable[14][(LOne shr 16) and $FF]
+        xor LCRCTable[15][(LOne shr 24) and $FF];
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
+      System.Inc(LUnrolling);
+    end;
+
+    System.Dec(ALength, BytesAtOnce);
   end;
   end;
 
 
-  System.Dec(ALength);
-  while (ALength >= 0) do
+  LCurrentPtr := PByte(LCurrent);
+  // remaining 1 to 63 bytes (standard algorithm)
+  while (ALength <> 0) do
   begin
   begin
-    LCRC := LCRCTable[Byte(LCRC xor AData[AIndex])] xor (LCRC shr 8);
-    System.Inc(AIndex);
+    LCRC := (LCRC shr 8) xor LCRCTable[0][(LCRC and $FF) xor LCurrentPtr^];
+    System.Inc(LCurrentPtr);
     System.Dec(ALength);
     System.Dec(ALength);
   end;
   end;
 
 
@@ -178,8 +207,13 @@ begin
 end;
 end;
 
 
 function TCRC32Fast.TransformFinal: IHashResult;
 function TCRC32Fast.TransformFinal: IHashResult;
+var
+  LBufferBytes: THashLibByteArray;
 begin
 begin
-  Result := THashResult.Create(FCurrentCRC);
+  System.SetLength(LBufferBytes, HashSize);
+  TConverters.ReadUInt32AsBytesBE(FCurrentCRC, LBufferBytes, 0);
+
+  Result := THashResult.Create(LBufferBytes);
   Initialize();
   Initialize();
 end;
 end;
 
 

+ 3 - 3
src/libraries/hashlib4pascal/HlpCRC64.pas

@@ -28,7 +28,7 @@ type
   TCRC64 = class(THash, IChecksum, IHash64, ITransformBlock)
   TCRC64 = class(THash, IChecksum, IHash64, ITransformBlock)
 
 
   strict private
   strict private
-
+  var
     FCRCAlgorithm: ICRC;
     FCRCAlgorithm: ICRC;
 
 
   public
   public
@@ -90,8 +90,8 @@ end;
 constructor TCRC64_ECMA_182.Create;
 constructor TCRC64_ECMA_182.Create;
 begin
 begin
   Inherited Create(TCRC64Polynomials.ECMA_182, $0000000000000000, false, false,
   Inherited Create(TCRC64Polynomials.ECMA_182, $0000000000000000, false, false,
-    $0000000000000000, $6C40DF5F0B497347,
-    THashLibStringArray.Create('CRC-64/ECMA'));
+    $0000000000000000, $6C40DF5F0B497347, THashLibStringArray.Create('CRC-64',
+    'CRC-64/ECMA-182'));
 end;
 end;
 
 
 end.
 end.

+ 160 - 233
src/libraries/hashlib4pascal/HlpConverters.pas

@@ -19,13 +19,7 @@ type
   TConverters = class sealed(TObject)
   TConverters = class sealed(TObject)
 
 
   strict private
   strict private
-    class function SplitString(const AInput: String; ADelimiter: Char)
-      : THashLibStringArray; static;
 
 
-{$IFDEF DEBUG}
-    class procedure Check(const AInput: THashLibByteArray;
-      AInputSize, AOutputSize: Int32); overload; static;
-{$ENDIF DEBUG}
     class procedure swap_copy_str_to_u32(ASource: Pointer; ASourceIndex: Int32;
     class procedure swap_copy_str_to_u32(ASource: Pointer; ASourceIndex: Int32;
       ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32); static;
       ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32); static;
 
 
@@ -58,18 +52,6 @@ type
       ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
       ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
       static; inline;
       static; inline;
 
 
-    class function ReadBytesAsUInt32LE(AInput: PByte; AIndex: Int32): UInt32;
-      static; inline;
-
-    class function ReadBytesAsUInt64LE(AInput: PByte; AIndex: Int32): UInt64;
-      static; inline;
-
-    class function ReadUInt32AsBytesLE(AInput: UInt32): THashLibByteArray;
-      overload; static; inline;
-
-    class function ReadUInt64AsBytesLE(AInput: UInt64): THashLibByteArray;
-      overload; static; inline;
-
     class procedure ReadUInt32AsBytesLE(AInput: UInt32;
     class procedure ReadUInt32AsBytesLE(AInput: UInt32;
       const AOutput: THashLibByteArray; AIndex: Int32); overload;
       const AOutput: THashLibByteArray; AIndex: Int32); overload;
       static; inline;
       static; inline;
@@ -86,6 +68,35 @@ type
       const AOutput: THashLibByteArray; AIndex: Int32); overload;
       const AOutput: THashLibByteArray; AIndex: Int32); overload;
       static; inline;
       static; inline;
 
 
+    class function ReadPCardinalAsUInt32(AInput: PCardinal): UInt32;
+      static; inline;
+
+    class function ReadPUInt64AsUInt64(AInput: PUInt64): UInt64; static; inline;
+
+    class function ReadPCardinalAsUInt32LE(AInput: PCardinal): UInt32;
+      static; inline;
+
+    class function ReadPUInt64AsUInt64LE(AInput: PUInt64): UInt64;
+      static; inline;
+
+    class function ReadBytesAsUInt32LE(AInput: PByte; AIndex: Int32): UInt32;
+      static; inline;
+
+    class function ReadBytesAsUInt64LE(AInput: PByte; AIndex: Int32): UInt64;
+      static; inline;
+
+    class function ReadBytesAsUInt32BE(AInput: PByte; AIndex: Int32): UInt32;
+      static; inline;
+
+    class function ReadBytesAsUInt64BE(AInput: PByte; AIndex: Int32): UInt64;
+      static; inline;
+
+    class function ReadUInt32AsBytesLE(AInput: UInt32): THashLibByteArray;
+      overload; static; inline;
+
+    class function ReadUInt64AsBytesLE(AInput: UInt64): THashLibByteArray;
+      overload; static; inline;
+
     class function ConvertStringToBytes(const AInput: String;
     class function ConvertStringToBytes(const AInput: String;
       const AEncoding: TEncoding): THashLibByteArray; overload; static;
       const AEncoding: TEncoding): THashLibByteArray; overload; static;
 
 
@@ -104,16 +115,6 @@ implementation
 
 
 { TConverters }
 { TConverters }
 
 
-{$IFDEF DEBUG}
-
-class procedure TConverters.Check(const AInput: THashLibByteArray;
-  AInputSize, AOutputSize: Int32);
-begin
-  System.Assert(((System.length(AInput) * AInputSize) mod AOutputSize) = 0);
-end;
-
-{$ENDIF DEBUG}
-
 class procedure TConverters.swap_copy_str_to_u32(ASource: Pointer;
 class procedure TConverters.swap_copy_str_to_u32(ASource: Pointer;
   ASourceIndex: Int32; ADestination: Pointer; ADestinationIndex: Int32;
   ASourceIndex: Int32; ADestination: Pointer; ADestinationIndex: Int32;
   ASize: Int32);
   ASize: Int32);
@@ -188,157 +189,86 @@ end;
 
 
 class function TConverters.be2me_32(AInput: UInt32): UInt32;
 class function TConverters.be2me_32(AInput: UInt32): UInt32;
 begin
 begin
-  if TBitConverter.IsLittleEndian then
-  begin
-    result := TBits.ReverseBytesUInt32(AInput)
-  end
-  else
-  begin
-    result := AInput;
-  end;
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  result := TBits.ReverseBytesUInt32(AInput);
+{$ELSE}
+  result := AInput;
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class function TConverters.be2me_64(AInput: UInt64): UInt64;
 class function TConverters.be2me_64(AInput: UInt64): UInt64;
 begin
 begin
-  if TBitConverter.IsLittleEndian then
-  begin
-    result := TBits.ReverseBytesUInt64(AInput)
-  end
-  else
-  begin
-    result := AInput;
-  end;
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  result := TBits.ReverseBytesUInt64(AInput);
+{$ELSE}
+  result := AInput;
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class procedure TConverters.be32_copy(ASource: Pointer; ASourceIndex: Int32;
 class procedure TConverters.be32_copy(ASource: Pointer; ASourceIndex: Int32;
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
 begin
 begin
-  if TBitConverter.IsLittleEndian then
-  begin
-    swap_copy_str_to_u32(ASource, ASourceIndex, ADestination,
-      ADestinationIndex, ASize)
-  end
-  else
-  begin
-    System.Move(Pointer(PByte(ASource) + ASourceIndex)^,
-      Pointer(PByte(ADestination) + ADestinationIndex)^, ASize);
-  end;
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  swap_copy_str_to_u32(ASource, ASourceIndex, ADestination,
+    ADestinationIndex, ASize)
+{$ELSE}
+  System.Move(Pointer(PByte(ASource) + ASourceIndex)^,
+    Pointer(PByte(ADestination) + ADestinationIndex)^, ASize);
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class procedure TConverters.be64_copy(ASource: Pointer; ASourceIndex: Int32;
 class procedure TConverters.be64_copy(ASource: Pointer; ASourceIndex: Int32;
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
 begin
 begin
-  if TBitConverter.IsLittleEndian then
-  begin
-    swap_copy_str_to_u64(ASource, ASourceIndex, ADestination,
-      ADestinationIndex, ASize)
-  end
-  else
-  begin
-    System.Move(Pointer(PByte(ASource) + ASourceIndex)^,
-      Pointer(PByte(ADestination) + ADestinationIndex)^, ASize);
-  end;
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  swap_copy_str_to_u64(ASource, ASourceIndex, ADestination,
+    ADestinationIndex, ASize)
+{$ELSE}
+  System.Move(Pointer(PByte(ASource) + ASourceIndex)^,
+    Pointer(PByte(ADestination) + ADestinationIndex)^, ASize);
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class function TConverters.le2me_32(AInput: UInt32): UInt32;
 class function TConverters.le2me_32(AInput: UInt32): UInt32;
 begin
 begin
-  if not TBitConverter.IsLittleEndian then
-  begin
-    result := TBits.ReverseBytesUInt32(AInput)
-  end
-  else
-  begin
-    result := AInput;
-  end;
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  result := AInput;
+{$ELSE}
+  result := TBits.ReverseBytesUInt32(AInput);
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class function TConverters.le2me_64(AInput: UInt64): UInt64;
 class function TConverters.le2me_64(AInput: UInt64): UInt64;
 begin
 begin
-  if not TBitConverter.IsLittleEndian then
-  begin
-    result := TBits.ReverseBytesUInt64(AInput)
-  end
-  else
-  begin
-    result := AInput;
-  end;
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  result := AInput;
+{$ELSE}
+  result := TBits.ReverseBytesUInt64(AInput);
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class procedure TConverters.le32_copy(ASource: Pointer; ASourceIndex: Int32;
 class procedure TConverters.le32_copy(ASource: Pointer; ASourceIndex: Int32;
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
 begin
 begin
-  if TBitConverter.IsLittleEndian then
-  begin
-    System.Move(Pointer(PByte(ASource) + ASourceIndex)^,
-      Pointer(PByte(ADestination) + ADestinationIndex)^, ASize)
-  end
-  else
-  begin
-    swap_copy_str_to_u32(ASource, ASourceIndex, ADestination,
-      ADestinationIndex, ASize);
-  end;
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  System.Move((PByte(ASource) + ASourceIndex)^,
+    (PByte(ADestination) + ADestinationIndex)^, ASize)
+{$ELSE}
+  swap_copy_str_to_u32(ASource, ASourceIndex, ADestination,
+    ADestinationIndex, ASize);
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class procedure TConverters.le64_copy(ASource: Pointer; ASourceIndex: Int32;
 class procedure TConverters.le64_copy(ASource: Pointer; ASourceIndex: Int32;
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
   ADestination: Pointer; ADestinationIndex: Int32; ASize: Int32);
 begin
 begin
-  if TBitConverter.IsLittleEndian then
-  begin
-    System.Move(Pointer(PByte(ASource) + ASourceIndex)^,
-      Pointer(PByte(ADestination) + ADestinationIndex)^, ASize)
-  end
-  else
-  begin
-    swap_copy_str_to_u64(ASource, ASourceIndex, ADestination,
-      ADestinationIndex, ASize);
-  end;
-end;
-
-class function TConverters.ReadBytesAsUInt32LE(AInput: PByte;
-  AIndex: Int32): UInt32;
-begin
-{$IFDEF FPC}
-{$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT}
-  System.Move(AInput[AIndex], result, System.SizeOf(UInt32));
-{$ELSE}
-  result := PCardinal(AInput + AIndex)^;
-{$ENDIF FPC_REQUIRES_PROPER_ALIGNMENT}
-{$ELSE}
-  // Delphi does not handle unaligned memory access on ARM Devices properly.
-  System.Move(AInput[AIndex], result, System.SizeOf(UInt32));
-{$ENDIF FPC}
-  result := le2me_32(result);
-end;
-
-class function TConverters.ReadBytesAsUInt64LE(AInput: PByte;
-  AIndex: Int32): UInt64;
-begin
-{$IFDEF FPC}
-{$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT}
-  System.Move(AInput[AIndex], result, System.SizeOf(UInt64));
-{$ELSE}
-  result := PUInt64(AInput + AIndex)^;
-{$ENDIF FPC_REQUIRES_PROPER_ALIGNMENT}
+{$IFDEF HASHLIB_LITTLE_ENDIAN}
+  System.Move((PByte(ASource) + ASourceIndex)^,
+    (PByte(ADestination) + ADestinationIndex)^, ASize)
 {$ELSE}
 {$ELSE}
-  // Delphi does not handle unaligned memory access on ARM Devices properly.
-  System.Move(AInput[AIndex], result, System.SizeOf(UInt64));
-{$ENDIF FPC}
-  result := le2me_64(result);
-end;
-
-class function TConverters.ReadUInt32AsBytesLE(AInput: UInt32)
-  : THashLibByteArray;
-begin
-  result := THashLibByteArray.Create(Byte(AInput), Byte(AInput shr 8),
-    Byte(AInput shr 16), Byte(AInput shr 24));
-end;
-
-class function TConverters.ReadUInt64AsBytesLE(AInput: UInt64)
-  : THashLibByteArray;
-begin
-  result := THashLibByteArray.Create(Byte(AInput), Byte(AInput shr 8),
-    Byte(AInput shr 16), Byte(AInput shr 24), Byte(AInput shr 32),
-    Byte(AInput shr 40), Byte(AInput shr 48), Byte(AInput shr 56));
+  swap_copy_str_to_u64(ASource, ASourceIndex, ADestination,
+    ADestinationIndex, ASize);
+{$ENDIF HASHLIB_LITTLE_ENDIAN}
 end;
 end;
 
 
 class procedure TConverters.ReadUInt32AsBytesLE(AInput: UInt32;
 class procedure TConverters.ReadUInt32AsBytesLE(AInput: UInt32;
@@ -385,55 +315,103 @@ begin
   AOutput[AIndex + 7] := Byte(AInput);
   AOutput[AIndex + 7] := Byte(AInput);
 end;
 end;
 
 
+class function TConverters.ReadBytesAsUInt32BE(AInput: PByte;
+  AIndex: Int32): UInt32;
+begin
+  result := (UInt32(AInput[AIndex]) shl 24) or
+    (UInt32(AInput[AIndex + 1]) shl 16) or (UInt32(AInput[AIndex + 2]) shl 8) or
+    (UInt32(AInput[AIndex + 3]));
+end;
+
+class function TConverters.ReadBytesAsUInt64BE(AInput: PByte;
+  AIndex: Int32): UInt64;
+begin
+  result := (UInt64(AInput[AIndex]) shl 56) or
+    (UInt64(AInput[AIndex + 1]) shl 48) or (UInt64(AInput[AIndex + 2]) shl 40)
+    or (UInt64(AInput[AIndex + 3]) shl 32) or
+    (UInt64(AInput[AIndex + 4]) shl 24) or (UInt64(AInput[AIndex + 5]) shl 16)
+    or (UInt64(AInput[AIndex + 6]) shl 8) or (UInt64(AInput[AIndex + 7]));
+end;
+
+class function TConverters.ReadPCardinalAsUInt32(AInput: PCardinal): UInt32;
+begin
+{$IFDEF HASHLIB_REQUIRES_PROPER_ALIGNMENT}
+  System.Move(AInput^, result, System.SizeOf(UInt32));
+{$ELSE}
+  result := AInput^;
+{$ENDIF HASHLIB_REQUIRES_PROPER_ALIGNMENT}
+end;
+
+class function TConverters.ReadPUInt64AsUInt64(AInput: PUInt64): UInt64;
+begin
+{$IFDEF HASHLIB_REQUIRES_PROPER_ALIGNMENT}
+  System.Move(AInput^, result, System.SizeOf(UInt64));
+{$ELSE}
+  result := AInput^;
+{$ENDIF HASHLIB_REQUIRES_PROPER_ALIGNMENT}
+end;
+
+class function TConverters.ReadPCardinalAsUInt32LE(AInput: PCardinal): UInt32;
+begin
+  result := le2me_32(ReadPCardinalAsUInt32(AInput));
+  // while this below is slower, it's portable
+  // result := (UInt32(AInput[AIndex])) or (UInt32(AInput[AIndex + 1]) shl 8) or
+  // (UInt32(AInput[AIndex + 2]) shl 16) or (UInt32(AInput[AIndex + 3]) shl 24);
+end;
+
+class function TConverters.ReadPUInt64AsUInt64LE(AInput: PUInt64): UInt64;
+begin
+  result := le2me_64(ReadPUInt64AsUInt64(AInput));
+  // while this below is slower, it's portable
+  // result := (UInt64(AInput[AIndex])) or (UInt64(AInput[AIndex + 1]) shl 8) or
+  // (UInt64(AInput[AIndex + 2]) shl 16) or (UInt64(AInput[AIndex + 3]) shl 24)
+  // or (UInt64(AInput[AIndex + 4]) shl 32) or
+  // (UInt64(AInput[AIndex + 5]) shl 40) or (UInt64(AInput[AIndex + 6]) shl 48)
+  // or (UInt64(AInput[AIndex + 7]) shl 56);
+end;
+
+class function TConverters.ReadBytesAsUInt32LE(AInput: PByte;
+  AIndex: Int32): UInt32;
+begin
+  result := ReadPCardinalAsUInt32LE(PCardinal(AInput + AIndex));
+end;
+
+class function TConverters.ReadBytesAsUInt64LE(AInput: PByte;
+  AIndex: Int32): UInt64;
+begin
+  result := ReadPUInt64AsUInt64LE(PUInt64(AInput + AIndex));
+end;
+
+class function TConverters.ReadUInt32AsBytesLE(AInput: UInt32)
+  : THashLibByteArray;
+begin
+  System.SetLength(result, System.SizeOf(UInt32));
+  TConverters.ReadUInt32AsBytesLE(AInput, result, 0);
+end;
+
+class function TConverters.ReadUInt64AsBytesLE(AInput: UInt64)
+  : THashLibByteArray;
+begin
+  System.SetLength(result, System.SizeOf(UInt64));
+  TConverters.ReadUInt64AsBytesLE(AInput, result, 0);
+end;
+
 class function TConverters.ConvertBytesToHexString(const AInput
 class function TConverters.ConvertBytesToHexString(const AInput
   : THashLibByteArray; AGroup: Boolean): String;
   : THashLibByteArray; AGroup: Boolean): String;
-var
-  LIdx: Int32;
-  LHexString, LWorkString: String;
-  LTempArray: THashLibStringArray;
 begin
 begin
-  LHexString := UpperCase(TBitConverter.ToString(AInput));
+  result := UpperCase(TBitConverter.ToString(AInput));
 
 
   if System.length(AInput) = 1 then
   if System.length(AInput) = 1 then
   begin
   begin
-    result := LHexString;
     Exit;
     Exit;
   end;
   end;
 
 
-  if System.length(AInput) = 2 then
+  if (AGroup) then
   begin
   begin
-    result := StringReplace(LHexString, '-', '', [rfIgnoreCase, rfReplaceAll]);
     Exit;
     Exit;
   end;
   end;
 
 
-  if (AGroup) then
-  begin
-{$IFDEF DEBUG}
-    Check(AInput, 1, 4);
-{$ENDIF DEBUG}
-    LWorkString := UpperCase(TBitConverter.ToString(AInput));
-
-    LTempArray := TConverters.SplitString(LWorkString, '-');
-    LHexString := '';
-    LIdx := 0;
-
-    while LIdx < (System.length(LTempArray) shr 2) do
-    begin
-      if (LIdx <> 0) then
-      begin
-        LHexString := LHexString + '-';
-      end;
-      LHexString := LHexString + LTempArray[LIdx * 4] + LTempArray[LIdx * 4 + 1]
-        + LTempArray[LIdx * 4 + 2] + LTempArray[LIdx * 4 + 3];
-      System.Inc(LIdx);
-    end;
-  end
-  else
-  begin
-    LHexString := StringReplace(LHexString, '-', '',
-      [rfIgnoreCase, rfReplaceAll]);
-  end;
-  result := LHexString;
+  result := StringReplace(result, '-', '', [rfIgnoreCase, rfReplaceAll]);
 end;
 end;
 
 
 class function TConverters.ConvertHexStringToBytes(const AInput: String)
 class function TConverters.ConvertHexStringToBytes(const AInput: String)
@@ -486,55 +464,4 @@ begin
 {$ENDIF FPC}
 {$ENDIF FPC}
 end;
 end;
 
 
-class function TConverters.SplitString(const AInput: String; ADelimiter: Char)
-  : THashLibStringArray;
-var
-  LPosStart, LPosSkip, LSplitPoints, LIdx, LLowIndex, LHighIndex,
-    LLength: Int32;
-begin
-  result := Nil;
-  if AInput <> '' then
-  begin
-    { Determine the length of the resulting array }
-    LSplitPoints := 0;
-{$IFDEF DELPHIXE3_UP}
-    LLowIndex := System.Low(AInput);
-    LHighIndex := System.High(AInput);
-{$ELSE}
-    LLowIndex := 1;
-    LHighIndex := System.length(AInput);
-{$ENDIF DELPHIXE3_UP}
-    for LIdx := LLowIndex to LHighIndex do
-    begin
-      if (ADelimiter = AInput[LIdx]) then
-      begin
-        System.Inc(LSplitPoints);
-      end;
-    end;
-
-    System.SetLength(result, LSplitPoints + 1);
-
-    { Split the string and fill the resulting array }
-
-    LIdx := 0;
-    LLength := System.length(ADelimiter);
-{$IFDEF DELPHIXE3_UP}
-    LPosStart := System.Low(AInput);
-    LHighIndex := System.High(AInput);
-{$ELSE}
-    LPosStart := 1;
-    LHighIndex := System.length(AInput);
-{$ENDIF DELPHIXE3_UP}
-    LPosSkip := System.Pos(ADelimiter, AInput);
-    while LPosSkip > 0 do
-    begin
-      result[LIdx] := System.Copy(AInput, LPosStart, LPosSkip - LPosStart);
-      LPosStart := LPosSkip + LLength;
-      LPosSkip := PosEx(ADelimiter, AInput, LPosStart);
-      System.Inc(LIdx);
-    end;
-    result[LIdx] := System.Copy(AInput, LPosStart, LHighIndex);
-  end;
-end;
-
 end.
 end.

+ 0 - 1
src/libraries/hashlib4pascal/HlpGost.pas

@@ -9,7 +9,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpConverters,
   HlpConverters,

+ 0 - 1
src/libraries/hashlib4pascal/HlpGrindahl256.pas

@@ -12,7 +12,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpConverters,
   HlpConverters,
   HlpIHash,
   HlpIHash,

+ 0 - 1
src/libraries/hashlib4pascal/HlpGrindahl512.pas

@@ -12,7 +12,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpConverters,
   HlpConverters,

+ 0 - 1
src/libraries/hashlib4pascal/HlpHAS160.pas

@@ -12,7 +12,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpConverters,
   HlpConverters,
   HlpIHash,
   HlpIHash,

+ 6 - 14
src/libraries/hashlib4pascal/HlpHMACNotBuildInAdapter.pas

@@ -11,33 +11,31 @@ uses
   HlpIHash,
   HlpIHash,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpIHashResult,
   HlpIHashResult,
-  HlpArrayUtils,
-  HlpNullable;
+  HlpArrayUtils;
 
 
 type
 type
 
 
-  THMACNotBuildInAdapter = class sealed(THash, IHMAC, IHMACNotBuildIn, IWithKey,
-    ICrypto, ICryptoNotBuildIn)
+  THMACNotBuildInAdapter = class sealed(THash, IHMAC, IHMACNotBuildIn, ICrypto,
+    ICryptoNotBuildIn)
 
 
   strict private
   strict private
   var
   var
     FHash: IHash;
     FHash: IHash;
     FOpad, FIpad, FKey: THashLibByteArray;
     FOpad, FIpad, FKey: THashLibByteArray;
 
 
+    constructor Create(const AUnderlyingHash: IHash;
+      const AHMACKey: THashLibByteArray);
+
   strict protected
   strict protected
 
 
     function GetName: String; override;
     function GetName: String; override;
 
 
     function GetKey(): THashLibByteArray;
     function GetKey(): THashLibByteArray;
-    function GetKeyLength(): TNullableInteger;
     procedure SetKey(const AValue: THashLibByteArray);
     procedure SetKey(const AValue: THashLibByteArray);
     procedure UpdatePads();
     procedure UpdatePads();
 
 
   public
   public
 
 
-    constructor Create(const AUnderlyingHash: IHash;
-      const AHMACKey: THashLibByteArray = Nil);
-
     destructor Destroy; override;
     destructor Destroy; override;
 
 
     procedure Clear();
     procedure Clear();
@@ -49,7 +47,6 @@ type
     function Clone(): IHash; override;
     function Clone(): IHash; override;
     property Key: THashLibByteArray read GetKey write SetKey;
     property Key: THashLibByteArray read GetKey write SetKey;
     property Name: String read GetName;
     property Name: String read GetName;
-    property KeyLength: TNullableInteger read GetKeyLength;
 
 
     class function CreateHMAC(const AHash: IHash;
     class function CreateHMAC(const AHash: IHash;
       const AHMACKey: THashLibByteArray): IHMAC; static;
       const AHMACKey: THashLibByteArray): IHMAC; static;
@@ -97,11 +94,6 @@ begin
   result := System.Copy(FKey);
   result := System.Copy(FKey);
 end;
 end;
 
 
-function THMACNotBuildInAdapter.GetKeyLength: TNullableInteger;
-begin
-  result := Nil;
-end;
-
 procedure THMACNotBuildInAdapter.SetKey(const AValue: THashLibByteArray);
 procedure THMACNotBuildInAdapter.SetKey(const AValue: THashLibByteArray);
 begin
 begin
   if (AValue = Nil) then
   if (AValue = Nil) then

+ 282 - 76
src/libraries/hashlib4pascal/HlpHashFactory.pas

@@ -47,6 +47,7 @@ uses
   HlpFNV1a64,
   HlpFNV1a64,
   HlpMurmur2_64,
   HlpMurmur2_64,
   HlpSipHash,
   HlpSipHash,
+  HlpSipHash128,
   HlpXXHash64,
   HlpXXHash64,
   // Hash128 Units //
   // Hash128 Units //
   HlpMurmurHash3_x86_128,
   HlpMurmurHash3_x86_128,
@@ -83,13 +84,13 @@ uses
   HlpRIPEMD320,
   HlpRIPEMD320,
   HlpSHA3,
   HlpSHA3,
   HlpBlake2B,
   HlpBlake2B,
-  HlpIBlake2BConfig,
-  HlpBlake2BConfig,
-  HlpIBlake2BTreeConfig,
+  HlpIBlake2BParams,
+  HlpBlake2BParams,
   HlpBlake2S,
   HlpBlake2S,
-  HlpBlake2SConfig,
-  HlpIBlake2SConfig,
-  HlpIBlake2STreeConfig,
+  HlpIBlake2SParams,
+  HlpBlake2SParams,
+  HlpBlake2BP,
+  HlpBlake2SP,
   // HMAC Unit
   // HMAC Unit
   HlpHMACNotBuildInAdapter,
   HlpHMACNotBuildInAdapter,
   // PBKDF2_HMAC Unit
   // PBKDF2_HMAC Unit
@@ -112,61 +113,61 @@ type
 
 
     end;
     end;
 
 
-    // ====================== TCRC ====================== //
-
-  type
-    TCRC = class sealed(TObject)
-
-    public
-
-      class function CreateCRC(AWidth: Int32;
-        APolynomial, AInitialValue: UInt64; AReflectIn, AReflectOut: Boolean;
-        AOutputXor, ACheckValue: UInt64; const ANames: THashLibStringArray)
-        : IHash; overload; static;
-
-      class function CreateCRC(AValue: TCRCStandard): IHash; overload; static;
-
-      class function CreateCRC16(APolynomial, AInitialValue: UInt64;
-        AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
-        const ANames: THashLibStringArray): IHash; static;
-
-      class function CreateCRC32(APolynomial, AInitialValue: UInt64;
-        AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
-        const ANames: THashLibStringArray): IHash; static;
-
-      class function CreateCRC64(APolynomial, AInitialValue: UInt64;
-        AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
-        const ANames: THashLibStringArray): IHash; static;
-
-      /// <summary>
-      /// BUYPASS, polynomial = $8005
-      /// </summary>
-      /// <returns></returns>
-      class function CreateCRC16_BUYPASS(): IHash; static;
-
-      /// <summary>
-      /// PKZIP, polynomial = $04C11DB7, reversed = $EDB88320
-      /// </summary>
-      /// <returns></returns>
-      class function CreateCRC32_PKZIP(): IHash; static;
-      /// <summary>
-      /// Castagnoli, polynomial = $1EDC6F41, reversed = $82F63B78
-      /// </summary>
-      /// <returns></returns>
-      class function CreateCRC32_CASTAGNOLI(): IHash; static;
-      /// <summary>
-      /// ECMA-182, polynomial = $42F0E1EBA9EA3693
-      /// </summary>
-      /// <returns></returns>
-      class function CreateCRC64_ECMA_182(): IHash; static;
-
-    end;
-
     // ====================== TChecksum ====================== //
     // ====================== TChecksum ====================== //
 
 
   type
   type
     TChecksum = class sealed(TObject)
     TChecksum = class sealed(TObject)
 
 
+      // ====================== TCRC ====================== //
+
+    type
+      TCRC = class sealed(TObject)
+
+      public
+
+        class function CreateCRC(AWidth: Int32;
+          APolynomial, AInitialValue: UInt64; AReflectIn, AReflectOut: Boolean;
+          AOutputXor, ACheckValue: UInt64; const ANames: THashLibStringArray)
+          : IHash; overload; static;
+
+        class function CreateCRC(AValue: TCRCStandard): IHash; overload; static;
+
+        class function CreateCRC16(APolynomial, AInitialValue: UInt64;
+          AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
+          const ANames: THashLibStringArray): IHash; static;
+
+        class function CreateCRC32(APolynomial, AInitialValue: UInt64;
+          AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
+          const ANames: THashLibStringArray): IHash; static;
+
+        class function CreateCRC64(APolynomial, AInitialValue: UInt64;
+          AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
+          const ANames: THashLibStringArray): IHash; static;
+
+        /// <summary>
+        /// BUYPASS, polynomial = $8005
+        /// </summary>
+        /// <returns></returns>
+        class function CreateCRC16_BUYPASS(): IHash; static;
+
+        /// <summary>
+        /// PKZIP, polynomial = $04C11DB7, reversed = $EDB88320
+        /// </summary>
+        /// <returns></returns>
+        class function CreateCRC32_PKZIP(): IHash; static;
+        /// <summary>
+        /// Castagnoli, polynomial = $1EDC6F41, reversed = $82F63B78
+        /// </summary>
+        /// <returns></returns>
+        class function CreateCRC32_CASTAGNOLI(): IHash; static;
+        /// <summary>
+        /// ECMA-182, polynomial = $42F0E1EBA9EA3693
+        /// </summary>
+        /// <returns></returns>
+        class function CreateCRC64_ECMA_182(): IHash; static;
+
+      end;
+
     public
     public
 
 
       class function CreateAdler32: IHash; static;
       class function CreateAdler32: IHash; static;
@@ -245,6 +246,7 @@ type
 
 
     public
     public
 
 
+      class function CreateSipHash128_2_4(): IHashWithKey; static;
       class function CreateMurmurHash3_x86_128(): IHashWithKey; static;
       class function CreateMurmurHash3_x86_128(): IHashWithKey; static;
       class function CreateMurmurHash3_x64_128(): IHashWithKey; static;
       class function CreateMurmurHash3_x64_128(): IHashWithKey; static;
 
 
@@ -405,6 +407,12 @@ type
       class function CreateBlake2S_224(): IHash; static;
       class function CreateBlake2S_224(): IHash; static;
       class function CreateBlake2S_256(): IHash; static;
       class function CreateBlake2S_256(): IHash; static;
 
 
+      class function CreateBlake2BP(AHashSize: Int32;
+        const AKey: THashLibByteArray): IHash; static;
+
+      class function CreateBlake2SP(AHashSize: Int32;
+        const AKey: THashLibByteArray): IHash; static;
+
     end;
     end;
 
 
     // ====================== TXOF ====================== //
     // ====================== TXOF ====================== //
@@ -412,10 +420,39 @@ type
   type
   type
     TXOF = class sealed(TObject)
     TXOF = class sealed(TObject)
 
 
+    type
+      TBlake2XSConfig = HlpBlake2S.TBlake2XSConfig;
+
+    type
+      TBlake2XBConfig = HlpBlake2B.TBlake2XBConfig;
+
     public
     public
 
 
-      class function CreateShake_128(AXofSizeInBits: UInt32): IHash; static;
-      class function CreateShake_256(AXofSizeInBits: UInt32): IHash; static;
+      class function CreateShake_128(AXofSizeInBits: UInt64): IHash; static;
+      class function CreateShake_256(AXofSizeInBits: UInt64): IHash; static;
+
+      class function CreateCShake_128(const AN, &AS: THashLibByteArray;
+        AXofSizeInBits: UInt64): IHash; static;
+      class function CreateCShake_256(const AN, &AS: THashLibByteArray;
+        AXofSizeInBits: UInt64): IHash; static;
+
+      class function CreateBlake2XS(const ABlake2XSConfig: TBlake2XSConfig;
+        AXofSizeInBits: UInt64): IHash; overload; static;
+
+      class function CreateBlake2XS(const AKey: THashLibByteArray;
+        AXofSizeInBits: UInt64): IHash; overload; static;
+
+      class function CreateBlake2XB(const ABlake2XBConfig: TBlake2XBConfig;
+        AXofSizeInBits: UInt64): IHash; overload; static;
+
+      class function CreateBlake2XB(const AKey: THashLibByteArray;
+        AXofSizeInBits: UInt64): IHash; overload; static;
+
+      class function CreateKMAC128XOF(const AKMACKey, ACustomization
+        : THashLibByteArray; AXofSizeInBits: UInt64): IHash; static;
+
+      class function CreateKMAC256XOF(const AKMACKey, ACustomization
+        : THashLibByteArray; AXofSizeInBits: UInt64): IHash; static;
 
 
     end;
     end;
 
 
@@ -431,6 +468,45 @@ type
 
 
     end;
     end;
 
 
+    // ====================== TKMAC ====================== //
+
+  type
+    TKMAC = class sealed(TObject)
+
+    public
+
+      class function CreateKMAC128(const AKMACKey, ACustomization
+        : THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC; static;
+
+      class function CreateKMAC256(const AKMACKey, ACustomization
+        : THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC; static;
+
+    end;
+
+    // ====================== TBlake2BMAC ====================== //
+
+  type
+    TBlake2BMAC = class sealed(TObject)
+
+    public
+
+      class function CreateBlake2BMAC(const ABlake2BKey, ASalt, APersonalisation
+        : THashLibByteArray; AOutputLengthInBits: Int32): IBlake2BMAC; static;
+
+    end;
+
+    // ====================== TBlake2SMAC ====================== //
+
+  type
+    TBlake2SMAC = class sealed(TObject)
+
+    public
+
+      class function CreateBlake2SMAC(const ABlake2SKey, ASalt, APersonalisation
+        : THashLibByteArray; AOutputLengthInBits: Int32): IBlake2SMAC; static;
+
+    end;
+
   end;
   end;
 
 
 type
 type
@@ -552,9 +628,9 @@ begin
   Result := TNullDigest.Create();
   Result := TNullDigest.Create();
 end;
 end;
 
 
-{ THashFactory.TCRC }
+{ THashFactory.TChecksum.TCRC }
 
 
-class function THashFactory.TCRC.CreateCRC(AWidth: Int32;
+class function THashFactory.TChecksum.TCRC.CreateCRC(AWidth: Int32;
   APolynomial, AInitialValue: UInt64; AReflectIn, AReflectOut: Boolean;
   APolynomial, AInitialValue: UInt64; AReflectIn, AReflectOut: Boolean;
   AOutputXor, ACheckValue: UInt64; const ANames: THashLibStringArray): IHash;
   AOutputXor, ACheckValue: UInt64; const ANames: THashLibStringArray): IHash;
 begin
 begin
@@ -562,51 +638,52 @@ begin
     AReflectOut, AOutputXor, ACheckValue, ANames);
     AReflectOut, AOutputXor, ACheckValue, ANames);
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC(AValue: TCRCStandard): IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC
+  (AValue: TCRCStandard): IHash;
 begin
 begin
   Result := HlpCRC.TCRC.CreateCRCObject(AValue);
   Result := HlpCRC.TCRC.CreateCRCObject(AValue);
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC16(APolynomial, AInitialValue: UInt64;
-  AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
-  const ANames: THashLibStringArray): IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC16(APolynomial,
+  AInitialValue: UInt64; AReflectIn, AReflectOut: Boolean;
+  AOutputXor, ACheckValue: UInt64; const ANames: THashLibStringArray): IHash;
 begin
 begin
   Result := TCRC16.Create(APolynomial, AInitialValue, AReflectIn, AReflectOut,
   Result := TCRC16.Create(APolynomial, AInitialValue, AReflectIn, AReflectOut,
     AOutputXor, ACheckValue, ANames);
     AOutputXor, ACheckValue, ANames);
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC16_BUYPASS: IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC16_BUYPASS: IHash;
 begin
 begin
   Result := TCRC16_BUYPASS.Create();
   Result := TCRC16_BUYPASS.Create();
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC32(APolynomial, AInitialValue: UInt64;
-  AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
-  const ANames: THashLibStringArray): IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC32(APolynomial,
+  AInitialValue: UInt64; AReflectIn, AReflectOut: Boolean;
+  AOutputXor, ACheckValue: UInt64; const ANames: THashLibStringArray): IHash;
 begin
 begin
   Result := TCRC32.Create(APolynomial, AInitialValue, AReflectIn, AReflectOut,
   Result := TCRC32.Create(APolynomial, AInitialValue, AReflectIn, AReflectOut,
     AOutputXor, ACheckValue, ANames);
     AOutputXor, ACheckValue, ANames);
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC32_CASTAGNOLI: IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC32_CASTAGNOLI: IHash;
 begin
 begin
   Result := HlpCRC32Fast.TCRC32_CASTAGNOLI.Create();
   Result := HlpCRC32Fast.TCRC32_CASTAGNOLI.Create();
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC32_PKZIP: IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC32_PKZIP: IHash;
 begin
 begin
   Result := HlpCRC32Fast.TCRC32_PKZIP.Create();
   Result := HlpCRC32Fast.TCRC32_PKZIP.Create();
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC64(APolynomial, AInitialValue: UInt64;
-  AReflectIn, AReflectOut: Boolean; AOutputXor, ACheckValue: UInt64;
-  const ANames: THashLibStringArray): IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC64(APolynomial,
+  AInitialValue: UInt64; AReflectIn, AReflectOut: Boolean;
+  AOutputXor, ACheckValue: UInt64; const ANames: THashLibStringArray): IHash;
 begin
 begin
   Result := TCRC64.Create(APolynomial, AInitialValue, AReflectIn, AReflectOut,
   Result := TCRC64.Create(APolynomial, AInitialValue, AReflectIn, AReflectOut,
     AOutputXor, ACheckValue, ANames);
     AOutputXor, ACheckValue, ANames);
 end;
 end;
 
 
-class function THashFactory.TCRC.CreateCRC64_ECMA_182: IHash;
+class function THashFactory.TChecksum.TCRC.CreateCRC64_ECMA_182: IHash;
 begin
 begin
   Result := TCRC64_ECMA_182.Create();
   Result := TCRC64_ECMA_182.Create();
 end;
 end;
@@ -759,6 +836,11 @@ begin
   Result := TMurmurHash3_x86_128.Create();
   Result := TMurmurHash3_x86_128.Create();
 end;
 end;
 
 
+class function THashFactory.THash128.CreateSipHash128_2_4: IHashWithKey;
+begin
+  Result := TSipHash128_2_4.Create();
+end;
+
 class function THashFactory.THash128.CreateMurmurHash3_x64_128: IHashWithKey;
 class function THashFactory.THash128.CreateMurmurHash3_x64_128: IHashWithKey;
 begin
 begin
   Result := TMurmurHash3_x64_128.Create();
   Result := TMurmurHash3_x64_128.Create();
@@ -1142,6 +1224,18 @@ begin
     (TBlake2SConfig.Create(THashSize.hsHashSize256));
     (TBlake2SConfig.Create(THashSize.hsHashSize256));
 end;
 end;
 
 
+class function THashFactory.TCrypto.CreateBlake2BP(AHashSize: Int32;
+  const AKey: THashLibByteArray): IHash;
+begin
+  Result := TBlake2BP.Create(AHashSize, AKey);
+end;
+
+class function THashFactory.TCrypto.CreateBlake2SP(AHashSize: Int32;
+  const AKey: THashLibByteArray): IHash;
+begin
+  Result := TBlake2SP.Create(AHashSize, AKey);
+end;
+
 class function THashFactory.TCrypto.CreateSnefru(ASecurityLevel: Int32;
 class function THashFactory.TCrypto.CreateSnefru(ASecurityLevel: Int32;
   AHashSize: THashSize): IHash;
   AHashSize: THashSize): IHash;
 begin
 begin
@@ -1286,7 +1380,7 @@ end;
 
 
 { THashFactory.TXOF }
 { THashFactory.TXOF }
 
 
-class function THashFactory.TXOF.CreateShake_128(AXofSizeInBits: UInt32): IHash;
+class function THashFactory.TXOF.CreateShake_128(AXofSizeInBits: UInt64): IHash;
 var
 var
   LXof: IXOF;
   LXof: IXOF;
 begin
 begin
@@ -1295,7 +1389,7 @@ begin
   Result := LXof as IHash;
   Result := LXof as IHash;
 end;
 end;
 
 
-class function THashFactory.TXOF.CreateShake_256(AXofSizeInBits: UInt32): IHash;
+class function THashFactory.TXOF.CreateShake_256(AXofSizeInBits: UInt64): IHash;
 var
 var
   LXof: IXOF;
   LXof: IXOF;
 begin
 begin
@@ -1304,6 +1398,82 @@ begin
   Result := LXof as IHash;
   Result := LXof as IHash;
 end;
 end;
 
 
+class function THashFactory.TXOF.CreateCShake_128(const AN,
+  &AS: THashLibByteArray; AXofSizeInBits: UInt64): IHash;
+var
+  LXof: IXOF;
+begin
+  LXof := (TCShake_128.Create(AN, &AS) as IXOF);
+  LXof.XOFSizeInBits := AXofSizeInBits;
+  Result := LXof as IHash;
+end;
+
+class function THashFactory.TXOF.CreateCShake_256(const AN,
+  &AS: THashLibByteArray; AXofSizeInBits: UInt64): IHash;
+var
+  LXof: IXOF;
+begin
+  LXof := (TCShake_256.Create(AN, &AS) as IXOF);
+  LXof.XOFSizeInBits := AXofSizeInBits;
+  Result := LXof as IHash;
+end;
+
+class function THashFactory.TXOF.CreateBlake2XS(const ABlake2XSConfig
+  : TBlake2XSConfig; AXofSizeInBits: UInt64): IHash;
+var
+  LXof: IXOF;
+begin
+  LXof := (TBlake2XS.Create(ABlake2XSConfig) as IXOF);
+  LXof.XOFSizeInBits := AXofSizeInBits;
+  Result := LXof as IHash;
+end;
+
+class function THashFactory.TXOF.CreateBlake2XS(const AKey: THashLibByteArray;
+  AXofSizeInBits: UInt64): IHash;
+var
+  LConfig: IBlake2SConfig;
+begin
+  LConfig := TBlake2SConfig.Create(32);
+  LConfig.Key := AKey;
+  Result := CreateBlake2XS(TBlake2XSConfig.Create(LConfig, Nil),
+    AXofSizeInBits);
+end;
+
+class function THashFactory.TXOF.CreateBlake2XB(const ABlake2XBConfig
+  : TBlake2XBConfig; AXofSizeInBits: UInt64): IHash;
+var
+  LXof: IXOF;
+begin
+  LXof := (TBlake2XB.Create(ABlake2XBConfig) as IXOF);
+  LXof.XOFSizeInBits := AXofSizeInBits;
+  Result := LXof as IHash;
+end;
+
+class function THashFactory.TXOF.CreateBlake2XB(const AKey: THashLibByteArray;
+  AXofSizeInBits: UInt64): IHash;
+var
+  LConfig: IBlake2BConfig;
+begin
+  LConfig := TBlake2BConfig.Create(64);
+  LConfig.Key := AKey;
+  Result := CreateBlake2XB(TBlake2XBConfig.Create(LConfig, Nil),
+    AXofSizeInBits);
+end;
+
+class function THashFactory.TXOF.CreateKMAC128XOF(const AKMACKey,
+  ACustomization: THashLibByteArray; AXofSizeInBits: UInt64): IHash;
+begin
+  Result := TKMAC128XOF.CreateKMAC128XOF(AKMACKey, ACustomization,
+    AXofSizeInBits);
+end;
+
+class function THashFactory.TXOF.CreateKMAC256XOF(const AKMACKey,
+  ACustomization: THashLibByteArray; AXofSizeInBits: UInt64): IHash;
+begin
+  Result := TKMAC256XOF.CreateKMAC256XOF(AKMACKey, ACustomization,
+    AXofSizeInBits);
+end;
+
 { THashFactory.THMAC }
 { THashFactory.THMAC }
 
 
 class function THashFactory.THMAC.CreateHMAC(const AHash: IHash;
 class function THashFactory.THMAC.CreateHMAC(const AHash: IHash;
@@ -1312,6 +1482,42 @@ begin
   Result := THMACNotBuildInAdapter.CreateHMAC(AHash, AHMACKey);
   Result := THMACNotBuildInAdapter.CreateHMAC(AHash, AHMACKey);
 end;
 end;
 
 
+{ THashFactory.TKMAC }
+
+class function THashFactory.TKMAC.CreateKMAC128(const AKMACKey,
+  ACustomization: THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC;
+begin
+  Result := TKMAC128.CreateKMAC128(AKMACKey, ACustomization,
+    AOutputLengthInBits);
+end;
+
+class function THashFactory.TKMAC.CreateKMAC256(const AKMACKey,
+  ACustomization: THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC;
+begin
+  Result := TKMAC256.CreateKMAC256(AKMACKey, ACustomization,
+    AOutputLengthInBits);
+end;
+
+{ THashFactory.TBlake2BMAC }
+
+class function THashFactory.TBlake2BMAC.CreateBlake2BMAC(const ABlake2BKey,
+  ASalt, APersonalisation: THashLibByteArray; AOutputLengthInBits: Int32)
+  : IBlake2BMAC;
+begin
+  Result := TBlake2BMACNotBuildInAdapter.CreateBlake2BMAC(ABlake2BKey, ASalt,
+    APersonalisation, AOutputLengthInBits)
+end;
+
+{ THashFactory.TBlake2SMAC }
+
+class function THashFactory.TBlake2SMAC.CreateBlake2SMAC(const ABlake2SKey,
+  ASalt, APersonalisation: THashLibByteArray; AOutputLengthInBits: Int32)
+  : IBlake2SMAC;
+begin
+  Result := TBlake2SMACNotBuildInAdapter.CreateBlake2SMAC(ABlake2SKey, ASalt,
+    APersonalisation, AOutputLengthInBits)
+end;
+
 { TKDF.TPBKDF2_HMAC }
 { TKDF.TPBKDF2_HMAC }
 
 
 class function TKDF.TPBKDF2_HMAC.CreatePBKDF2_HMAC(const AHash: IHash;
 class function TKDF.TPBKDF2_HMAC.CreatePBKDF2_HMAC(const AHash: IHash;

+ 1 - 8
src/libraries/hashlib4pascal/HlpHashLibTypes.pas

@@ -23,17 +23,10 @@ type
   ENotImplementedHashLibException = class(EHashLibException);
   ENotImplementedHashLibException = class(EHashLibException);
   EUnsupportedTypeHashLibException = class(EHashLibException);
   EUnsupportedTypeHashLibException = class(EHashLibException);
 
 
-{$IFDEF HAS_UNITSCOPE}
   /// <summary>
   /// <summary>
   /// Represents a dynamic array of Byte.
   /// Represents a dynamic array of Byte.
   /// </summary>
   /// </summary>
-  THashLibByteArray = System.SysUtils.TBytes
-{$ELSE}
-  /// <summary>
-  /// Represents a dynamic array of Byte.
-  /// </summary>
-    THashLibByteArray = TBytes
-{$ENDIF HAS_UNITSCOPE};
+  THashLibByteArray = TBytes;
 
 
   /// <summary>
   /// <summary>
   /// Represents a dynamic generic array of Type T.
   /// Represents a dynamic generic array of Type T.

+ 6 - 11
src/libraries/hashlib4pascal/HlpHashResult.pas

@@ -70,9 +70,8 @@ implementation
 constructor THashResult.Create(AHash: UInt64);
 constructor THashResult.Create(AHash: UInt64);
 begin
 begin
   Inherited Create();
   Inherited Create();
-  FHash := THashLibByteArray.Create(Byte(AHash shr 56), Byte(AHash shr 48),
-    Byte(AHash shr 40), Byte(AHash shr 32), Byte(AHash shr 24),
-    Byte(AHash shr 16), Byte(AHash shr 8), Byte(AHash));
+  System.SetLength(FHash, System.SizeOf(UInt64));
+  TConverters.ReadUInt64AsBytesBE(AHash, FHash, 0);
 end;
 end;
 
 
 constructor THashResult.Create(const AHash: THashLibByteArray);
 constructor THashResult.Create(const AHash: THashLibByteArray);
@@ -84,8 +83,8 @@ end;
 constructor THashResult.Create(AHash: UInt32);
 constructor THashResult.Create(AHash: UInt32);
 begin
 begin
   Inherited Create();
   Inherited Create();
-  FHash := THashLibByteArray.Create(Byte(AHash shr 24), Byte(AHash shr 16),
-    Byte(AHash shr 8), Byte(AHash));
+  System.SetLength(FHash, System.SizeOf(UInt32));
+  TConverters.ReadUInt32AsBytesBE(AHash, FHash, 0);
 end;
 end;
 
 
 constructor THashResult.Create(AHash: UInt8);
 constructor THashResult.Create(AHash: UInt8);
@@ -221,8 +220,7 @@ begin
     raise EInvalidOperationHashLibException.CreateRes
     raise EInvalidOperationHashLibException.CreateRes
       (@SImpossibleRepresentationUInt32);
       (@SImpossibleRepresentationUInt32);
   end;
   end;
-  result := (UInt32(FHash[0]) shl 24) or (UInt32(FHash[1]) shl 16) or
-    (UInt32(FHash[2]) shl 8) or (UInt32(FHash[3]));
+  result := TConverters.ReadBytesAsUInt32BE(PByte(FHash), 0);
 end;
 end;
 
 
 function THashResult.GetUInt64: UInt64;
 function THashResult.GetUInt64: UInt64;
@@ -232,10 +230,7 @@ begin
     raise EInvalidOperationHashLibException.CreateRes
     raise EInvalidOperationHashLibException.CreateRes
       (@SImpossibleRepresentationUInt64);
       (@SImpossibleRepresentationUInt64);
   end;
   end;
-  result := (UInt64(FHash[0]) shl 56) or (UInt64(FHash[1]) shl 48) or
-    (UInt64(FHash[2]) shl 40) or (UInt64(FHash[3]) shl 32) or
-    (UInt64(FHash[4]) shl 24) or (UInt64(FHash[5]) shl 16) or
-    (UInt64(FHash[6]) shl 8) or (UInt64(FHash[7]));
+  result := TConverters.ReadBytesAsUInt64BE(PByte(FHash), 0);
 end;
 end;
 
 
 function THashResult.ToString(AGroup: Boolean): String;
 function THashResult.ToString(AGroup: Boolean): String;

+ 6 - 36
src/libraries/hashlib4pascal/HlpHaval.pas

@@ -12,7 +12,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpHashSize,
   HlpHashSize,
@@ -34,11 +33,13 @@ type
   const
   const
     HAVAL_VERSION = Int32(1);
     HAVAL_VERSION = Int32(1);
 
 
+  var
+    FRounds: Int32;
+
     procedure TailorDigestBits();
     procedure TailorDigestBits();
 
 
   strict protected
   strict protected
   var
   var
-    FRounds, FHashSize: Int32;
     FHash: THashLibUInt32Array;
     FHash: THashLibUInt32Array;
 
 
     constructor Create(ARounds: THashRounds; AHashSize: THashSize);
     constructor Create(ARounds: THashRounds; AHashSize: THashSize);
@@ -246,7 +247,6 @@ implementation
 constructor THaval.Create(ARounds: THashRounds; AHashSize: THashSize);
 constructor THaval.Create(ARounds: THashRounds; AHashSize: THashSize);
 begin
 begin
   inherited Create(Int32(AHashSize), 128);
   inherited Create(Int32(AHashSize), 128);
-  FHashSize := HashSize;
   System.SetLength(FHash, 8);
   System.SetLength(FHash, 8);
   FRounds := Int32(ARounds);
   FRounds := Int32(ARounds);
 end;
 end;
@@ -272,7 +272,7 @@ begin
 
 
   LPad[LPadIndex] := Byte((FRounds shl 3) or (HAVAL_VERSION and $07));
   LPad[LPadIndex] := Byte((FRounds shl 3) or (HAVAL_VERSION and $07));
   System.Inc(LPadIndex);
   System.Inc(LPadIndex);
-  LPad[LPadIndex] := Byte(FHashSize shl 1);
+  LPad[LPadIndex] := Byte(HashSize shl 1);
   System.Inc(LPadIndex);
   System.Inc(LPadIndex);
 
 
   LBits := TConverters.le2me_64(LBits);
   LBits := TConverters.le2me_64(LBits);
@@ -287,7 +287,7 @@ end;
 function THaval.GetResult: THashLibByteArray;
 function THaval.GetResult: THashLibByteArray;
 begin
 begin
   TailorDigestBits();
   TailorDigestBits();
-  System.SetLength(result, (FHashSize shr 2) * System.SizeOf(UInt32));
+  System.SetLength(result, (HashSize shr 2) * System.SizeOf(UInt32));
   TConverters.le32_copy(PCardinal(FHash), 0, PByte(result), 0,
   TConverters.le32_copy(PCardinal(FHash), 0, PByte(result), 0,
     System.Length(result));
     System.Length(result));
 end;
 end;
@@ -311,7 +311,7 @@ var
   LT: UInt32;
   LT: UInt32;
 begin
 begin
 
 
-  case FHashSize of
+  case HashSize of
     16:
     16:
       begin
       begin
         LT := (FHash[7] and $000000FF) or (FHash[6] and $FF000000) or
         LT := (FHash[7] and $000000FF) or (FHash[6] and $FF000000) or
@@ -2093,8 +2093,6 @@ var
   LHashInstance: THaval_3_128;
   LHashInstance: THaval_3_128;
 begin
 begin
   LHashInstance := THaval_3_128.Create();
   LHashInstance := THaval_3_128.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2114,8 +2112,6 @@ var
   LHashInstance: THaval_4_128;
   LHashInstance: THaval_4_128;
 begin
 begin
   LHashInstance := THaval_4_128.Create();
   LHashInstance := THaval_4_128.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2135,8 +2131,6 @@ var
   LHashInstance: THaval_5_128;
   LHashInstance: THaval_5_128;
 begin
 begin
   LHashInstance := THaval_5_128.Create();
   LHashInstance := THaval_5_128.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2156,8 +2150,6 @@ var
   LHashInstance: THaval_3_160;
   LHashInstance: THaval_3_160;
 begin
 begin
   LHashInstance := THaval_3_160.Create();
   LHashInstance := THaval_3_160.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2177,8 +2169,6 @@ var
   LHashInstance: THaval_4_160;
   LHashInstance: THaval_4_160;
 begin
 begin
   LHashInstance := THaval_4_160.Create();
   LHashInstance := THaval_4_160.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2198,8 +2188,6 @@ var
   LHashInstance: THaval_5_160;
   LHashInstance: THaval_5_160;
 begin
 begin
   LHashInstance := THaval_5_160.Create();
   LHashInstance := THaval_5_160.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2219,8 +2207,6 @@ var
   LHashInstance: THaval_3_192;
   LHashInstance: THaval_3_192;
 begin
 begin
   LHashInstance := THaval_3_192.Create();
   LHashInstance := THaval_3_192.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2240,8 +2226,6 @@ var
   LHashInstance: THaval_4_192;
   LHashInstance: THaval_4_192;
 begin
 begin
   LHashInstance := THaval_4_192.Create();
   LHashInstance := THaval_4_192.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2261,8 +2245,6 @@ var
   LHashInstance: THaval_5_192;
   LHashInstance: THaval_5_192;
 begin
 begin
   LHashInstance := THaval_5_192.Create();
   LHashInstance := THaval_5_192.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2282,8 +2264,6 @@ var
   LHashInstance: THaval_3_224;
   LHashInstance: THaval_3_224;
 begin
 begin
   LHashInstance := THaval_3_224.Create();
   LHashInstance := THaval_3_224.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2303,8 +2283,6 @@ var
   LHashInstance: THaval_4_224;
   LHashInstance: THaval_4_224;
 begin
 begin
   LHashInstance := THaval_4_224.Create();
   LHashInstance := THaval_4_224.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2324,8 +2302,6 @@ var
   LHashInstance: THaval_5_224;
   LHashInstance: THaval_5_224;
 begin
 begin
   LHashInstance := THaval_5_224.Create();
   LHashInstance := THaval_5_224.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2345,8 +2321,6 @@ var
   LHashInstance: THaval_3_256;
   LHashInstance: THaval_3_256;
 begin
 begin
   LHashInstance := THaval_3_256.Create();
   LHashInstance := THaval_3_256.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2366,8 +2340,6 @@ var
   LHashInstance: THaval_4_256;
   LHashInstance: THaval_4_256;
 begin
 begin
   LHashInstance := THaval_4_256.Create();
   LHashInstance := THaval_4_256.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -2387,8 +2359,6 @@ var
   LHashInstance: THaval_5_256;
   LHashInstance: THaval_5_256;
 begin
 begin
   LHashInstance := THaval_5_256.Create();
   LHashInstance := THaval_5_256.Create();
-  LHashInstance.FRounds := FRounds;
-  LHashInstance.FHashSize := FHashSize;
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FHash := System.Copy(FHash);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;

+ 0 - 31
src/libraries/hashlib4pascal/HlpIBlake2BConfig.pas

@@ -1,31 +0,0 @@
-unit HlpIBlake2BConfig;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-  HlpHashLibTypes;
-
-type
-  IBlake2BConfig = interface(IInterface)
-    ['{176861A3-B06E-4CA3-A1BB-DDEAFF40BFE1}']
-    function GetPersonalisation: THashLibByteArray;
-    procedure SetPersonalisation(const AValue: THashLibByteArray);
-    property Personalisation: THashLibByteArray read GetPersonalisation
-      write SetPersonalisation;
-    function GetSalt: THashLibByteArray;
-    procedure SetSalt(const AValue: THashLibByteArray);
-    property Salt: THashLibByteArray read GetSalt write SetSalt;
-    function GetKey: THashLibByteArray;
-    procedure SetKey(const AValue: THashLibByteArray);
-    property Key: THashLibByteArray read GetKey write SetKey;
-    function GetHashSize: Int32;
-    procedure SetHashSize(AValue: Int32);
-    property HashSize: Int32 read GetHashSize write SetHashSize;
-
-  end;
-
-implementation
-
-end.

+ 29 - 1
src/libraries/hashlib4pascal/HlpIBlake2BTreeConfig.pas → src/libraries/hashlib4pascal/HlpIBlake2BParams.pas

@@ -1,9 +1,35 @@
-unit HlpIBlake2BTreeConfig;
+unit HlpIBlake2BParams;
 
 
 {$I HashLib.inc}
 {$I HashLib.inc}
 
 
 interface
 interface
 
 
+uses
+  HlpHashLibTypes;
+
+type
+  IBlake2BConfig = interface(IInterface)
+    ['{176861A3-B06E-4CA3-A1BB-DDEAFF40BFE1}']
+    function GetPersonalisation: THashLibByteArray;
+    procedure SetPersonalisation(const AValue: THashLibByteArray);
+    property Personalisation: THashLibByteArray read GetPersonalisation
+      write SetPersonalisation;
+    function GetSalt: THashLibByteArray;
+    procedure SetSalt(const AValue: THashLibByteArray);
+    property Salt: THashLibByteArray read GetSalt write SetSalt;
+    function GetKey: THashLibByteArray;
+    procedure SetKey(const AValue: THashLibByteArray);
+    property Key: THashLibByteArray read GetKey write SetKey;
+    function GetHashSize: Int32;
+    procedure SetHashSize(AValue: Int32);
+    property HashSize: Int32 read GetHashSize write SetHashSize;
+
+    function Clone(): IBlake2BConfig;
+
+    procedure Clear();
+
+  end;
+
 type
 type
   IBlake2BTreeConfig = interface(IInterface)
   IBlake2BTreeConfig = interface(IInterface)
     ['{3EFB1A70-4478-4375-BAF6-EF17B3673DA8}']
     ['{3EFB1A70-4478-4375-BAF6-EF17B3673DA8}']
@@ -36,6 +62,8 @@ type
     procedure SetIsLastNode(AValue: Boolean);
     procedure SetIsLastNode(AValue: Boolean);
     property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
     property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
 
 
+    function Clone(): IBlake2BTreeConfig;
+
   end;
   end;
 
 
 implementation
 implementation

+ 0 - 31
src/libraries/hashlib4pascal/HlpIBlake2SConfig.pas

@@ -1,31 +0,0 @@
-unit HlpIBlake2SConfig;
-
-{$I HashLib.inc}
-
-interface
-
-uses
-  HlpHashLibTypes;
-
-type
-  IBlake2SConfig = interface(IInterface)
-    ['{C78DE94A-0290-467D-BE26-D0AD1639076C}']
-    function GetPersonalisation: THashLibByteArray;
-    procedure SetPersonalisation(const AValue: THashLibByteArray);
-    property Personalisation: THashLibByteArray read GetPersonalisation
-      write SetPersonalisation;
-    function GetSalt: THashLibByteArray;
-    procedure SetSalt(const AValue: THashLibByteArray);
-    property Salt: THashLibByteArray read GetSalt write SetSalt;
-    function GetKey: THashLibByteArray;
-    procedure SetKey(const AValue: THashLibByteArray);
-    property Key: THashLibByteArray read GetKey write SetKey;
-    function GetHashSize: Int32;
-    procedure SetHashSize(AValue: Int32);
-    property HashSize: Int32 read GetHashSize write SetHashSize;
-
-  end;
-
-implementation
-
-end.

+ 29 - 1
src/libraries/hashlib4pascal/HlpIBlake2STreeConfig.pas → src/libraries/hashlib4pascal/HlpIBlake2SParams.pas

@@ -1,9 +1,35 @@
-unit HlpIBlake2STreeConfig;
+unit HlpIBlake2SParams;
 
 
 {$I HashLib.inc}
 {$I HashLib.inc}
 
 
 interface
 interface
 
 
+uses
+  HlpHashLibTypes;
+
+type
+  IBlake2SConfig = interface(IInterface)
+    ['{C78DE94A-0290-467D-BE26-D0AD1639076C}']
+    function GetPersonalisation: THashLibByteArray;
+    procedure SetPersonalisation(const AValue: THashLibByteArray);
+    property Personalisation: THashLibByteArray read GetPersonalisation
+      write SetPersonalisation;
+    function GetSalt: THashLibByteArray;
+    procedure SetSalt(const AValue: THashLibByteArray);
+    property Salt: THashLibByteArray read GetSalt write SetSalt;
+    function GetKey: THashLibByteArray;
+    procedure SetKey(const AValue: THashLibByteArray);
+    property Key: THashLibByteArray read GetKey write SetKey;
+    function GetHashSize: Int32;
+    procedure SetHashSize(AValue: Int32);
+    property HashSize: Int32 read GetHashSize write SetHashSize;
+
+    function Clone(): IBlake2SConfig;
+
+    procedure Clear();
+
+  end;
+
 type
 type
   IBlake2STreeConfig = interface(IInterface)
   IBlake2STreeConfig = interface(IInterface)
     ['{93635D4F-7104-4E4A-BE9B-C608606F620F}']
     ['{93635D4F-7104-4E4A-BE9B-C608606F620F}']
@@ -36,6 +62,8 @@ type
     procedure SetIsLastNode(AValue: Boolean);
     procedure SetIsLastNode(AValue: Boolean);
     property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
     property IsLastNode: Boolean read GetIsLastNode write SetIsLastNode;
 
 
+    function Clone(): IBlake2STreeConfig;
+
   end;
   end;
 
 
 implementation
 implementation

+ 45 - 12
src/libraries/hashlib4pascal/HlpIHashInfo.pas

@@ -48,6 +48,46 @@ type
 
 
   end;
   end;
 
 
+  IMAC = Interface(IHash)
+    ['{C75C99A1-B7D3-475F-AC39-03386EECC095}']
+    procedure Clear();
+    function GetKey(): THashLibByteArray;
+    procedure SetKey(const AValue: THashLibByteArray);
+    property Key: THashLibByteArray read GetKey write SetKey;
+  end;
+
+  IHMAC = Interface(IMAC)
+    ['{A6D4DCC6-F6C3-4110-8CA2-FBE85227676E}']
+  end;
+
+  IHMACNotBuildIn = Interface(IHMAC)
+    ['{A44E01D3-164E-4E3F-9551-3EFFDE95A36C}']
+  end;
+
+  IKMAC = Interface(IMAC)
+    ['{49309B2F-20C3-4631-BFDD-06373D14CCE0}']
+  end;
+
+  IKMACNotBuildIn = Interface(IKMAC)
+    ['{FC7AF5A9-BD6A-4DBD-B1DD-B6E110B44A20}']
+  end;
+
+  IBlake2BMAC = Interface(IMAC)
+    ['{F6E0B1CA-1497-43C6-9CD9-2628F70E8451}']
+  end;
+
+  IBlake2BMACNotBuildIn = Interface(IBlake2BMAC)
+    ['{20B33EE5-48B4-4F7E-B1B8-1FD7B45E256E}']
+  end;
+
+  IBlake2SMAC = Interface(IMAC)
+    ['{7354FC5C-775C-42E9-9A25-274F62BF2CCE}']
+  end;
+
+  IBlake2SMACNotBuildIn = Interface(IBlake2SMAC)
+    ['{FFB17B7A-86A1-40D7-A5E7-60366FF8513C}']
+  end;
+
   IPBKDF2_HMAC = Interface(IKDF)
   IPBKDF2_HMAC = Interface(IKDF)
     ['{0D409BA8-7F98-4417-858F-3C1EBA11B7E1}']
     ['{0D409BA8-7F98-4417-858F-3C1EBA11B7E1}']
   end;
   end;
@@ -72,15 +112,6 @@ type
     ['{7DD70C4D-FBF6-4629-B587-C6A7CC047D35}']
     ['{7DD70C4D-FBF6-4629-B587-C6A7CC047D35}']
   end;
   end;
 
 
-  IHMAC = Interface(IWithKey)
-    ['{A6D4DCC6-F6C3-4110-8CA2-FBE85227676E}']
-    procedure Clear();
-  end;
-
-  IHMACNotBuildIn = Interface(IHMAC)
-    ['{A44E01D3-164E-4E3F-9551-3EFFDE95A36C}']
-  end;
-
   IHash16 = Interface(IHash)
   IHash16 = Interface(IHash)
     ['{C15AF648-C9F7-460D-9F74-B68CA593C2F8}']
     ['{C15AF648-C9F7-460D-9F74-B68CA593C2F8}']
   end;
   end;
@@ -103,9 +134,11 @@ type
 
 
   IXOF = Interface(IHash)
   IXOF = Interface(IHash)
     ['{944ED7F0-D033-4489-A5DD-9C83353F23F0}']
     ['{944ED7F0-D033-4489-A5DD-9C83353F23F0}']
-    function GetXOFSizeInBits: UInt32;
-    procedure SetXOFSizeInBits(AXofSizeInBits: UInt32);
-    property XOFSizeInBits: UInt32 read GetXOFSizeInBits write SetXOFSizeInBits;
+    function GetXOFSizeInBits: UInt64;
+    procedure SetXOFSizeInBits(AXofSizeInBits: UInt64);
+    property XOFSizeInBits: UInt64 read GetXOFSizeInBits write SetXOFSizeInBits;
+    procedure DoOutput(const ADestination: THashLibByteArray;
+      ADestinationOffset, AOutputLength: UInt64);
   end;
   end;
 
 
 type
 type

+ 0 - 1
src/libraries/hashlib4pascal/HlpMD4.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpMDBase,
   HlpMDBase,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpMD5.pas

@@ -11,7 +11,6 @@ uses
   HlpBits,
   HlpBits,
   HlpMDBase,
   HlpMDBase,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpMDBase.pas

@@ -11,7 +11,6 @@ uses
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpIHashInfo,
   HlpIHashInfo,
   HlpHashCryptoNotBuildIn,
   HlpHashCryptoNotBuildIn,

+ 50 - 55
src/libraries/hashlib4pascal/HlpMurmur2.pas

@@ -24,21 +24,19 @@ resourcestring
   SInvalidKeyLength = 'KeyLength Must Be Equal to %d';
   SInvalidKeyLength = 'KeyLength Must Be Equal to %d';
 
 
 type
 type
-
+  // The original MurmurHash2 32-bit algorithm by Austin Appleby.
   TMurmur2 = class sealed(TMultipleTransformNonBlock, IHash32, IHashWithKey,
   TMurmur2 = class sealed(TMultipleTransformNonBlock, IHash32, IHashWithKey,
     ITransformBlock)
     ITransformBlock)
 
 
   strict private
   strict private
   var
   var
-    FKey, FWorkingKey, FH: UInt32;
+    FKey, FWorkingKey: UInt32;
 
 
   const
   const
     CKEY = UInt32($0);
     CKEY = UInt32($0);
     M = UInt32($5BD1E995);
     M = UInt32($5BD1E995);
     R = Int32(24);
     R = Int32(24);
 
 
-    function InternalComputeBytes(const AData: THashLibByteArray): Int32;
-    procedure TransformUInt32Fast(ABlock: UInt32); inline;
     function GetKeyLength(): TNullableInteger;
     function GetKeyLength(): TNullableInteger;
     function GetKey: THashLibByteArray; inline;
     function GetKey: THashLibByteArray; inline;
     procedure SetKey(const AValue: THashLibByteArray); inline;
     procedure SetKey(const AValue: THashLibByteArray); inline;
@@ -88,16 +86,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TMurmur2.TransformUInt32Fast(ABlock: UInt32);
-begin
-  ABlock := ABlock * M;
-  ABlock := ABlock xor (ABlock shr R);
-  ABlock := ABlock * M;
-
-  FH := FH * M;
-  FH := FH xor ABlock;
-end;
-
 function TMurmur2.GetKeyLength: TNullableInteger;
 function TMurmur2.GetKeyLength: TNullableInteger;
 begin
 begin
   result := 4;
   result := 4;
@@ -109,28 +97,55 @@ begin
   inherited Initialize();
   inherited Initialize();
 end;
 end;
 
 
-function TMurmur2.InternalComputeBytes(const AData: THashLibByteArray): Int32;
+function TMurmur2.Clone(): IHash;
 var
 var
-  LLength, LCurrentIndex: Int32;
-  LBlock: UInt32;
+  LHashInstance: TMurmur2;
+begin
+  LHashInstance := TMurmur2.Create();
+  LHashInstance.FKey := FKey;
+  LHashInstance.FWorkingKey := FWorkingKey;
+  FBuffer.Position := 0;
+  LHashInstance.FBuffer.CopyFrom(FBuffer, FBuffer.Size);
+  result := LHashInstance as IHash;
+  result.BufferSize := BufferSize;
+end;
+
+function TMurmur2.ComputeAggregatedBytes(const AData: THashLibByteArray)
+  : IHashResult;
+var
+  LLength, LCurrentIndex, LNBlocks, LIdx: Int32;
+  LBlock, LH: UInt32;
   LPtrData: PByte;
   LPtrData: PByte;
+  LPtrDataCardinal: PCardinal;
 begin
 begin
   LLength := System.Length(AData);
   LLength := System.Length(AData);
   LPtrData := PByte(AData);
   LPtrData := PByte(AData);
 
 
   if (LLength = 0) then
   if (LLength = 0) then
   begin
   begin
-    result := 0;
+    result := THashResult.Create(Int32(0));
     Exit;
     Exit;
   end;
   end;
 
 
-  FH := FWorkingKey xor UInt32(LLength);
+  LH := FWorkingKey xor UInt32(LLength);
+
   LCurrentIndex := 0;
   LCurrentIndex := 0;
+  LIdx := 0;
+  LPtrDataCardinal := PCardinal(LPtrData);
+  LNBlocks := LLength shr 2;
 
 
-  while (LLength >= 4) do
+  while LIdx < LNBlocks do
   begin
   begin
-    LBlock := TConverters.ReadBytesAsUInt32LE(LPtrData, LCurrentIndex);
-    TransformUInt32Fast(LBlock);
+    LBlock := TConverters.ReadPCardinalAsUInt32LE(LPtrDataCardinal + LIdx);
+
+    LBlock := LBlock * M;
+    LBlock := LBlock xor (LBlock shr R);
+    LBlock := LBlock * M;
+
+    LH := LH * M;
+    LH := LH xor LBlock;
+
+    System.Inc(LIdx);
     System.Inc(LCurrentIndex, 4);
     System.Inc(LCurrentIndex, 4);
     System.Dec(LLength, 4);
     System.Dec(LLength, 4);
   end;
   end;
@@ -138,58 +153,38 @@ begin
   case LLength of
   case LLength of
     3:
     3:
       begin
       begin
-        FH := FH xor (AData[LCurrentIndex + 2] shl 16);
+        LH := LH xor (AData[LCurrentIndex + 2] shl 16);
 
 
-        FH := FH xor (AData[LCurrentIndex + 1] shl 8);
+        LH := LH xor (AData[LCurrentIndex + 1] shl 8);
 
 
-        FH := FH xor (AData[LCurrentIndex]);
+        LH := LH xor (AData[LCurrentIndex]);
 
 
-        FH := FH * M;
+        LH := LH * M;
       end;
       end;
 
 
     2:
     2:
       begin
       begin
-        FH := FH xor (AData[LCurrentIndex + 1] shl 8);
+        LH := LH xor (AData[LCurrentIndex + 1] shl 8);
 
 
-        FH := FH xor (AData[LCurrentIndex]);
+        LH := LH xor (AData[LCurrentIndex]);
 
 
-        FH := FH * M;
+        LH := LH * M;
       end;
       end;
 
 
     1:
     1:
       begin
       begin
-        FH := FH xor (AData[LCurrentIndex]);
+        LH := LH xor (AData[LCurrentIndex]);
 
 
-        FH := FH * M;
+        LH := LH * M;
       end;
       end;
   end;
   end;
 
 
-  FH := FH xor (FH shr 13);
+  LH := LH xor (LH shr 13);
 
 
-  FH := FH * M;
-  FH := FH xor (FH shr 15);
+  LH := LH * M;
+  LH := LH xor (LH shr 15);
 
 
-  result := Int32(FH);
-end;
-
-function TMurmur2.Clone(): IHash;
-var
-  LHashInstance: TMurmur2;
-begin
-  LHashInstance := TMurmur2.Create();
-  LHashInstance.FKey := FKey;
-  LHashInstance.FWorkingKey := FWorkingKey;
-  LHashInstance.FH := FH;
-  FBuffer.Position := 0;
-  LHashInstance.FBuffer.CopyFrom(FBuffer, FBuffer.Size);
-  result := LHashInstance as IHash;
-  result.BufferSize := BufferSize;
-end;
-
-function TMurmur2.ComputeAggregatedBytes(const AData: THashLibByteArray)
-  : IHashResult;
-begin
-  result := THashResult.Create(InternalComputeBytes(AData));
+  result := THashResult.Create(Int32(LH));
 end;
 end;
 
 
 end.
 end.

+ 36 - 54
src/libraries/hashlib4pascal/HlpMurmur2_64.pas

@@ -21,16 +21,16 @@ resourcestring
   SInvalidKeyLength = 'KeyLength Must Be Equal to %d';
   SInvalidKeyLength = 'KeyLength Must Be Equal to %d';
 
 
 type
 type
-
+  // MurmurHash64A (64-bit) algorithm by Austin Appleby.
   TMurmur2_64 = class sealed(TMultipleTransformNonBlock, IHash64, IHashWithKey,
   TMurmur2_64 = class sealed(TMultipleTransformNonBlock, IHash64, IHashWithKey,
     ITransformBlock)
     ITransformBlock)
 
 
   strict private
   strict private
   var
   var
-    FKey, FWorkingKey: UInt32;
+    FKey, FWorkingKey: UInt64;
 
 
   const
   const
-    CKEY = UInt32($0);
+    CKEY = UInt64($0);
 {$IFDEF FPC}
 {$IFDEF FPC}
     // to bypass Internal error (200706094) on FPC, We use "Typed Constant".
     // to bypass Internal error (200706094) on FPC, We use "Typed Constant".
 
 
@@ -78,9 +78,10 @@ end;
 function TMurmur2_64.ComputeAggregatedBytes(const AData: THashLibByteArray)
 function TMurmur2_64.ComputeAggregatedBytes(const AData: THashLibByteArray)
   : IHashResult;
   : IHashResult;
 var
 var
-  LLength, LCurrentIndex: Int32;
+  LLength, LCurrentIndex, LNBlocks, LIdx: Int32;
   LH, LK: UInt64;
   LH, LK: UInt64;
   LPtrData: PByte;
   LPtrData: PByte;
+  LPtrDataUInt64: PUInt64;
 begin
 begin
   LLength := System.length(AData);
   LLength := System.length(AData);
   LPtrData := PByte(AData);
   LPtrData := PByte(AData);
@@ -91,13 +92,15 @@ begin
     Exit;
     Exit;
   end;
   end;
 
 
-  LH := FWorkingKey xor UInt64(LLength);
+  LH := FWorkingKey xor (UInt64(LLength) * M);
   LCurrentIndex := 0;
   LCurrentIndex := 0;
+  LIdx := 0;
+  LPtrDataUInt64 := PUInt64(LPtrData);
+  LNBlocks := LLength shr 3;
 
 
-  while (LLength >= 8) do
+  while LIdx < LNBlocks do
   begin
   begin
-
-    LK := TConverters.ReadBytesAsUInt64LE(LPtrData, LCurrentIndex);
+    LK := TConverters.ReadPUInt64AsUInt64LE(LPtrDataUInt64 + LIdx);
 
 
     LK := LK * M;
     LK := LK * M;
     LK := LK xor (LK shr R);
     LK := LK xor (LK shr R);
@@ -106,31 +109,25 @@ begin
     LH := LH xor LK;
     LH := LH xor LK;
     LH := LH * M;
     LH := LH * M;
 
 
+    System.Inc(LIdx);
     System.Inc(LCurrentIndex, 8);
     System.Inc(LCurrentIndex, 8);
     System.Dec(LLength, 8);
     System.Dec(LLength, 8);
-
   end;
   end;
 
 
   case LLength of
   case LLength of
     7:
     7:
       begin
       begin
-        LH := LH xor ((UInt64(AData[LCurrentIndex]) shl 48));
-        System.Inc(LCurrentIndex);
+        LH := LH xor ((UInt64(AData[LCurrentIndex + 6]) shl 48));
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 40);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 5]) shl 40);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 32);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 4]) shl 32);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 24);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 3]) shl 24);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 16);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 2]) shl 16);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 8);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 1]) shl 8);
 
 
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH xor UInt64(AData[LCurrentIndex]);
 
 
@@ -139,20 +136,15 @@ begin
 
 
     6:
     6:
       begin
       begin
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 40);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 5]) shl 40);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 32);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 4]) shl 32);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 24);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 3]) shl 24);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 16);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 2]) shl 16);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 8);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 1]) shl 8);
 
 
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH xor UInt64(AData[LCurrentIndex]);
 
 
@@ -161,17 +153,13 @@ begin
 
 
     5:
     5:
       begin
       begin
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 32);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 4]) shl 32);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 24);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 3]) shl 24);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 16);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 2]) shl 16);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 8);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 1]) shl 8);
 
 
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH * M;
         LH := LH * M;
@@ -179,14 +167,11 @@ begin
 
 
     4:
     4:
       begin
       begin
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 24);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 3]) shl 24);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 16);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 2]) shl 16);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 8);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 1]) shl 8);
 
 
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH * M;
         LH := LH * M;
@@ -194,11 +179,9 @@ begin
 
 
     3:
     3:
       begin
       begin
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 16);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 2]) shl 16);
 
 
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 8);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 1]) shl 8);
 
 
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH * M;
         LH := LH * M;
@@ -206,8 +189,7 @@ begin
 
 
     2:
     2:
       begin
       begin
-        LH := LH xor (UInt64(AData[LCurrentIndex]) shl 8);
-        System.Inc(LCurrentIndex);
+        LH := LH xor (UInt64(AData[LCurrentIndex + 1]) shl 8);
 
 
         LH := LH xor UInt64(AData[LCurrentIndex]);
         LH := LH xor UInt64(AData[LCurrentIndex]);
 
 
@@ -238,12 +220,12 @@ end;
 
 
 function TMurmur2_64.GetKey: THashLibByteArray;
 function TMurmur2_64.GetKey: THashLibByteArray;
 begin
 begin
-  result := TConverters.ReadUInt32AsBytesLE(FKey);
+  result := TConverters.ReadUInt64AsBytesLE(FKey);
 end;
 end;
 
 
 function TMurmur2_64.GetKeyLength: TNullableInteger;
 function TMurmur2_64.GetKeyLength: TNullableInteger;
 begin
 begin
-  result := 4;
+  result := 8;
 end;
 end;
 
 
 procedure TMurmur2_64.Initialize;
 procedure TMurmur2_64.Initialize;
@@ -265,7 +247,7 @@ begin
       raise EArgumentHashLibException.CreateResFmt(@SInvalidKeyLength,
       raise EArgumentHashLibException.CreateResFmt(@SInvalidKeyLength,
         [KeyLength.value]);
         [KeyLength.value]);
     end;
     end;
-    FKey := TConverters.ReadBytesAsUInt32LE(PByte(AValue), 0);
+    FKey := TConverters.ReadBytesAsUInt64LE(PByte(AValue), 0);
   end;
   end;
 end;
 end;
 
 

+ 25 - 27
src/libraries/hashlib4pascal/HlpMurmurHash3_x64_128.pas

@@ -8,9 +8,6 @@ uses
 {$IFDEF DELPHI2010}
 {$IFDEF DELPHI2010}
   SysUtils, // to get rid of compiler hint "not inlined" on Delphi 2010.
   SysUtils, // to get rid of compiler hint "not inlined" on Delphi 2010.
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
   HlpHashLibTypes,
   HlpHashLibTypes,
   HlpConverters,
   HlpConverters,
   HlpIHashInfo,
   HlpIHashInfo,
@@ -416,8 +413,9 @@ procedure TMurmurHash3_x64_128.TransformBytes(const AData: THashLibByteArray;
   AIndex, ALength: Int32);
   AIndex, ALength: Int32);
 var
 var
   LLength, LNBlocks, LIndex, LOffset, LIdx: Int32;
   LLength, LNBlocks, LIndex, LOffset, LIdx: Int32;
-  LK1, LK2: UInt64;
+  LK1, LK2, LH1, LH2: UInt64;
   LPtrData: PByte;
   LPtrData: PByte;
+  LPtrDataUInt64: PUInt64;
 begin
 begin
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
   System.Assert(AIndex >= 0);
   System.Assert(AIndex >= 0);
@@ -458,38 +456,41 @@ begin
 
 
   // body
   // body
 
 
+  LH1 := FH1;
+  LH2 := FH2;
+  LPtrDataUInt64 := PUInt64(LPtrData + AIndex);
   while LIndex < LNBlocks do
   while LIndex < LNBlocks do
   begin
   begin
 
 
-    LK1 := TConverters.ReadBytesAsUInt64LE(LPtrData, AIndex + LIdx);
-
-    System.Inc(LIdx, 8);
-
-    LK2 := TConverters.ReadBytesAsUInt64LE(LPtrData, AIndex + LIdx);
-
-    System.Inc(LIdx, 8);
+    LK1 := TConverters.ReadPUInt64AsUInt64LE(LPtrDataUInt64 + LIdx);
+    System.Inc(LIdx);
+    LK2 := TConverters.ReadPUInt64AsUInt64LE(LPtrDataUInt64 + LIdx);
+    System.Inc(LIdx);
 
 
     LK1 := LK1 * C1;
     LK1 := LK1 * C1;
     LK1 := TBits.RotateLeft64(LK1, 31);
     LK1 := TBits.RotateLeft64(LK1, 31);
     LK1 := LK1 * C2;
     LK1 := LK1 * C2;
-    FH1 := FH1 xor LK1;
+    LH1 := LH1 xor LK1;
 
 
-    FH1 := TBits.RotateLeft64(FH1, 27);
-    FH1 := FH1 + FH2;
-    FH1 := FH1 * 5 + C3;
+    LH1 := TBits.RotateLeft64(LH1, 27);
+    LH1 := LH1 + LH2;
+    LH1 := LH1 * 5 + C3;
 
 
     LK2 := LK2 * C2;
     LK2 := LK2 * C2;
     LK2 := TBits.RotateLeft64(LK2, 33);
     LK2 := TBits.RotateLeft64(LK2, 33);
     LK2 := LK2 * C1;
     LK2 := LK2 * C1;
-    FH2 := FH2 xor LK2;
+    LH2 := LH2 xor LK2;
 
 
-    FH2 := TBits.RotateLeft64(FH2, 31);
-    FH2 := FH2 + FH1;
-    FH2 := FH2 * 5 + C4;
+    LH2 := TBits.RotateLeft64(LH2, 31);
+    LH2 := LH2 + LH1;
+    LH2 := LH2 * 5 + C4;
 
 
     System.Inc(LIndex);
     System.Inc(LIndex);
   end;
   end;
 
 
+  FH1 := LH1;
+  FH2 := LH2;
+
   LOffset := AIndex + (LIndex * 16);
   LOffset := AIndex + (LIndex * 16);
 
 
   while (LOffset < (AIndex + LLength)) do
   while (LOffset < (AIndex + LLength)) do
@@ -501,18 +502,15 @@ end;
 
 
 function TMurmurHash3_x64_128.TransformFinal: IHashResult;
 function TMurmurHash3_x64_128.TransformFinal: IHashResult;
 var
 var
-  LBufferByte: THashLibByteArray;
-  LBufferUInt64: THashLibUInt64Array;
+  LBufferBytes: THashLibByteArray;
 begin
 begin
   Finish();
   Finish();
-  LBufferUInt64 := THashLibUInt64Array.Create(FH1, FH2);
-  System.SetLength(LBufferByte, System.length(LBufferUInt64) *
-    System.SizeOf(UInt64));
-  TConverters.be64_copy(PUInt64(LBufferUInt64), 0, PByte(LBufferByte), 0,
-    System.length(LBufferByte));
 
 
-  result := THashResult.Create(LBufferByte);
+  System.SetLength(LBufferBytes, HashSize);
+  TConverters.ReadUInt64AsBytesBE(FH1, LBufferBytes, 0);
+  TConverters.ReadUInt64AsBytesBE(FH2, LBufferBytes, 8);
 
 
+  result := THashResult.Create(LBufferBytes);
   Initialize();
   Initialize();
 end;
 end;
 
 

+ 43 - 36
src/libraries/hashlib4pascal/HlpMurmurHash3_x86_128.pas

@@ -12,9 +12,6 @@ uses
   HlpConverters,
   HlpConverters,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpNullable,
   HlpNullable,
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
   HlpHash,
   HlpHash,
   HlpIHash,
   HlpIHash,
   HlpHashResult,
   HlpHashResult,
@@ -468,8 +465,9 @@ procedure TMurmurHash3_x86_128.TransformBytes(const AData: THashLibByteArray;
   AIndex, ALength: Int32);
   AIndex, ALength: Int32);
 var
 var
   LLength, LNBlocks, LIndex, LOffset, LIdx: Int32;
   LLength, LNBlocks, LIndex, LOffset, LIdx: Int32;
-  LK1, LK2, LK3, LK4: UInt32;
+  LK1, LK2, LK3, LK4, LH1, LH2, LH3, LH4: UInt32;
   LPtrData: PByte;
   LPtrData: PByte;
+  LPtrDataCardinal: PCardinal;
 begin
 begin
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
   System.Assert(AIndex >= 0);
   System.Assert(AIndex >= 0);
@@ -510,61 +508,71 @@ begin
 
 
   // body
   // body
 
 
+  LH1 := FH1;
+  LH2 := FH2;
+  LH3 := FH3;
+  LH4 := FH4;
+  LPtrDataCardinal := PCardinal(LPtrData + AIndex);
   while LIndex < LNBlocks do
   while LIndex < LNBlocks do
   begin
   begin
 
 
-    LK1 := TConverters.ReadBytesAsUInt32LE(LPtrData, AIndex + LIdx);
-    System.Inc(LIdx, 4);
-    LK2 := TConverters.ReadBytesAsUInt32LE(LPtrData, AIndex + LIdx);
-    System.Inc(LIdx, 4);
-    LK3 := TConverters.ReadBytesAsUInt32LE(LPtrData, AIndex + LIdx);
-    System.Inc(LIdx, 4);
-    LK4 := TConverters.ReadBytesAsUInt32LE(LPtrData, AIndex + LIdx);
-    System.Inc(LIdx, 4);
+    LK1 := TConverters.ReadPCardinalAsUInt32LE(LPtrDataCardinal + LIdx);
+    System.Inc(LIdx);
+    LK2 := TConverters.ReadPCardinalAsUInt32LE(LPtrDataCardinal + LIdx);
+    System.Inc(LIdx);
+    LK3 := TConverters.ReadPCardinalAsUInt32LE(LPtrDataCardinal + LIdx);
+    System.Inc(LIdx);
+    LK4 := TConverters.ReadPCardinalAsUInt32LE(LPtrDataCardinal + LIdx);
+    System.Inc(LIdx);
 
 
     LK1 := LK1 * C1;
     LK1 := LK1 * C1;
     LK1 := TBits.RotateLeft32(LK1, 15);
     LK1 := TBits.RotateLeft32(LK1, 15);
     LK1 := LK1 * C2;
     LK1 := LK1 * C2;
-    FH1 := FH1 xor LK1;
+    LH1 := LH1 xor LK1;
 
 
-    FH1 := TBits.RotateLeft32(FH1, 19);
+    LH1 := TBits.RotateLeft32(LH1, 19);
 
 
-    FH1 := FH1 + FH2;
-    FH1 := FH1 * 5 + C7;
+    LH1 := LH1 + LH2;
+    LH1 := LH1 * 5 + C7;
 
 
     LK2 := LK2 * C2;
     LK2 := LK2 * C2;
     LK2 := TBits.RotateLeft32(LK2, 16);
     LK2 := TBits.RotateLeft32(LK2, 16);
     LK2 := LK2 * C3;
     LK2 := LK2 * C3;
-    FH2 := FH2 xor LK2;
+    LH2 := LH2 xor LK2;
 
 
-    FH2 := TBits.RotateLeft32(FH2, 17);
+    LH2 := TBits.RotateLeft32(LH2, 17);
 
 
-    FH2 := FH2 + FH3;
-    FH2 := FH2 * 5 + C8;
+    LH2 := LH2 + LH3;
+    LH2 := LH2 * 5 + C8;
 
 
     LK3 := LK3 * C3;
     LK3 := LK3 * C3;
     LK3 := TBits.RotateLeft32(LK3, 17);
     LK3 := TBits.RotateLeft32(LK3, 17);
     LK3 := LK3 * C4;
     LK3 := LK3 * C4;
-    FH3 := FH3 xor LK3;
+    LH3 := LH3 xor LK3;
 
 
-    FH3 := TBits.RotateLeft32(FH3, 15);
+    LH3 := TBits.RotateLeft32(LH3, 15);
 
 
-    FH3 := FH3 + FH4;
-    FH3 := FH3 * 5 + C9;
+    LH3 := LH3 + LH4;
+    LH3 := LH3 * 5 + C9;
 
 
     LK4 := LK4 * C4;
     LK4 := LK4 * C4;
     LK4 := TBits.RotateLeft32(LK4, 18);
     LK4 := TBits.RotateLeft32(LK4, 18);
     LK4 := LK4 * C1;
     LK4 := LK4 * C1;
-    FH4 := FH4 xor LK4;
+    LH4 := LH4 xor LK4;
 
 
-    FH4 := TBits.RotateLeft32(FH4, 13);
+    LH4 := TBits.RotateLeft32(LH4, 13);
 
 
-    FH4 := FH4 + FH1;
-    FH4 := FH4 * 5 + C10;
+    LH4 := LH4 + LH1;
+    LH4 := LH4 * 5 + C10;
 
 
     System.Inc(LIndex);
     System.Inc(LIndex);
   end;
   end;
 
 
+  FH1 := LH1;
+  FH2 := LH2;
+  FH3 := LH3;
+  FH4 := LH4;
+
   LOffset := AIndex + (LIndex * 16);
   LOffset := AIndex + (LIndex * 16);
 
 
   while LOffset < (AIndex + LLength) do
   while LOffset < (AIndex + LLength) do
@@ -577,18 +585,17 @@ end;
 
 
 function TMurmurHash3_x86_128.TransformFinal: IHashResult;
 function TMurmurHash3_x86_128.TransformFinal: IHashResult;
 var
 var
-  LBufferByte: THashLibByteArray;
-  LBufferUInt32: THashLibUInt32Array;
+  LBufferBytes: THashLibByteArray;
 begin
 begin
   Finish();
   Finish();
-  LBufferUInt32 := THashLibUInt32Array.Create(FH1, FH2, FH3, FH4);
-  System.SetLength(LBufferByte, System.length(LBufferUInt32) *
-    System.SizeOf(UInt32));
-  TConverters.be32_copy(PCardinal(LBufferUInt32), 0, PByte(LBufferByte), 0,
-    System.length(LBufferByte));
 
 
-  result := THashResult.Create(LBufferByte);
+  System.SetLength(LBufferBytes, HashSize);
+  TConverters.ReadUInt32AsBytesBE(FH1, LBufferBytes, 0);
+  TConverters.ReadUInt32AsBytesBE(FH2, LBufferBytes, 4);
+  TConverters.ReadUInt32AsBytesBE(FH3, LBufferBytes, 8);
+  TConverters.ReadUInt32AsBytesBE(FH4, LBufferBytes, 12);
 
 
+  result := THashResult.Create(LBufferBytes);
   Initialize();
   Initialize();
 end;
 end;
 
 

+ 40 - 39
src/libraries/hashlib4pascal/HlpMurmurHash3_x86_32.pas

@@ -9,9 +9,6 @@ uses
   SysUtils, // to get rid of compiler hint "not inlined" on Delphi 2010.
   SysUtils, // to get rid of compiler hint "not inlined" on Delphi 2010.
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
   HlpConverters,
   HlpConverters,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpNullable,
   HlpNullable,
@@ -35,7 +32,6 @@ type
     FIdx: Int32;
     FIdx: Int32;
     FBuffer: THashLibByteArray;
     FBuffer: THashLibByteArray;
 
 
-    procedure TransformUInt32Fast(ABlock: UInt32); inline;
     procedure ByteUpdate(AByte: Byte); inline;
     procedure ByteUpdate(AByte: Byte); inline;
     procedure Finish();
     procedure Finish();
 
 
@@ -148,33 +144,24 @@ begin
   FH := FH xor (FH shr 16);
   FH := FH xor (FH shr 16);
 end;
 end;
 
 
-procedure TMurmurHash3_x86_32.TransformUInt32Fast(ABlock: UInt32);
-var
-  LBlock: UInt32;
-begin
-  LBlock := ABlock;
-
-  LBlock := LBlock * C1;
-  LBlock := TBits.RotateLeft32(LBlock, 15);
-  LBlock := LBlock * C2;
-
-  FH := FH xor LBlock;
-  FH := TBits.RotateLeft32(FH, 13);
-  FH := (FH * 5) + C3;
-end;
-
 procedure TMurmurHash3_x86_32.ByteUpdate(AByte: Byte);
 procedure TMurmurHash3_x86_32.ByteUpdate(AByte: Byte);
 var
 var
   LBlock: UInt32;
   LBlock: UInt32;
-  LPtrBuffer: PByte;
 begin
 begin
   FBuffer[FIdx] := AByte;
   FBuffer[FIdx] := AByte;
   System.Inc(FIdx);
   System.Inc(FIdx);
   if FIdx >= 4 then
   if FIdx >= 4 then
   begin
   begin
-    LPtrBuffer := PByte(FBuffer);
-    LBlock := TConverters.ReadBytesAsUInt32LE(LPtrBuffer, 0);
-    TransformUInt32Fast(LBlock);
+    LBlock := TConverters.ReadBytesAsUInt32LE(PByte(FBuffer), 0);
+
+    LBlock := LBlock * C1;
+    LBlock := TBits.RotateLeft32(LBlock, 15);
+    LBlock := LBlock * C2;
+
+    FH := FH xor LBlock;
+    FH := TBits.RotateLeft32(FH, 13);
+    FH := (FH * 5) + C3;
+
     FIdx := 0;
     FIdx := 0;
   end;
   end;
 end;
 end;
@@ -217,8 +204,9 @@ procedure TMurmurHash3_x86_32.TransformBytes(const AData: THashLibByteArray;
   AIndex, ALength: Int32);
   AIndex, ALength: Int32);
 var
 var
   LLength, LNBlocks, LIdx, LOffset: Int32;
   LLength, LNBlocks, LIdx, LOffset: Int32;
-  LBlock: UInt32;
-  LPtrData, LPtrBuffer: PByte;
+  LBlock, LH: UInt32;
+  LPtrData: PByte;
+  LPtrDataCardinal: PCardinal;
 begin
 begin
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
   System.Assert(AIndex >= 0);
   System.Assert(AIndex >= 0);
@@ -257,9 +245,16 @@ begin
     end;
     end;
     if (FIdx = 4) then
     if (FIdx = 4) then
     begin
     begin
-      LPtrBuffer := PByte(FBuffer);
-      LBlock := TConverters.ReadBytesAsUInt32LE(LPtrBuffer, 0);
-      TransformUInt32Fast(LBlock);
+      LBlock := TConverters.ReadBytesAsUInt32LE(PByte(FBuffer), 0);
+
+      LBlock := LBlock * C1;
+      LBlock := TBits.RotateLeft32(LBlock, 15);
+      LBlock := LBlock * C2;
+
+      FH := FH xor LBlock;
+      FH := TBits.RotateLeft32(FH, 13);
+      FH := (FH * 5) + C3;
+
       FIdx := 0;
       FIdx := 0;
     end;
     end;
   end
   end
@@ -272,38 +267,44 @@ begin
 
 
   // body
   // body
 
 
+  LH := FH;
+  LPtrDataCardinal := PCardinal(LPtrData + AIndex);
   while LIdx < LNBlocks do
   while LIdx < LNBlocks do
   begin
   begin
-    LBlock := TConverters.ReadBytesAsUInt32LE(LPtrData, AIndex + (LIdx * 4));
-    TransformUInt32Fast(LBlock);
+    LBlock := TConverters.ReadPCardinalAsUInt32LE(LPtrDataCardinal + LIdx);
+
+    LBlock := LBlock * C1;
+    LBlock := TBits.RotateLeft32(LBlock, 15);
+    LBlock := LBlock * C2;
+
+    LH := LH xor LBlock;
+    LH := TBits.RotateLeft32(LH, 13);
+    LH := (LH * 5) + C3;
 
 
     System.Inc(LIdx);
     System.Inc(LIdx);
   end;
   end;
 
 
+  FH := LH;
+
   // save pending end bytes
   // save pending end bytes
   LOffset := AIndex + (LIdx * 4);
   LOffset := AIndex + (LIdx * 4);
   while LOffset < (LLength + AIndex) do
   while LOffset < (LLength + AIndex) do
   begin
   begin
     ByteUpdate(AData[LOffset]);
     ByteUpdate(AData[LOffset]);
     System.Inc(LOffset);
     System.Inc(LOffset);
-
   end;
   end;
 end;
 end;
 
 
 function TMurmurHash3_x86_32.TransformFinal: IHashResult;
 function TMurmurHash3_x86_32.TransformFinal: IHashResult;
 var
 var
-  LBufferByte: THashLibByteArray;
-  LBufferUInt32: THashLibUInt32Array;
+  LBufferBytes: THashLibByteArray;
 begin
 begin
   Finish();
   Finish();
-  LBufferUInt32 := THashLibUInt32Array.Create(FH);
-  System.SetLength(LBufferByte, System.Length(LBufferUInt32) *
-    System.SizeOf(UInt32));
-  TConverters.be32_copy(PCardinal(LBufferUInt32), 0, PByte(LBufferByte), 0,
-    System.Length(LBufferByte));
 
 
-  result := THashResult.Create(LBufferByte);
+  System.SetLength(LBufferBytes, HashSize);
+  TConverters.ReadUInt32AsBytesBE(FH, LBufferBytes, 0);
 
 
+  result := THashResult.Create(LBufferBytes);
   Initialize();
   Initialize();
 end;
 end;
 
 

+ 21 - 5
src/libraries/hashlib4pascal/HlpNullDigest.pas

@@ -14,12 +14,20 @@ uses
   HlpHashResult,
   HlpHashResult,
   HlpIHashResult;
   HlpIHashResult;
 
 
+resourcestring
+  SHashSizeNotImplemented = 'HashSize Not Implemented For "%s"';
+  SBlockSizeNotImplemented = 'BlockSize Not Implemented For "%s"';
+
 type
 type
   TNullDigest = class sealed(THash, ITransformBlock)
   TNullDigest = class sealed(THash, ITransformBlock)
   strict private
   strict private
   var
   var
     FOut: TMemoryStream;
     FOut: TMemoryStream;
 
 
+  strict protected
+    function GetBlockSize: Int32; override;
+    function GetHashSize: Int32; override;
+
   public
   public
     constructor Create();
     constructor Create();
     destructor Destroy(); override;
     destructor Destroy(); override;
@@ -34,6 +42,18 @@ implementation
 
 
 { TNullDigest }
 { TNullDigest }
 
 
+function TNullDigest.GetBlockSize: Int32;
+begin
+  raise ENotImplementedHashLibException.CreateResFmt
+    (@SBlockSizeNotImplemented, [Name]);
+end;
+
+function TNullDigest.GetHashSize: Int32;
+begin
+  raise ENotImplementedHashLibException.CreateResFmt
+    (@SHashSizeNotImplemented, [Name]);
+end;
+
 function TNullDigest.Clone(): IHash;
 function TNullDigest.Clone(): IHash;
 var
 var
   LHashInstance: TNullDigest;
   LHashInstance: TNullDigest;
@@ -59,10 +79,7 @@ end;
 
 
 procedure TNullDigest.Initialize;
 procedure TNullDigest.Initialize;
 begin
 begin
-  FOut.Position := 0;
-  FOut.Size := 0;
-  HashSize := 0;
-  BlockSize := 0;
+  FOut.Clear;
 end;
 end;
 
 
 procedure TNullDigest.TransformBytes(const AData: THashLibByteArray;
 procedure TNullDigest.TransformBytes(const AData: THashLibByteArray;
@@ -71,7 +88,6 @@ begin
   if AData <> Nil then
   if AData <> Nil then
   begin
   begin
     FOut.Write(AData[AIndex], ALength);
     FOut.Write(AData[AIndex], ALength);
-    HashSize := Int32(FOut.Size);
   end;
   end;
 end;
 end;
 
 

+ 7 - 18
src/libraries/hashlib4pascal/HlpPBKDF2_HMACNotBuildInAdapter.pas

@@ -9,7 +9,7 @@ uses
   HlpKDF,
   HlpKDF,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpHMACNotBuildInAdapter,
   HlpHMACNotBuildInAdapter,
-  HlpBitConverter,
+  HlpConverters,
   HlpArrayUtils,
   HlpArrayUtils,
   HlpHashLibTypes;
   HlpHashLibTypes;
 
 
@@ -109,20 +109,9 @@ end;
 
 
 class function TPBKDF2_HMACNotBuildInAdapter.GetBigEndianBytes(AInput: UInt32)
 class function TPBKDF2_HMACNotBuildInAdapter.GetBigEndianBytes(AInput: UInt32)
   : THashLibByteArray;
   : THashLibByteArray;
-var
-  LBytes, LInvertedBytes: THashLibByteArray;
 begin
 begin
-  LBytes := TBitConverter.GetBytes(AInput);
-  LInvertedBytes := THashLibByteArray.Create(LBytes[3], LBytes[2], LBytes[1],
-    LBytes[0]);
-  if TBitConverter.IsLittleEndian then
-  begin
-    result := LInvertedBytes
-  end
-  else
-  begin
-    result := LBytes;
-  end;
+  System.SetLength(Result, System.SizeOf(UInt32));
+  TConverters.ReadUInt32AsBytesBE(AInput, Result, 0);
 end;
 end;
 
 
 function TPBKDF2_HMACNotBuildInAdapter.Func: THashLibByteArray;
 function TPBKDF2_HMACNotBuildInAdapter.Func: THashLibByteArray;
@@ -155,7 +144,7 @@ begin
     System.Inc(LIdx);
     System.Inc(LIdx);
   end;
   end;
   System.Inc(FBlock);
   System.Inc(FBlock);
-  result := LRet;
+  Result := LRet;
 end;
 end;
 
 
 function TPBKDF2_HMACNotBuildInAdapter.GetBytes(AByteCount: Int32)
 function TPBKDF2_HMACNotBuildInAdapter.GetBytes(AByteCount: Int32)
@@ -187,7 +176,7 @@ begin
     begin
     begin
       System.Move(FBuffer[FStartIndex], LKey[0], AByteCount);
       System.Move(FBuffer[FStartIndex], LKey[0], AByteCount);
       FStartIndex := FStartIndex + AByteCount;
       FStartIndex := FStartIndex + AByteCount;
-      result := LKey;
+      Result := LKey;
       Exit;
       Exit;
     end;
     end;
   end;
   end;
@@ -218,11 +207,11 @@ begin
         System.Move(LT_Block[LRemainder], FBuffer[FStartIndex], LRemCount);
         System.Move(LT_Block[LRemainder], FBuffer[FStartIndex], LRemCount);
       end;
       end;
       FEndIndex := FEndIndex + LRemCount;
       FEndIndex := FEndIndex + LRemCount;
-      result := LKey;
+      Result := LKey;
       Exit;
       Exit;
     end;
     end;
   end;
   end;
-  result := LKey;
+  Result := LKey;
 end;
 end;
 
 
 procedure TPBKDF2_HMACNotBuildInAdapter.Initialize;
 procedure TPBKDF2_HMACNotBuildInAdapter.Initialize;

+ 158 - 69
src/libraries/hashlib4pascal/HlpPBKDF_Argon2NotBuildInAdapter.pas

@@ -5,18 +5,24 @@
 interface
 interface
 
 
 uses
 uses
-{$IFDEF HAS_DELPHI_PPL}
+{$IFDEF USE_DELPHI_PPL}
   System.Classes,
   System.Classes,
   System.SysUtils,
   System.SysUtils,
   System.Threading,
   System.Threading,
-{$ENDIF HAS_DELPHI_PPL}
+{$ENDIF USE_DELPHI_PPL}
+{$IFDEF USE_PASMP}
+  PasMP,
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+  MTProcs,
+{$ENDIF USE_MTPROCS}
   HlpKDF,
   HlpKDF,
   HlpBits,
   HlpBits,
   HlpIHash,
   HlpIHash,
   HlpIHashInfo,
   HlpIHashInfo,
   HlpBlake2B,
   HlpBlake2B,
-  HlpBlake2BConfig,
-  HlpIBlake2BConfig,
+  HlpIBlake2BParams,
+  HlpBlake2BParams,
   HlpConverters,
   HlpConverters,
   HlpArgon2TypeAndVersion,
   HlpArgon2TypeAndVersion,
   HlpArrayUtils,
   HlpArrayUtils,
@@ -211,7 +217,7 @@ type
     public
     public
       class function CreateBlock(): TBlock; static;
       class function CreateBlock(): TBlock; static;
 
 
-      function Clear(): TBlock; inline;
+      function Clear(): TBlock;
       procedure &Xor(const AB1, AB2, AB3: TBlock); overload;
       procedure &Xor(const AB1, AB2, AB3: TBlock); overload;
       procedure FromBytes(const AInput: THashLibByteArray);
       procedure FromBytes(const AInput: THashLibByteArray);
 
 
@@ -262,6 +268,13 @@ type
       class function CreateFillBlock(): TFillBlock; static;
       class function CreateFillBlock(): TFillBlock; static;
     end;
     end;
 
 
+  type
+    PDataContainer = ^TDataContainer;
+
+    TDataContainer = record
+      Position: TPosition;
+    end;
+
   var
   var
 
 
     FMemory: THashLibGenericArray<TBlock>;
     FMemory: THashLibGenericArray<TBlock>;
@@ -323,9 +336,19 @@ type
     function GetPrevOffset(ACurrentOffset: Int32): Int32; inline;
     function GetPrevOffset(ACurrentOffset: Int32): Int32; inline;
     function RotatePrevOffset(ACurrentOffset, APrevOffset: Int32)
     function RotatePrevOffset(ACurrentOffset, APrevOffset: Int32)
       : Int32; inline;
       : Int32; inline;
-    procedure FillSegment(const AFiller: TFillBlock; var APosition: TPosition);
-    procedure DoParallelFillMemoryBlocks();
-
+    procedure FillSegment(AIdx: Int32; var APosition: TPosition);
+    procedure FillMemoryBlocks(AIdx: Int32;
+      ADataContainer: PDataContainer); inline;
+    procedure DoParallelFillMemoryBlocks(ADataContainer: PDataContainer);
+{$IFDEF USE_PASMP}
+    procedure PasMPFillMemoryBlocksWrapper(const AJob: PPasMPJob;
+      const AThreadIndex: LongInt; const ADataContainer: Pointer;
+      const AFromIndex, AToIndex: TPasMPNativeInt); inline;
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+    procedure MTProcsFillMemoryBlocksWrapper(AIdx: PtrInt;
+      ADataContainer: Pointer; AItem: TMultiThreadProcItem); inline;
+{$ENDIF USE_MTPROCS}
     (* *
     (* *
 
 
       * H0 = H64(p, τ, m, t, v, y, |P|, P, |S|, S, |L|, K, |X|, X)
       * H0 = H64(p, τ, m, t, v, y, |P|, P, |S|, S, |L|, K, |X|, X)
@@ -1047,7 +1070,16 @@ begin
   result := APrevOffset;
   result := APrevOffset;
 end;
 end;
 
 
-procedure TPBKDF_Argon2NotBuildInAdapter.FillSegment(const AFiller: TFillBlock;
+procedure TPBKDF_Argon2NotBuildInAdapter.Initialize(const APassword
+  : THashLibByteArray; AOutputLength: Int32);
+var
+  LInitialHash: THashLibByteArray;
+begin
+  LInitialHash := InitialHash(FParameters, AOutputLength, APassword);
+  FillFirstBlocks(LInitialHash);
+end;
+
+procedure TPBKDF_Argon2NotBuildInAdapter.FillSegment(AIdx: Int32;
   var APosition: TPosition);
   var APosition: TPosition);
 var
 var
   LAddressBlock, LInputBlock, LZeroBlock, LPrevBlock, LRefBlock,
   LAddressBlock, LInputBlock, LZeroBlock, LPrevBlock, LRefBlock,
@@ -1055,8 +1087,11 @@ var
   LDataIndependentAddressing, LWithXor: Boolean;
   LDataIndependentAddressing, LWithXor: Boolean;
   LStartingIndex, LCurrentOffset, LPrevOffset, LRefLane, LRefColumn: Int32;
   LStartingIndex, LCurrentOffset, LPrevOffset, LRefLane, LRefColumn: Int32;
   LPseudoRandom: UInt64;
   LPseudoRandom: UInt64;
+  LFiller: TFillBlock;
 begin
 begin
-
+  // line below not really needed, just added to fix compiler hint
+  APosition.FLane := AIdx;
+  LFiller := TFillBlock.CreateFillBlock();
   LDataIndependentAddressing := IsDataIndependentAddressing(APosition);
   LDataIndependentAddressing := IsDataIndependentAddressing(APosition);
   LStartingIndex := GetStartingIndex(APosition);
   LStartingIndex := GetStartingIndex(APosition);
   LCurrentOffset := (APosition.FLane * FLaneLength) +
   LCurrentOffset := (APosition.FLane * FLaneLength) +
@@ -1065,11 +1100,11 @@ begin
 
 
   if (LDataIndependentAddressing) then
   if (LDataIndependentAddressing) then
   begin
   begin
-    LAddressBlock := AFiller.AddressBlock.Clear();
-    LZeroBlock := AFiller.ZeroBlock.Clear();
-    LInputBlock := AFiller.InputBlock.Clear();
+    LAddressBlock := LFiller.AddressBlock.Clear();
+    LZeroBlock := LFiller.ZeroBlock.Clear();
+    LInputBlock := LFiller.InputBlock.Clear();
 
 
-    InitAddressBlocks(AFiller, APosition, LZeroBlock, LInputBlock,
+    InitAddressBlocks(LFiller, APosition, LZeroBlock, LInputBlock,
       LAddressBlock);
       LAddressBlock);
   end;
   end;
 
 
@@ -1079,7 +1114,7 @@ begin
   begin
   begin
     LPrevOffset := RotatePrevOffset(LCurrentOffset, LPrevOffset);
     LPrevOffset := RotatePrevOffset(LCurrentOffset, LPrevOffset);
 
 
-    LPseudoRandom := GetPseudoRandom(AFiller, APosition, LAddressBlock,
+    LPseudoRandom := GetPseudoRandom(LFiller, APosition, LAddressBlock,
       LInputBlock, LZeroBlock, LPrevOffset, LDataIndependentAddressing);
       LInputBlock, LZeroBlock, LPrevOffset, LDataIndependentAddressing);
     LRefLane := GetRefLane(APosition, LPseudoRandom);
     LRefLane := GetRefLane(APosition, LPseudoRandom);
     LRefColumn := GetRefColumn(APosition, LPseudoRandom,
     LRefColumn := GetRefColumn(APosition, LPseudoRandom,
@@ -1091,7 +1126,7 @@ begin
     LCurrentBlock := FMemory[LCurrentOffset];
     LCurrentBlock := FMemory[LCurrentOffset];
 
 
     LWithXor := IsWithXor(APosition);
     LWithXor := IsWithXor(APosition);
-    AFiller.FillBlock(LPrevBlock, LRefBlock, LCurrentBlock, LWithXor);
+    LFiller.FillBlock(LPrevBlock, LRefBlock, LCurrentBlock, LWithXor);
 
 
     System.Inc(APosition.FIndex);
     System.Inc(APosition.FIndex);
     System.Inc(LCurrentOffset);
     System.Inc(LCurrentOffset);
@@ -1099,41 +1134,65 @@ begin
   end;
   end;
 end;
 end;
 
 
-{$IFDEF HAS_DELPHI_PPL}
+procedure TPBKDF_Argon2NotBuildInAdapter.FillMemoryBlocks(AIdx: Int32;
+  ADataContainer: PDataContainer);
+var
+  LPosition: TPosition;
+begin
+  LPosition := ADataContainer^.Position;
+  FillSegment(AIdx, LPosition);
+end;
+
+{$IFDEF USE_PASMP}
 
 
-procedure TPBKDF_Argon2NotBuildInAdapter.DoParallelFillMemoryBlocks;
+procedure TPBKDF_Argon2NotBuildInAdapter.PasMPFillMemoryBlocksWrapper
+  (const AJob: PPasMPJob; const AThreadIndex: LongInt;
+  const ADataContainer: Pointer; const AFromIndex, AToIndex: TPasMPNativeInt);
+begin
+  PDataContainer(ADataContainer)^.Position.FLane := AFromIndex;
+  FillMemoryBlocks(AFromIndex, ADataContainer);
+end;
+{$ENDIF}
+{$IFDEF USE_MTPROCS}
+
+procedure TPBKDF_Argon2NotBuildInAdapter.MTProcsFillMemoryBlocksWrapper
+  (AIdx: PtrInt; ADataContainer: Pointer; AItem: TMultiThreadProcItem);
+begin
+  PDataContainer(ADataContainer)^.Position.FLane := AIdx;
+  FillMemoryBlocks(AIdx, ADataContainer);
+end;
+{$ENDIF}
+{$IF DEFINED(USE_DELPHI_PPL)}
+
+procedure TPBKDF_Argon2NotBuildInAdapter.DoParallelFillMemoryBlocks
+  (ADataContainer: PDataContainer);
 
 
-  function CreateTask(AFiller: TFillBlock; APosition: TPosition): ITask;
+  function CreateTask(AIdx: Int32; ADataContainer: PDataContainer): ITask;
   begin
   begin
     result := TTask.Create(
     result := TTask.Create(
       procedure()
       procedure()
       begin
       begin
-        FillSegment(AFiller, APosition);
+        FillMemoryBlocks(AIdx, ADataContainer);
       end);
       end);
   end;
   end;
 
 
 var
 var
-  LIdx, LJdx, LKdx, LTaskIdx: Int32;
-  LFiller: TFillBlock;
-  LPosition: TPosition;
+  LIdx, LJdx, LKdx, LIterations, LLanes: Int32;
   LArrayTasks: array of ITask;
   LArrayTasks: array of ITask;
 begin
 begin
-  System.SetLength(LArrayTasks, FParameters.Lanes);
+  LIterations := FParameters.Iterations;
+  LLanes := FParameters.Lanes;
+  System.SetLength(LArrayTasks, LLanes);
 
 
-  for LIdx := 0 to System.Pred(FParameters.Iterations) do
+  for LIdx := 0 to System.Pred(LIterations) do
   begin
   begin
     for LJdx := 0 to System.Pred(ARGON2_SYNC_POINTS) do
     for LJdx := 0 to System.Pred(ARGON2_SYNC_POINTS) do
     begin
     begin
-      for LKdx := 0 to System.Pred(FParameters.Lanes) do
+      for LKdx := 0 to System.Pred(LLanes) do
       begin
       begin
-        LFiller := TFillBlock.CreateFillBlock();
-        LPosition := TPosition.CreatePosition();
-        LPosition.Update(LIdx, LKdx, LJdx, 0);
-        LArrayTasks[LKdx] := CreateTask(LFiller, LPosition);
-      end;
-      for LTaskIdx := System.Low(LArrayTasks) to System.High(LArrayTasks) do
-      begin
-        LArrayTasks[LTaskIdx].Start;
+        ADataContainer^.Position.Update(LIdx, LKdx, LJdx, 0);
+        LArrayTasks[LKdx] := CreateTask(LKdx, ADataContainer);
+        LArrayTasks[LKdx].Start;
       end;
       end;
       TTask.WaitForAll(LArrayTasks);
       TTask.WaitForAll(LArrayTasks);
     end;
     end;
@@ -1141,38 +1200,85 @@ begin
 
 
 end;
 end;
 
 
+{$ELSEIF DEFINED(USE_PASMP) OR DEFINED(USE_MTPROCS)}
+
+procedure TPBKDF_Argon2NotBuildInAdapter.DoParallelFillMemoryBlocks
+  (ADataContainer: PDataContainer);
+var
+  LIdx, LJdx, LIterations, LLanes: Int32;
+begin
+  LIterations := FParameters.Iterations;
+  LLanes := FParameters.Lanes;
+  for LIdx := 0 to System.Pred(LIterations) do
+  begin
+    for LJdx := 0 to System.Pred(ARGON2_SYNC_POINTS) do
+    begin
+      ADataContainer^.Position.Update(LIdx, 0, LJdx, 0);
+{$IF DEFINED(USE_PASMP)}
+      TPasMP.CreateGlobalInstance;
+      GlobalPasMP.Invoke(GlobalPasMP.ParallelFor(ADataContainer, 0, LLanes - 1,
+        PasMPFillMemoryBlocksWrapper));
+{$ELSEIF DEFINED(USE_MTPROCS)}
+      ProcThreadPool.DoParallel(MTProcsFillMemoryBlocksWrapper, 0, LLanes - 1,
+        ADataContainer);
+{$ELSE}
+{$MESSAGE ERROR 'Unsupported Threading Library.'}
+{$IFEND USE_PASMP}
+    end;
+  end;
+
+end;
+
 {$ELSE}
 {$ELSE}
 
 
-procedure TPBKDF_Argon2NotBuildInAdapter.DoParallelFillMemoryBlocks;
+procedure TPBKDF_Argon2NotBuildInAdapter.DoParallelFillMemoryBlocks
+  (ADataContainer: PDataContainer);
 var
 var
-  LIdx, LJdx, LKdx: Int32;
-  LFiller: TFillBlock;
-  LPosition: TPosition;
+  LIdx, LJdx, LKdx, LIterations, LLanes: Int32;
 begin
 begin
-  LFiller := TFillBlock.CreateFillBlock();
-  LPosition := TPosition.CreatePosition();
-  for LIdx := 0 to System.Pred(FParameters.Iterations) do
+  LIterations := FParameters.Iterations;
+  LLanes := FParameters.Lanes;
+  for LIdx := 0 to System.Pred(LIterations) do
   begin
   begin
     for LJdx := 0 to System.Pred(ARGON2_SYNC_POINTS) do
     for LJdx := 0 to System.Pred(ARGON2_SYNC_POINTS) do
     begin
     begin
-      for LKdx := 0 to System.Pred(FParameters.Lanes) do
+      for LKdx := 0 to System.Pred(LLanes) do
       begin
       begin
-        LPosition.Update(LIdx, LKdx, LJdx, 0);
-        FillSegment(LFiller, LPosition);
+        ADataContainer^.Position.Update(LIdx, LKdx, LJdx, 0);
+        FillMemoryBlocks(LKdx, ADataContainer);
       end;
       end;
     end;
     end;
   end;
   end;
 end;
 end;
 
 
-{$ENDIF HAS_DELPHI_PPL}
+{$IFEND USE_DELPHI_PPL}
 
 
-procedure TPBKDF_Argon2NotBuildInAdapter.Initialize(const APassword
-  : THashLibByteArray; AOutputLength: Int32);
+function TPBKDF_Argon2NotBuildInAdapter.GetBytes(AByteCount: Int32)
+  : THashLibByteArray;
 var
 var
-  LInitialHash: THashLibByteArray;
+  LPtrDataContainer: PDataContainer;
+  LPosition: TPosition;
 begin
 begin
-  LInitialHash := InitialHash(FParameters, AOutputLength, APassword);
-  FillFirstBlocks(LInitialHash);
+  if (AByteCount <= MIN_OUTLEN) then
+  begin
+    raise EArgumentHashLibException.CreateResFmt(@SInvalidOutputByteCount,
+      [MIN_OUTLEN]);
+  end;
+
+  Initialize(FPassword, AByteCount);
+  LPosition := TPosition.CreatePosition();
+  LPtrDataContainer := New(PDataContainer);
+  try
+    LPtrDataContainer^.Position := LPosition;
+    DoParallelFillMemoryBlocks(LPtrDataContainer);
+  finally
+    Dispose(LPtrDataContainer);
+  end;
+  Digest(AByteCount);
+  System.SetLength(result, AByteCount);
+  System.Move(FResult[0], result[0], AByteCount * System.SizeOf(Byte));
+
+  Reset();
 end;
 end;
 
 
 procedure TPBKDF_Argon2NotBuildInAdapter.Clear();
 procedure TPBKDF_Argon2NotBuildInAdapter.Clear();
@@ -1218,24 +1324,6 @@ begin
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-function TPBKDF_Argon2NotBuildInAdapter.GetBytes(AByteCount: Int32)
-  : THashLibByteArray;
-begin
-  if (AByteCount <= MIN_OUTLEN) then
-  begin
-    raise EArgumentHashLibException.CreateResFmt(@SInvalidOutputByteCount,
-      [MIN_OUTLEN]);
-  end;
-
-  Initialize(FPassword, AByteCount);
-  DoParallelFillMemoryBlocks();
-  Digest(AByteCount);
-  System.SetLength(result, AByteCount);
-  System.Move(FResult[0], result[0], AByteCount * System.SizeOf(Byte));
-
-  Reset();
-end;
-
 { TPBKDF_Argon2NotBuildInAdapter.TBlock }
 { TPBKDF_Argon2NotBuildInAdapter.TBlock }
 
 
 class function TPBKDF_Argon2NotBuildInAdapter.TBlock.CreateBlock: TBlock;
 class function TPBKDF_Argon2NotBuildInAdapter.TBlock.CreateBlock: TBlock;
@@ -1254,7 +1342,8 @@ begin
   begin
   begin
     if not(LBlock.FInitialized) then
     if not(LBlock.FInitialized) then
     begin
     begin
-      raise EArgumentNilHashLibException.Create(SBlockInstanceNotInitialized);
+      raise EArgumentNilHashLibException.CreateRes
+        (@SBlockInstanceNotInitialized);
     end;
     end;
   end;
   end;
 end;
 end;

+ 114 - 44
src/libraries/hashlib4pascal/HlpPBKDF_ScryptNotBuildInAdapter.pas

@@ -5,14 +5,17 @@ unit HlpPBKDF_ScryptNotBuildInAdapter;
 interface
 interface
 
 
 uses
 uses
-{$IFDEF HAS_DELPHI_PPL}
+{$IFDEF USE_DELPHI_PPL}
   System.Classes,
   System.Classes,
   System.SysUtils,
   System.SysUtils,
   System.Threading,
   System.Threading,
-{$ENDIF HAS_DELPHI_PPL}
-{$IFDEF DELPHI}
-  HlpBitConverter,
-{$ENDIF DELPHI}
+{$ENDIF USE_DELPHI_PPL}
+{$IFDEF USE_PASMP}
+  PasMP,
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+  MTProcs,
+{$ENDIF USE_MTPROCS}
   HlpIHash,
   HlpIHash,
   HlpKDF,
   HlpKDF,
   HlpBits,
   HlpBits,
@@ -43,6 +46,14 @@ type
     IPBKDF_ScryptNotBuildIn)
     IPBKDF_ScryptNotBuildIn)
 
 
   strict private
   strict private
+  type
+    PDataContainer = ^TDataContainer;
+
+    TDataContainer = record
+      PtrB: PCardinal;
+      Parallelism, Cost, BlockSize: Int32;
+    end;
+
   var
   var
     FPasswordBytes, FSaltBytes: THashLibByteArray;
     FPasswordBytes, FSaltBytes: THashLibByteArray;
     FCost, FBlockSize, FParallelism: Int32;
     FCost, FBlockSize, FParallelism: Int32;
@@ -86,15 +97,23 @@ type
     class procedure &Xor(const Aa, Ab: THashLibUInt32Array; AbOff: Int32;
     class procedure &Xor(const Aa, Ab: THashLibUInt32Array; AbOff: Int32;
       const AOutput: THashLibUInt32Array); static;
       const AOutput: THashLibUInt32Array); static;
 
 
-    class procedure SMix(const Ab: THashLibUInt32Array;
-      AbOff, AN, AR: Int32); static;
+    class procedure SMix(AIdx: Int32;
+      APtrDataContainer: PDataContainer); static;
 
 
     class procedure BlockMix(const Ab, AX1, AX2, Ay: THashLibUInt32Array;
     class procedure BlockMix(const Ab, AX1, AX2, Ay: THashLibUInt32Array;
       AR: Int32); static;
       AR: Int32); static;
 
 
-    class procedure DoSMix(const Ab: THashLibUInt32Array;
-      AParallelism, ACost, ABlockSize: Int32); static;
-
+    class procedure DoParallelSMix(ADataContainer: PDataContainer); static;
+
+{$IFDEF USE_PASMP}
+    class procedure PasMPSMixWrapper(const AJob: PPasMPJob;
+      const AThreadIndex: LongInt; const ADataContainer: Pointer;
+      const AFromIndex, AToIndex: TPasMPNativeInt); inline;
+{$ENDIF USE_PASMP}
+{$IFDEF USE_MTPROCS}
+    class procedure MTProcsSMixWrapper(AIdx: PtrInt; ADataContainer: Pointer;
+      AItem: TMultiThreadProcItem); inline;
+{$ENDIF USE_MTPROCS}
     class function MFCrypt(const APasswordBytes, ASaltBytes: THashLibByteArray;
     class function MFCrypt(const APasswordBytes, ASaltBytes: THashLibByteArray;
       ACost, ABlockSize, AParallelism, AOutputLength: Int32)
       ACost, ABlockSize, AParallelism, AOutputLength: Int32)
       : THashLibByteArray; static;
       : THashLibByteArray; static;
@@ -303,52 +322,57 @@ begin
   end;
   end;
 end;
 end;
 
 
-class procedure TPBKDF_ScryptNotBuildInAdapter.SMix
-  (const Ab: THashLibUInt32Array; AbOff, AN, AR: Int32);
+class procedure TPBKDF_ScryptNotBuildInAdapter.SMix(AIdx: Int32;
+  APtrDataContainer: PDataContainer);
 var
 var
-  LBCount, LIdx, LJdx, LOffset: Int32;
+  LBCount, LIdx, LJdx, LOffset, LBlockSize, LCost: Int32;
   LMask: UInt32;
   LMask: UInt32;
   LBlockX1, LBlockX2, LBlockY, LX, LV: THashLibUInt32Array;
   LBlockX1, LBlockX2, LBlockY, LX, LV: THashLibUInt32Array;
+  LPtrB: PCardinal;
 begin
 begin
-  LBCount := AR * 32;
+  LPtrB := APtrDataContainer^.PtrB;
+  LCost := APtrDataContainer^.Cost;
+  LBlockSize := APtrDataContainer^.BlockSize;
+  AIdx := AIdx * 32 * LBlockSize;
+  LBCount := LBlockSize * 32;
   System.SetLength(LBlockX1, 16);
   System.SetLength(LBlockX1, 16);
   System.SetLength(LBlockX2, 16);
   System.SetLength(LBlockX2, 16);
   System.SetLength(LBlockY, LBCount);
   System.SetLength(LBlockY, LBCount);
 
 
   System.SetLength(LX, LBCount);
   System.SetLength(LX, LBCount);
 
 
-  System.SetLength(LV, AN * LBCount);
+  System.SetLength(LV, LCost * LBCount);
 
 
   try
   try
-    System.Move(Ab[AbOff], LX[0], LBCount * System.SizeOf(UInt32));
+    System.Move(LPtrB[AIdx], LX[0], LBCount * System.SizeOf(UInt32));
 
 
     LOffset := 0;
     LOffset := 0;
     LIdx := 0;
     LIdx := 0;
-    while LIdx < AN do
+    while LIdx < LCost do
     begin
     begin
       System.Move(LX[0], LV[LOffset], LBCount * System.SizeOf(UInt32));
       System.Move(LX[0], LV[LOffset], LBCount * System.SizeOf(UInt32));
       LOffset := LOffset + LBCount;
       LOffset := LOffset + LBCount;
-      BlockMix(LX, LBlockX1, LBlockX2, LBlockY, AR);
+      BlockMix(LX, LBlockX1, LBlockX2, LBlockY, LBlockSize);
       System.Move(LBlockY[0], LV[LOffset], LBCount * System.SizeOf(UInt32));
       System.Move(LBlockY[0], LV[LOffset], LBCount * System.SizeOf(UInt32));
       LOffset := LOffset + LBCount;
       LOffset := LOffset + LBCount;
-      BlockMix(LBlockY, LBlockX1, LBlockX2, LX, AR);
+      BlockMix(LBlockY, LBlockX1, LBlockX2, LX, LBlockSize);
       System.Inc(LIdx, 2);
       System.Inc(LIdx, 2);
     end;
     end;
 
 
-    LMask := UInt32(AN) - 1;
+    LMask := UInt32(LCost) - 1;
 
 
     LIdx := 0;
     LIdx := 0;
-    while LIdx < AN do
+    while LIdx < LCost do
     begin
     begin
-      LJdx := LX[LBCount - 16] and LMask;
+      LJdx := Int32(LX[LBCount - 16] and LMask);
       System.Move(LV[LJdx * LBCount], LBlockY[0],
       System.Move(LV[LJdx * LBCount], LBlockY[0],
         LBCount * System.SizeOf(UInt32));
         LBCount * System.SizeOf(UInt32));
       &Xor(LBlockY, LX, 0, LBlockY);
       &Xor(LBlockY, LX, 0, LBlockY);
-      BlockMix(LBlockY, LBlockX1, LBlockX2, LX, AR);
+      BlockMix(LBlockY, LBlockX1, LBlockX2, LX, LBlockSize);
       System.Inc(LIdx);
       System.Inc(LIdx);
     end;
     end;
 
 
-    System.Move(LX[0], Ab[AbOff], LBCount * System.SizeOf(UInt32));
+    System.Move(LX[0], LPtrB[AIdx], LBCount * System.SizeOf(UInt32));
   finally
   finally
     ClearArray(LV);
     ClearArray(LV);
     ClearAllArrays(THashLibMatrixUInt32Array.Create(LX, LBlockX1, LBlockX2,
     ClearAllArrays(THashLibMatrixUInt32Array.Create(LX, LBlockX1, LBlockX2,
@@ -356,50 +380,86 @@ begin
   end;
   end;
 end;
 end;
 
 
-{$IFDEF HAS_DELPHI_PPL}
+{$IFDEF USE_PASMP}
+
+class procedure TPBKDF_ScryptNotBuildInAdapter.PasMPSMixWrapper
+  (const AJob: PPasMPJob; const AThreadIndex: LongInt;
+  const ADataContainer: Pointer; const AFromIndex, AToIndex: TPasMPNativeInt);
+begin
+  SMix(AFromIndex, ADataContainer);
+end;
+{$ENDIF}
+{$IFDEF USE_MTPROCS}
+
+class procedure TPBKDF_ScryptNotBuildInAdapter.MTProcsSMixWrapper(AIdx: PtrInt;
+  ADataContainer: Pointer; AItem: TMultiThreadProcItem);
+begin
+  SMix(AIdx, ADataContainer);
+end;
+{$ENDIF}
+{$IF DEFINED(USE_DELPHI_PPL)}
 
 
-class procedure TPBKDF_ScryptNotBuildInAdapter.DoSMix
-  (const Ab: THashLibUInt32Array; AParallelism, ACost, ABlockSize: Int32);
+class procedure TPBKDF_ScryptNotBuildInAdapter.DoParallelSMix
+  (ADataContainer: PDataContainer);
 
 
-  function CreateTask(AOffset: Int32): ITask;
+  function CreateTask(AIdx: Int32; ADataContainer: PDataContainer): ITask;
   begin
   begin
     result := TTask.Create(
     result := TTask.Create(
       procedure()
       procedure()
       begin
       begin
-        SMix(Ab, AOffset, ACost, ABlockSize);
+        SMix(AIdx, ADataContainer);
       end);
       end);
   end;
   end;
 
 
 var
 var
-  LIdx, LTaskIdx: Int32;
+  LIdx, LParallelism: Int32;
   LArrayTasks: array of ITask;
   LArrayTasks: array of ITask;
 begin
 begin
-  System.SetLength(LArrayTasks, AParallelism);
-  for LIdx := 0 to System.Pred(AParallelism) do
+  LParallelism := ADataContainer^.Parallelism;
+  System.SetLength(LArrayTasks, LParallelism);
+  for LIdx := 0 to System.Pred(LParallelism) do
   begin
   begin
-    LArrayTasks[LIdx] := CreateTask(LIdx * 32 * ABlockSize);
-  end;
-  for LTaskIdx := System.Low(LArrayTasks) to System.High(LArrayTasks) do
-  begin
-    LArrayTasks[LTaskIdx].Start;
+    LArrayTasks[LIdx] := CreateTask(LIdx, ADataContainer);
+    LArrayTasks[LIdx].Start;
   end;
   end;
   TTask.WaitForAll(LArrayTasks);
   TTask.WaitForAll(LArrayTasks);
 end;
 end;
 
 
+{$ELSEIF DEFINED(USE_PASMP) OR DEFINED(USE_MTPROCS)}
+
+class procedure TPBKDF_ScryptNotBuildInAdapter.DoParallelSMix
+  (ADataContainer: PDataContainer);
+var
+  LParallelism: Int32;
+begin
+  LParallelism := ADataContainer^.Parallelism;
+{$IF DEFINED(USE_PASMP)}
+  TPasMP.CreateGlobalInstance;
+  GlobalPasMP.Invoke(GlobalPasMP.ParallelFor(ADataContainer, 0,
+    LParallelism - 1, PasMPSMixWrapper));
+{$ELSEIF DEFINED(USE_MTPROCS)}
+  ProcThreadPool.DoParallel(MTProcsSMixWrapper, 0, LParallelism - 1,
+    ADataContainer);
+{$ELSE}
+{$MESSAGE ERROR 'Unsupported Threading Library.'}
+{$IFEND USE_PASMP}
+end;
+
 {$ELSE}
 {$ELSE}
 
 
-class procedure TPBKDF_ScryptNotBuildInAdapter.DoSMix
-  (const Ab: THashLibUInt32Array; AParallelism, ACost, ABlockSize: Int32);
+class procedure TPBKDF_ScryptNotBuildInAdapter.DoParallelSMix
+  (ADataContainer: PDataContainer);
 var
 var
-  LIdx: Int32;
+  LIdx, LParallelism: Int32;
 begin
 begin
-  for LIdx := 0 to System.Pred(AParallelism) do
+  LParallelism := ADataContainer^.Parallelism;
+  for LIdx := 0 to System.Pred(LParallelism) do
   begin
   begin
-    SMix(Ab, LIdx * 32 * ABlockSize, ACost, ABlockSize);
+    SMix(LIdx, ADataContainer);
   end;
   end;
 end;
 end;
 
 
-{$ENDIF HAS_DELPHI_PPL}
+{$IFEND USE_DELPHI_PPL}
 
 
 class function TPBKDF_ScryptNotBuildInAdapter.MFCrypt(const APasswordBytes,
 class function TPBKDF_ScryptNotBuildInAdapter.MFCrypt(const APasswordBytes,
   ASaltBytes: THashLibByteArray; ACost, ABlockSize, AParallelism,
   ASaltBytes: THashLibByteArray; ACost, ABlockSize, AParallelism,
@@ -408,6 +468,7 @@ var
   LMFLenBytes, LBLen: Int32;
   LMFLenBytes, LBLen: Int32;
   LBytes: THashLibByteArray;
   LBytes: THashLibByteArray;
   Lb: THashLibUInt32Array;
   Lb: THashLibUInt32Array;
+  LPtrDataContainer: PDataContainer;
 begin
 begin
   LMFLenBytes := ABlockSize * 128;
   LMFLenBytes := ABlockSize * 128;
   LBytes := SingleIterationPBKDF2(APasswordBytes, ASaltBytes,
   LBytes := SingleIterationPBKDF2(APasswordBytes, ASaltBytes,
@@ -420,7 +481,16 @@ begin
     TConverters.le32_copy(PByte(LBytes), 0, PCardinal(Lb), 0,
     TConverters.le32_copy(PByte(LBytes), 0, PCardinal(Lb), 0,
       System.Length(LBytes) * System.SizeOf(Byte));
       System.Length(LBytes) * System.SizeOf(Byte));
 
 
-    DoSMix(Lb, AParallelism, ACost, ABlockSize);
+    LPtrDataContainer := New(PDataContainer);
+    try
+      LPtrDataContainer^.PtrB := PCardinal(Lb);
+      LPtrDataContainer^.Parallelism := AParallelism;
+      LPtrDataContainer^.Cost := ACost;
+      LPtrDataContainer^.BlockSize := ABlockSize;
+      DoParallelSMix(LPtrDataContainer);
+    finally
+      Dispose(LPtrDataContainer);
+    end;
 
 
     TConverters.le32_copy(PCardinal(Lb), 0, PByte(LBytes), 0,
     TConverters.le32_copy(PCardinal(Lb), 0, PByte(LBytes), 0,
       System.Length(Lb) * System.SizeOf(UInt32));
       System.Length(Lb) * System.SizeOf(UInt32));

+ 0 - 1
src/libraries/hashlib4pascal/HlpPanama.pas

@@ -8,7 +8,6 @@ uses
   HlpHashLibTypes,
   HlpHashLibTypes,
   HlpBits,
   HlpBits,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpRIPEMD.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpBits,
   HlpBits,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpRIPEMD128.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpMDBase,
   HlpMDBase,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpRIPEMD160.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpMDBase,
   HlpMDBase,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpRIPEMD256.pas

@@ -11,7 +11,6 @@ uses
   HlpMDBase,
   HlpMDBase,
   HlpBits,
   HlpBits,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpRIPEMD320.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpMDBase,
   HlpMDBase,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpRadioGatun32.pas

@@ -7,7 +7,6 @@ interface
 uses
 uses
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpRadioGatun64.pas

@@ -7,7 +7,6 @@ interface
 uses
 uses
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA0.pas

@@ -11,7 +11,6 @@ uses
   HlpBits,
   HlpBits,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpHashLibTypes,
   HlpHashLibTypes,

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_224.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_256.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_256Base.pas

@@ -11,7 +11,6 @@ uses
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpConverters,
   HlpConverters,

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_384.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_512.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_512Base.pas

@@ -11,7 +11,6 @@ uses
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpConverters,
   HlpConverters,

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_512_224.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 0 - 1
src/libraries/hashlib4pascal/HlpSHA2_512_256.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 769 - 49
src/libraries/hashlib4pascal/HlpSHA3.pas

@@ -7,10 +7,9 @@ interface
 uses
 uses
   SysUtils,
   SysUtils,
   HlpBits,
   HlpBits,
-{$IFDEF DELPHI}
   HlpHash,
   HlpHash,
+{$IFDEF DELPHI}
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpIHashInfo,
   HlpIHashInfo,
   HlpIHash,
   HlpIHash,
@@ -24,19 +23,22 @@ uses
 
 
 resourcestring
 resourcestring
   SInvalidHashMode = 'Only "[%s]" HashModes are Supported';
   SInvalidHashMode = 'Only "[%s]" HashModes are Supported';
-  SInvalidXOFSize = 'XOFSize in Bits must be Divisible by 8.';
+  SInvalidXOFSize =
+    'XOFSize in Bits must be Multiples of 8 and be Greater than Zero Bytes';
+  SOutputLengthInvalid = 'Output Length is above the Digest Length';
+  SOutputBufferTooShort = 'Output Buffer Too Short';
+  SWritetoXofAfterReadError = '"%s" Write to Xof after Read not Allowed';
 
 
 type
 type
   TSHA3 = class abstract(TBlockHash, ICryptoNotBuildIn, ITransformBlock)
   TSHA3 = class abstract(TBlockHash, ICryptoNotBuildIn, ITransformBlock)
 
 
   type
   type
 {$SCOPEDENUMS ON}
 {$SCOPEDENUMS ON}
-    THashMode = (hmKeccak = $1, hmSHA3 = $6, hmShake = $1F);
+    THashMode = (hmKeccak = $1, hmSHA3 = $6, hmShake = $1F, hmCShake = $4);
 {$SCOPEDENUMS OFF}
 {$SCOPEDENUMS OFF}
   strict protected
   strict protected
   var
   var
     FState: THashLibUInt64Array;
     FState: THashLibUInt64Array;
-    FHashSize, FBlockSize: Int32;
     FHashMode: THashMode;
     FHashMode: THashMode;
 
 
 {$REGION 'Consts'}
 {$REGION 'Consts'}
@@ -167,17 +169,26 @@ type
   TShake = class abstract(TSHA3, IXOF)
   TShake = class abstract(TSHA3, IXOF)
   strict private
   strict private
   var
   var
-    FXOFSizeInBits: UInt32;
-    function GetXOFSizeInBits: UInt32; inline;
-    procedure SetXOFSizeInBits(AXofSizeInBits: UInt32); inline;
-    function SetXOFSizeInBitsInternal(AXofSizeInBits: UInt32): IXOF;
+    FXOFSizeInBits: UInt64;
+    function GetXOFSizeInBits: UInt64; inline;
+    procedure SetXOFSizeInBits(AXofSizeInBits: UInt64); inline;
+    function SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
   strict protected
   strict protected
+  var
+    FBufferPosition, FDigestPosition, FShakeBufferPosition: UInt64;
+    FShakeBuffer: THashLibByteArray;
+    FFinalized: Boolean;
     constructor Create(AHashSize: THashSize);
     constructor Create(AHashSize: THashSize);
-    property XOFSizeInBits: UInt32 read GetXOFSizeInBits write SetXOFSizeInBits;
+    property XOFSizeInBits: UInt64 read GetXOFSizeInBits write SetXOFSizeInBits;
 
 
   public
   public
+    procedure Initialize(); override;
     function GetResult(): THashLibByteArray; override;
     function GetResult(): THashLibByteArray; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ADataLength: Int32); override;
     function TransformFinal(): IHashResult; override;
     function TransformFinal(): IHashResult; override;
+    procedure DoOutput(const ADestination: THashLibByteArray;
+      ADestinationOffset, AOutputLength: UInt64);
   end;
   end;
 
 
 type
 type
@@ -198,6 +209,173 @@ type
     function Clone(): IHash; override;
     function Clone(): IHash; override;
   end;
   end;
 
 
+type
+  TCShake = class abstract(TShake)
+
+  strict private
+
+    // LeftEncode returns max 9 bytes
+    class function LeftEncode(AInput: UInt64): THashLibByteArray; static;
+
+  strict protected
+
+  var
+    FN, FS, FInitBlock: THashLibByteArray;
+
+    /// <param name="AHashSize">
+    /// the HashSize of the underlying Shake function
+    /// </param>
+    /// <param name="N">
+    /// the function name string, note this is reserved for use by NIST.
+    /// Avoid using if not required
+    /// </param>
+    /// <param name="S">
+    /// the customization string - available for local use
+    /// </param>
+    constructor Create(AHashSize: THashSize; const N, S: THashLibByteArray);
+
+  public
+
+    procedure Initialize(); override;
+
+    class function RightEncode(AInput: UInt64): THashLibByteArray; static;
+    class function BytePad(const AInput: THashLibByteArray; AW: Int32)
+      : THashLibByteArray; static;
+    class function EncodeString(const AInput: THashLibByteArray)
+      : THashLibByteArray; static;
+  end;
+
+type
+  TCShake_128 = class sealed(TCShake)
+
+  public
+
+    constructor Create(const N, S: THashLibByteArray);
+    function Clone(): IHash; override;
+  end;
+
+type
+  TCShake_256 = class sealed(TCShake)
+
+  public
+
+    constructor Create(const N, S: THashLibByteArray);
+    function Clone(): IHash; override;
+  end;
+
+type
+  TKMACNotBuildInAdapter = class abstract(THash, IKMAC, IKMACNotBuildIn,
+    ICrypto, ICryptoNotBuildIn)
+
+  strict protected
+  var
+    FHash: IHash;
+    FKey: THashLibByteArray;
+
+    function GetName: String; override;
+
+    function GetKey(): THashLibByteArray;
+    procedure SetKey(const AValue: THashLibByteArray);
+
+    procedure DoOutput(const ADestination: THashLibByteArray;
+      ADestinationOffset, AOutputLength: UInt64);
+
+    constructor Create(AHashSize: Int32);
+
+    function GetResult(): THashLibByteArray;
+
+  public
+
+    destructor Destroy; override;
+
+    procedure Clear();
+
+    procedure Initialize(); override;
+    function TransformFinal(): IHashResult; override;
+    procedure TransformBytes(const AData: THashLibByteArray;
+      AIndex, ALength: Int32); override;
+
+    property Key: THashLibByteArray read GetKey write SetKey;
+    property Name: String read GetName;
+
+  end;
+
+type
+  TKMAC128 = class(TKMACNotBuildInAdapter, IKMAC)
+
+  strict private
+    constructor Create(const AKMACKey, ACustomization: THashLibByteArray;
+      AOutputLengthInBits: UInt64); overload;
+    constructor Create(const AHash: IHash; const AKMACKey: THashLibByteArray;
+      AOutputLengthInBits: UInt64); overload;
+
+  public
+    function Clone(): IHash; override;
+    class function CreateKMAC128(const AKMACKey, ACustomization
+      : THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC; static;
+  end;
+
+type
+  TKMAC128XOF = class sealed(TKMAC128, IKMAC, IXOF)
+  strict private
+
+    function GetXOFSizeInBits: UInt64; inline;
+    procedure SetXOFSizeInBits(AXofSizeInBits: UInt64); inline;
+    function SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+
+    constructor Create(const AKMACKey, ACustomization
+      : THashLibByteArray); overload;
+    constructor Create(const AHash: IHash;
+      const AKMACKey: THashLibByteArray); overload;
+
+  strict protected
+    property XOFSizeInBits: UInt64 read GetXOFSizeInBits write SetXOFSizeInBits;
+
+  public
+    function Clone(): IHash; override;
+    class function CreateKMAC128XOF(const AKMACKey, ACustomization
+      : THashLibByteArray; AXofSizeInBits: UInt64): IKMAC; static;
+
+  end;
+
+type
+  TKMAC256 = class(TKMACNotBuildInAdapter, IKMAC)
+
+  strict private
+    constructor Create(const AKMACKey, ACustomization: THashLibByteArray;
+      AOutputLengthInBits: UInt64); overload;
+    constructor Create(const AHash: IHash; const AKMACKey: THashLibByteArray;
+      AOutputLengthInBits: UInt64); overload;
+
+  public
+    function Clone(): IHash; override;
+    class function CreateKMAC256(const AKMACKey, ACustomization
+      : THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC; static;
+  end;
+
+type
+  TKMAC256XOF = class sealed(TKMAC256, IKMAC, IXOF)
+  strict private
+
+    function GetXOFSizeInBits: UInt64; inline;
+    procedure SetXOFSizeInBits(AXofSizeInBits: UInt64); inline;
+    function SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+
+    constructor Create(const AKMACKey, ACustomization
+      : THashLibByteArray); overload;
+    constructor Create(const AHash: IHash;
+      const AKMACKey: THashLibByteArray); overload;
+
+  strict protected
+    property XOFSizeInBits: UInt64 read GetXOFSizeInBits write SetXOFSizeInBits;
+
+  public
+    function Clone(): IHash; override;
+    class function CreateKMAC256XOF(const AKMACKey, ACustomization
+      : THashLibByteArray; AXofSizeInBits: UInt64): IKMAC; static;
+
+  end;
+
 implementation
 implementation
 
 
 { TSHA3 }
 { TSHA3 }
@@ -205,8 +383,6 @@ implementation
 constructor TSHA3.Create(AHashSize: THashSize);
 constructor TSHA3.Create(AHashSize: THashSize);
 begin
 begin
   Inherited Create(Int32(AHashSize), 200 - (Int32(AHashSize) * 2));
   Inherited Create(Int32(AHashSize), 200 - (Int32(AHashSize) * 2));
-  FHashSize := HashSize;
-  FBlockSize := BlockSize;
   System.SetLength(FState, 25);
   System.SetLength(FState, 25);
 end;
 end;
 
 
@@ -219,7 +395,7 @@ begin
   LBlock := FBuffer.GetBytesZeroPadded();
   LBlock := FBuffer.GetBytesZeroPadded();
 
 
   LBlock[LBufferPosition] := Int32(FHashMode);
   LBlock[LBufferPosition] := Int32(FHashMode);
-  LBlock[FBlockSize - 1] := LBlock[FBlockSize - 1] xor $80;
+  LBlock[BlockSize - 1] := LBlock[BlockSize - 1] xor $80;
 
 
   TransformBlock(PByte(LBlock), System.Length(LBlock), 0);
   TransformBlock(PByte(LBlock), System.Length(LBlock), 0);
 end;
 end;
@@ -231,20 +407,20 @@ begin
       Result := Format('%s_%u', ['TKeccak', Self.HashSize * 8]);
       Result := Format('%s_%u', ['TKeccak', Self.HashSize * 8]);
     TSHA3.THashMode.hmSHA3:
     TSHA3.THashMode.hmSHA3:
       Result := Self.ClassName;
       Result := Self.ClassName;
-    TSHA3.THashMode.hmShake:
-      Result := Format('%s_%s_%u', [Self.ClassName, 'XOFSizeInBits',
-        (Self as IXOF).XOFSizeInBits]);
+    TSHA3.THashMode.hmShake, TSHA3.THashMode.hmCShake:
+      Result := Format('%s_%s_%u', [Self.ClassName, 'XOFSizeInBytes',
+        (Self as IXOF).XOFSizeInBits shr 3]);
   else
   else
     begin
     begin
       raise EArgumentInvalidHashLibException.CreateResFmt(@SInvalidHashMode,
       raise EArgumentInvalidHashLibException.CreateResFmt(@SInvalidHashMode,
-        ['hmKeccak, hmSHA3, hmShake']);
+        ['hmKeccak, hmSHA3, hmShake, hmCShake']);
     end;
     end;
   end;
   end;
 end;
 end;
 
 
 function TSHA3.GetResult: THashLibByteArray;
 function TSHA3.GetResult: THashLibByteArray;
 begin
 begin
-  System.SetLength(Result, FHashSize);
+  System.SetLength(Result, HashSize);
 
 
   TConverters.le64_copy(PUInt64(FState), 0, PByte(Result), 0,
   TConverters.le64_copy(PUInt64(FState), 0, PByte(Result), 0,
     System.Length(Result));
     System.Length(Result));
@@ -604,7 +780,7 @@ var
 begin
 begin
   TConverters.le64_copy(AData, AIndex, @(LData[0]), 0, ADataLength);
   TConverters.le64_copy(AData, AIndex, @(LData[0]), 0, ADataLength);
   LJdx := 0;
   LJdx := 0;
-  LBlockCount := FBlockSize shr 3;
+  LBlockCount := BlockSize shr 3;
   while LJdx < LBlockCount do
   while LJdx < LBlockCount do
   begin
   begin
     FState[LJdx] := FState[LJdx] xor LData[LJdx];
     FState[LJdx] := FState[LJdx] xor LData[LJdx];
@@ -797,9 +973,12 @@ end;
 
 
 { TShake }
 { TShake }
 
 
-function TShake.SetXOFSizeInBitsInternal(AXofSizeInBits: UInt32): IXOF;
+function TShake.SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+var
+  LXofSizeInBytes: UInt64;
 begin
 begin
-  If ((AXofSizeInBits and $7) <> 0) then
+  LXofSizeInBytes := AXofSizeInBits shr 3;
+  If (((AXofSizeInBits and $7) <> 0) or (LXofSizeInBytes < 1)) then
   begin
   begin
     raise EArgumentInvalidHashLibException.CreateRes(@SInvalidXOFSize);
     raise EArgumentInvalidHashLibException.CreateRes(@SInvalidXOFSize);
   end;
   end;
@@ -807,65 +986,118 @@ begin
   Result := Self;
   Result := Self;
 end;
 end;
 
 
+function TShake.GetXOFSizeInBits: UInt64;
+begin
+  Result := FXOFSizeInBits;
+end;
+
+procedure TShake.SetXOFSizeInBits(AXofSizeInBits: UInt64);
+begin
+  SetXOFSizeInBitsInternal(AXofSizeInBits);
+end;
+
 constructor TShake.Create(AHashSize: THashSize);
 constructor TShake.Create(AHashSize: THashSize);
 begin
 begin
   Inherited Create(AHashSize);
   Inherited Create(AHashSize);
   FHashMode := THashMode.hmShake;
   FHashMode := THashMode.hmShake;
+  FFinalized := False;
+  System.SetLength(FShakeBuffer, 8);
 end;
 end;
 
 
-function TShake.GetResult: THashLibByteArray;
+procedure TShake.DoOutput(const ADestination: THashLibByteArray;
+  ADestinationOffset, AOutputLength: UInt64);
 var
 var
-  LBufferPosition: Int32;
-  LIdx, LXofSizeInBytes: UInt32;
+  LDestinationOffset: UInt64;
 begin
 begin
-  LBufferPosition := FBuffer.Position;
 
 
-  LXofSizeInBytes := FXOFSizeInBits shr 3;
-  LIdx := 0;
-  System.SetLength(Result, LXofSizeInBytes);
+  if (UInt64(System.Length(ADestination)) - ADestinationOffset) < AOutputLength
+  then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateRes(@SOutputBufferTooShort);
+  end;
+
+  if ((FDigestPosition + AOutputLength) > (XOFSizeInBits shr 3)) then
+  begin
+    raise EArgumentOutOfRangeHashLibException.CreateRes(@SOutputLengthInvalid);
+  end;
 
 
-  while LIdx < (LXofSizeInBytes shr 3) do
+  if not FFinalized then
   begin
   begin
+    Finish();
+    FFinalized := True;
+  end;
 
 
-    if (LBufferPosition * 8) >= FBlockSize then
+  LDestinationOffset := ADestinationOffset;
+
+  while AOutputLength > 0 do
+  begin
+    if FShakeBufferPosition >= 8 then
     begin
     begin
-      KeccakF1600_StatePermute();
-      LBufferPosition := 0;
+
+      if (FBufferPosition * 8) >= UInt64(BlockSize) then
+      begin
+        KeccakF1600_StatePermute();
+        FBufferPosition := 0;
+      end;
+
+      TConverters.ReadUInt64AsBytesLE(FState[FBufferPosition], FShakeBuffer, 0);
+      System.Inc(FBufferPosition);
+      FShakeBufferPosition := 0;
     end;
     end;
 
 
-    TConverters.ReadUInt64AsBytesLE(FState[LBufferPosition], Result, LIdx * 8);
+    ADestination[LDestinationOffset] := FShakeBuffer[FShakeBufferPosition];
 
 
-    System.Inc(LBufferPosition);
-    System.Inc(LIdx);
+    System.Inc(FShakeBufferPosition);
+    System.Dec(AOutputLength);
+    System.Inc(FDigestPosition);
+    System.Inc(LDestinationOffset);
   end;
   end;
 end;
 end;
 
 
-function TShake.GetXOFSizeInBits: UInt32;
+function TShake.GetResult: THashLibByteArray;
+var
+  LXofSizeInBytes: UInt64;
 begin
 begin
-  Result := FXOFSizeInBits;
+  LXofSizeInBytes := FXOFSizeInBits shr 3;
+
+  System.SetLength(Result, LXofSizeInBytes);
+
+  DoOutput(Result, 0, LXofSizeInBytes);
+end;
+
+procedure TShake.Initialize;
+begin
+  inherited Initialize();
+  FBufferPosition := 0;
+  FDigestPosition := 0;
+  FShakeBufferPosition := 8;
+  FFinalized := False;
+  TArrayUtils.ZeroFill(FShakeBuffer);
+end;
+
+procedure TShake.TransformBytes(const AData: THashLibByteArray;
+  AIndex, ADataLength: Int32);
+begin
+  if FFinalized then
+  begin
+    raise EInvalidOperationHashLibException.CreateResFmt
+      (@SWritetoXofAfterReadError, [Name]);
+  end;
+  inherited TransformBytes(AData, AIndex, ADataLength);
 end;
 end;
 
 
 function TShake.TransformFinal: IHashResult;
 function TShake.TransformFinal: IHashResult;
 var
 var
   LBuffer: THashLibByteArray;
   LBuffer: THashLibByteArray;
 begin
 begin
-  Finish();
-{$IFDEF DEBUG}
-  System.Assert(FBuffer.IsEmpty);
-{$ENDIF DEBUG}
   LBuffer := GetResult();
   LBuffer := GetResult();
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
-  System.Assert(UInt32(System.Length(LBuffer)) = (XOFSizeInBits shr 3));
+  System.Assert(UInt64(System.Length(LBuffer)) = (XOFSizeInBits shr 3));
 {$ENDIF DEBUG}
 {$ENDIF DEBUG}
   Initialize();
   Initialize();
   Result := THashResult.Create(LBuffer);
   Result := THashResult.Create(LBuffer);
 end;
 end;
 
 
-procedure TShake.SetXOFSizeInBits(AXofSizeInBits: UInt32);
-begin
-  SetXOFSizeInBitsInternal(AXofSizeInBits);
-end;
-
 { TShake_128 }
 { TShake_128 }
 
 
 function TShake_128.Clone(): IHash;
 function TShake_128.Clone(): IHash;
@@ -873,12 +1105,23 @@ var
   LHashInstance: TShake_128;
   LHashInstance: TShake_128;
   LXof: IXOF;
   LXof: IXOF;
 begin
 begin
+  // Xof Cloning
   LXof := (TShake_128.Create() as IXOF);
   LXof := (TShake_128.Create() as IXOF);
   LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
   LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
+
+  // Shake_128 Cloning
   LHashInstance := LXof as TShake_128;
   LHashInstance := LXof as TShake_128;
-  LHashInstance.FState := System.Copy(FState);
+  LHashInstance.FBufferPosition := FBufferPosition;
+  LHashInstance.FDigestPosition := FDigestPosition;
+  LHashInstance.FShakeBufferPosition := FShakeBufferPosition;
+  LHashInstance.FFinalized := FFinalized;
+  LHashInstance.FShakeBuffer := System.Copy(FShakeBuffer);
+
+  // Internal Sha3 Cloning
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
+  LHashInstance.FState := System.Copy(FState);
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
+
   Result := LHashInstance as IHash;
   Result := LHashInstance as IHash;
   Result.BufferSize := BufferSize;
   Result.BufferSize := BufferSize;
 end;
 end;
@@ -895,12 +1138,23 @@ var
   LHashInstance: TShake_256;
   LHashInstance: TShake_256;
   LXof: IXOF;
   LXof: IXOF;
 begin
 begin
+  // Xof Cloning
   LXof := (TShake_256.Create() as IXOF);
   LXof := (TShake_256.Create() as IXOF);
   LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
   LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
+
+  // Shake_256 Cloning
   LHashInstance := LXof as TShake_256;
   LHashInstance := LXof as TShake_256;
-  LHashInstance.FState := System.Copy(FState);
+  LHashInstance.FBufferPosition := FBufferPosition;
+  LHashInstance.FDigestPosition := FDigestPosition;
+  LHashInstance.FShakeBufferPosition := FShakeBufferPosition;
+  LHashInstance.FFinalized := FFinalized;
+  LHashInstance.FShakeBuffer := System.Copy(FShakeBuffer);
+
+  // Internal Sha3 Cloning
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
+  LHashInstance.FState := System.Copy(FState);
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
+
   Result := LHashInstance as IHash;
   Result := LHashInstance as IHash;
   Result.BufferSize := BufferSize;
   Result.BufferSize := BufferSize;
 end;
 end;
@@ -910,4 +1164,470 @@ begin
   Inherited Create(THashSize.hsHashSize256);
   Inherited Create(THashSize.hsHashSize256);
 end;
 end;
 
 
+{ TCShake }
+
+class function TCShake.LeftEncode(AInput: UInt64): THashLibByteArray;
+var
+  LN: Byte;
+  LV: UInt64;
+  LIdx: Int32;
+begin
+  LN := 1;
+  LV := AInput;
+  LV := LV shr 8;
+
+  while (LV <> 0) do
+  begin
+    System.Inc(LN);
+    LV := LV shr 8;
+  end;
+
+  System.SetLength(Result, LN + 1);
+  Result[0] := LN;
+  for LIdx := 1 to LN do
+  begin
+    Result[LIdx] := Byte(AInput shr (8 * (LN - LIdx)));
+  end;
+end;
+
+class function TCShake.RightEncode(AInput: UInt64): THashLibByteArray;
+var
+  LN: Byte;
+  LV: UInt64;
+  LIdx: Int32;
+begin
+  LN := 1;
+  LV := AInput;
+  LV := LV shr 8;
+
+  while (LV <> 0) do
+  begin
+    System.Inc(LN);
+    LV := LV shr 8;
+  end;
+
+  System.SetLength(Result, LN + 1);
+  Result[LN] := LN;
+  for LIdx := 1 to LN do
+  begin
+    Result[LIdx - 1] := Byte(AInput shr (8 * (LN - LIdx)));
+  end;
+end;
+
+class function TCShake.BytePad(const AInput: THashLibByteArray; AW: Int32)
+  : THashLibByteArray;
+var
+  LBuffer: THashLibByteArray;
+  LPadLength: Int32;
+begin
+  LBuffer := TArrayUtils.Concatenate(LeftEncode(UInt64(AW)), AInput);
+  LPadLength := AW - (System.Length(LBuffer) mod AW);
+  System.SetLength(Result, LPadLength);
+  Result := TArrayUtils.Concatenate(LBuffer, Result);
+end;
+
+class function TCShake.EncodeString(const AInput: THashLibByteArray)
+  : THashLibByteArray;
+begin
+  if System.Length(AInput) = 0 then
+  begin
+    Result := LeftEncode(0);
+    Exit;
+  end;
+  Result := TArrayUtils.Concatenate(LeftEncode(UInt64(System.Length(AInput) * 8)
+    ), AInput);
+end;
+
+constructor TCShake.Create(AHashSize: THashSize; const N, S: THashLibByteArray);
+begin
+  Inherited Create(AHashSize);
+
+  FN := N;
+  FS := S;
+  FInitBlock := Nil;
+
+  if (System.Length(FN) = 0) and (System.Length(FS) = 0) then
+  begin
+    FHashMode := THashMode.hmShake;
+  end
+  else
+  begin
+    FHashMode := THashMode.hmCShake;
+    FInitBlock := TArrayUtils.Concatenate(EncodeString(N), EncodeString(S));
+  end;
+end;
+
+procedure TCShake.Initialize;
+begin
+  Inherited Initialize();
+
+  if FInitBlock <> Nil then
+  begin
+    TransformBytes(BytePad(FInitBlock, BlockSize));
+  end;
+end;
+
+{ TCShake_128 }
+
+function TCShake_128.Clone(): IHash;
+var
+  LHashInstance: TCShake_128;
+  LXof: IXOF;
+begin
+  // Xof Cloning
+  LXof := TCShake_128.Create(System.Copy(FN), System.Copy(FS)) as IXOF;
+  LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
+
+  // CShake_128 Cloning
+  LHashInstance := LXof as TCShake_128;
+  LHashInstance.FInitBlock := System.Copy(FInitBlock);
+
+  LHashInstance.FBufferPosition := FBufferPosition;
+  LHashInstance.FDigestPosition := FDigestPosition;
+  LHashInstance.FShakeBufferPosition := FShakeBufferPosition;
+  LHashInstance.FFinalized := FFinalized;
+  LHashInstance.FShakeBuffer := System.Copy(FShakeBuffer);
+
+  // Internal Sha3 Cloning
+  LHashInstance.FBuffer := FBuffer.Clone();
+  LHashInstance.FState := System.Copy(FState);
+  LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
+
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TCShake_128.Create(const N, S: THashLibByteArray);
+begin
+  Inherited Create(THashSize.hsHashSize128, N, S);
+end;
+
+{ TCShake_256 }
+
+function TCShake_256.Clone(): IHash;
+var
+  LHashInstance: TCShake_256;
+  LXof: IXOF;
+begin
+  // Xof Cloning
+  LXof := TCShake_256.Create(System.Copy(FN), System.Copy(FS)) as IXOF;
+  LXof.XOFSizeInBits := (Self as IXOF).XOFSizeInBits;
+
+  // CShake_256 Cloning
+  LHashInstance := LXof as TCShake_256;
+  LHashInstance.FInitBlock := System.Copy(FInitBlock);
+
+  LHashInstance.FBufferPosition := FBufferPosition;
+  LHashInstance.FDigestPosition := FDigestPosition;
+  LHashInstance.FShakeBufferPosition := FShakeBufferPosition;
+  LHashInstance.FFinalized := FFinalized;
+  LHashInstance.FShakeBuffer := System.Copy(FShakeBuffer);
+
+  // Internal Sha3 Cloning
+  LHashInstance.FBuffer := FBuffer.Clone();
+  LHashInstance.FState := System.Copy(FState);
+  LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
+
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TCShake_256.Create(const N, S: THashLibByteArray);
+begin
+  Inherited Create(THashSize.hsHashSize256, N, S);
+end;
+
+{ TKMACNotBuildInAdapter }
+
+procedure TKMACNotBuildInAdapter.Clear();
+begin
+  TArrayUtils.ZeroFill(FKey);
+end;
+
+constructor TKMACNotBuildInAdapter.Create(AHashSize: Int32);
+begin
+  Inherited Create(AHashSize, 200 - (AHashSize * 2));
+end;
+
+destructor TKMACNotBuildInAdapter.Destroy;
+begin
+  Clear();
+  inherited Destroy;
+end;
+
+procedure TKMACNotBuildInAdapter.DoOutput(const ADestination: THashLibByteArray;
+  ADestinationOffset, AOutputLength: UInt64);
+begin
+  if Supports(Self, IXOF) then
+  begin
+    TransformBytes(TCShake.RightEncode(0));
+  end
+  else
+  begin
+    TransformBytes(TCShake.RightEncode((FHash as IXOF).XOFSizeInBits));
+  end;
+
+  (FHash as IXOF).DoOutput(ADestination, ADestinationOffset, AOutputLength);
+end;
+
+function TKMACNotBuildInAdapter.GetKey: THashLibByteArray;
+begin
+  Result := System.Copy(FKey);
+end;
+
+function TKMACNotBuildInAdapter.GetName: String;
+begin
+  if Supports(Self, IXOF) then
+  begin
+    Result := Format('%s_%s_%u', [Self.ClassName, 'XOFSizeInBytes',
+      (FHash as IXOF).XOFSizeInBits shr 3]);
+  end
+  else
+  begin
+    Result := Format('%s', [Self.ClassName]);
+  end;
+end;
+
+procedure TKMACNotBuildInAdapter.Initialize;
+begin
+  FHash.Initialize;
+  TransformBytes(TCShake.BytePad(TCShake.EncodeString(FKey), BlockSize));
+end;
+
+procedure TKMACNotBuildInAdapter.SetKey(const AValue: THashLibByteArray);
+begin
+  if (AValue = Nil) then
+  begin
+    FKey := Nil;
+  end
+  else
+  begin
+    FKey := System.Copy(AValue);
+  end;
+end;
+
+procedure TKMACNotBuildInAdapter.TransformBytes(const AData: THashLibByteArray;
+  AIndex, ALength: Int32);
+begin
+  FHash.TransformBytes(AData, AIndex, ALength);
+end;
+
+function TKMACNotBuildInAdapter.GetResult: THashLibByteArray;
+var
+  LXofSizeInBytes: UInt64;
+begin
+  LXofSizeInBytes := (FHash as IXOF).XOFSizeInBits shr 3;
+  System.SetLength(Result, LXofSizeInBytes);
+  DoOutput(Result, 0, LXofSizeInBytes);
+end;
+
+function TKMACNotBuildInAdapter.TransformFinal: IHashResult;
+var
+  LBuffer: THashLibByteArray;
+begin
+  LBuffer := GetResult();
+{$IFDEF DEBUG}
+  System.Assert(UInt64(System.Length(LBuffer))
+    = ((FHash as IXOF).XOFSizeInBits shr 3));
+{$ENDIF DEBUG}
+  Initialize();
+  Result := THashResult.Create(LBuffer);
+end;
+
+{ TKMAC128 }
+
+function TKMAC128.Clone(): IHash;
+var
+  LHashInstance: TKMAC128;
+begin
+  LHashInstance := TKMAC128.Create(FHash.Clone(), FKey,
+    (FHash as IXOF).XOFSizeInBits);
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TKMAC128.Create(const AKMACKey, ACustomization: THashLibByteArray;
+  AOutputLengthInBits: UInt64);
+begin
+  Create(TCShake_128.Create(TConverters.ConvertStringToBytes('KMAC',
+    TEncoding.UTF8), ACustomization) as IHash, AKMACKey, AOutputLengthInBits);
+end;
+
+constructor TKMAC128.Create(const AHash: IHash;
+  const AKMACKey: THashLibByteArray; AOutputLengthInBits: UInt64);
+begin
+  inherited Create(Int32(THashSize.hsHashSize128));
+  SetKey(AKMACKey);
+  FHash := AHash;
+  (FHash as IXOF).XOFSizeInBits := AOutputLengthInBits;
+end;
+
+class function TKMAC128.CreateKMAC128(const AKMACKey, ACustomization
+  : THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC;
+begin
+  Result := TKMAC128.Create(AKMACKey, ACustomization,
+    AOutputLengthInBits) as IKMAC;
+end;
+
+{ TKMAC128XOF }
+
+function TKMAC128XOF.SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+var
+  AXofSizeInBytes: UInt64;
+begin
+  AXofSizeInBytes := AXofSizeInBits shr 3;
+  If (((AXofSizeInBytes and $7) <> 0) or (AXofSizeInBytes < 1)) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes(@SInvalidXOFSize);
+  end;
+
+  (FHash as IXOF).XOFSizeInBits := AXofSizeInBits;
+  Result := Self;
+end;
+
+function TKMAC128XOF.GetXOFSizeInBits: UInt64;
+begin
+  Result := (FHash as IXOF).XOFSizeInBits;
+end;
+
+procedure TKMAC128XOF.SetXOFSizeInBits(AXofSizeInBits: UInt64);
+begin
+  SetXOFSizeInBitsInternal(AXofSizeInBits);
+end;
+
+function TKMAC128XOF.Clone(): IHash;
+var
+  LHashInstance: TKMAC128XOF;
+  LXof: IXOF;
+begin
+  LHashInstance := TKMAC128XOF.Create(FHash.Clone(), FKey);
+  LXof := LHashInstance as IXOF;
+  LXof.XOFSizeInBits := XOFSizeInBits;
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TKMAC128XOF.Create(const AHash: IHash;
+  const AKMACKey: THashLibByteArray);
+begin
+  inherited Create(Int32(THashSize.hsHashSize128));
+  SetKey(AKMACKey);
+  FHash := AHash;
+end;
+
+constructor TKMAC128XOF.Create(const AKMACKey, ACustomization
+  : THashLibByteArray);
+begin
+  Create(TCShake_128.Create(TConverters.ConvertStringToBytes('KMAC',
+    TEncoding.UTF8), ACustomization) as IHash, AKMACKey);
+end;
+
+class function TKMAC128XOF.CreateKMAC128XOF(const AKMACKey, ACustomization
+  : THashLibByteArray; AXofSizeInBits: UInt64): IKMAC;
+var
+  LXof: IXOF;
+begin
+  LXof := (TKMAC128XOF.Create(AKMACKey, ACustomization) as IKMAC) as IXOF;
+  LXof.XOFSizeInBits := AXofSizeInBits;
+  Result := (LXof as IHash) as IKMAC;
+end;
+
+{ TKMAC256 }
+
+function TKMAC256.Clone(): IHash;
+var
+  LHashInstance: TKMAC256;
+begin
+  LHashInstance := TKMAC256.Create(FHash.Clone(), FKey,
+    (FHash as IXOF).XOFSizeInBits);
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TKMAC256.Create(const AKMACKey, ACustomization: THashLibByteArray;
+  AOutputLengthInBits: UInt64);
+begin
+  Create(TCShake_256.Create(TConverters.ConvertStringToBytes('KMAC',
+    TEncoding.UTF8), ACustomization) as IHash, AKMACKey, AOutputLengthInBits);
+end;
+
+constructor TKMAC256.Create(const AHash: IHash;
+  const AKMACKey: THashLibByteArray; AOutputLengthInBits: UInt64);
+begin
+  inherited Create(Int32(THashSize.hsHashSize256));
+  SetKey(AKMACKey);
+  FHash := AHash;
+  (FHash as IXOF).XOFSizeInBits := AOutputLengthInBits;
+end;
+
+class function TKMAC256.CreateKMAC256(const AKMACKey, ACustomization
+  : THashLibByteArray; AOutputLengthInBits: UInt64): IKMAC;
+begin
+  Result := TKMAC256.Create(AKMACKey, ACustomization,
+    AOutputLengthInBits) as IKMAC;
+end;
+
+{ TKMAC256XOF }
+
+function TKMAC256XOF.SetXOFSizeInBitsInternal(AXofSizeInBits: UInt64): IXOF;
+var
+  AXofSizeInBytes: UInt64;
+begin
+  AXofSizeInBytes := AXofSizeInBits shr 3;
+  If (((AXofSizeInBytes and $7) <> 0) or (AXofSizeInBytes < 1)) then
+  begin
+    raise EArgumentInvalidHashLibException.CreateRes(@SInvalidXOFSize);
+  end;
+
+  (FHash as IXOF).XOFSizeInBits := AXofSizeInBits;
+  Result := Self;
+end;
+
+function TKMAC256XOF.GetXOFSizeInBits: UInt64;
+begin
+  Result := (FHash as IXOF).XOFSizeInBits;
+end;
+
+procedure TKMAC256XOF.SetXOFSizeInBits(AXofSizeInBits: UInt64);
+begin
+  SetXOFSizeInBitsInternal(AXofSizeInBits);
+end;
+
+function TKMAC256XOF.Clone(): IHash;
+var
+  LHashInstance: TKMAC256XOF;
+  LXof: IXOF;
+begin
+  LHashInstance := TKMAC256XOF.Create(FHash.Clone(), FKey);
+  LXof := LHashInstance as IXOF;
+  LXof.XOFSizeInBits := XOFSizeInBits;
+  Result := LHashInstance as IHash;
+  Result.BufferSize := BufferSize;
+end;
+
+constructor TKMAC256XOF.Create(const AHash: IHash;
+  const AKMACKey: THashLibByteArray);
+begin
+  inherited Create(Int32(THashSize.hsHashSize256));
+  SetKey(AKMACKey);
+  FHash := AHash;
+end;
+
+constructor TKMAC256XOF.Create(const AKMACKey, ACustomization
+  : THashLibByteArray);
+begin
+  Create(TCShake_256.Create(TConverters.ConvertStringToBytes('KMAC',
+    TEncoding.UTF8), ACustomization) as IHash, AKMACKey);
+end;
+
+class function TKMAC256XOF.CreateKMAC256XOF(const AKMACKey, ACustomization
+  : THashLibByteArray; AXofSizeInBits: UInt64): IKMAC;
+var
+  LXof: IXOF;
+begin
+  LXof := (TKMAC256XOF.Create(AKMACKey, ACustomization) as IKMAC) as IXOF;
+  LXof.XOFSizeInBits := AXofSizeInBits;
+  Result := (LXof as IHash) as IKMAC;
+end;
+
 end.
 end.

+ 141 - 87
src/libraries/hashlib4pascal/HlpSipHash.pas

@@ -41,6 +41,7 @@ type
     procedure CompressTimes(ATimes: Int32); inline;
     procedure CompressTimes(ATimes: Int32); inline;
     procedure ProcessBlock(ABlock: UInt64); inline;
     procedure ProcessBlock(ABlock: UInt64); inline;
     procedure ByteUpdate(AByte: Byte); inline;
     procedure ByteUpdate(AByte: Byte); inline;
+    function ProcessFinalBlock(): UInt64;
     procedure Finish();
     procedure Finish();
 
 
     function GetKeyLength(): TNullableInteger;
     function GetKeyLength(): TNullableInteger;
@@ -49,13 +50,13 @@ type
 
 
   strict protected
   strict protected
   var
   var
-    FV0, FV1, FV2, FV3, FKey0, FKey1, FTotalLength: UInt64;
+    FV0, FV1, FV2, FV3, FKey0, FKey1, FTotalLength, FPartA, FPartB: UInt64;
     FCompressionRounds, FFinalizationRounds, FIdx: Int32;
     FCompressionRounds, FFinalizationRounds, FIdx: Int32;
+    FMagicXor: Byte;
     FBuffer: THashLibByteArray;
     FBuffer: THashLibByteArray;
 
 
   public
   public
-    constructor Create(ACompressionRounds: Int32 = 2;
-      AFinalizationRounds: Int32 = 4);
+    constructor Create(AHashSize, ABlockSize: Int32);
     procedure Initialize(); override;
     procedure Initialize(); override;
     procedure TransformBytes(const AData: THashLibByteArray;
     procedure TransformBytes(const AData: THashLibByteArray;
       AIndex, ALength: Int32); override;
       AIndex, ALength: Int32); override;
@@ -73,7 +74,8 @@ type
 
 
   public
   public
 
 
-    constructor Create();
+    constructor Create(ACompressionRounds: Int32 = 2;
+      AFinalizationRounds: Int32 = 4);
     function Clone(): IHash; override;
     function Clone(): IHash; override;
 
 
   end;
   end;
@@ -93,6 +95,7 @@ begin
   LHashInstance.FV3 := FV3;
   LHashInstance.FV3 := FV3;
   LHashInstance.FKey0 := FKey0;
   LHashInstance.FKey0 := FKey0;
   LHashInstance.FKey1 := FKey1;
   LHashInstance.FKey1 := FKey1;
+  LHashInstance.FPartA := FPartA;
   LHashInstance.FTotalLength := FTotalLength;
   LHashInstance.FTotalLength := FTotalLength;
   LHashInstance.FCompressionRounds := FCompressionRounds;
   LHashInstance.FCompressionRounds := FCompressionRounds;
   LHashInstance.FFinalizationRounds := FFinalizationRounds;
   LHashInstance.FFinalizationRounds := FFinalizationRounds;
@@ -102,30 +105,44 @@ begin
   result.BufferSize := BufferSize;
   result.BufferSize := BufferSize;
 end;
 end;
 
 
-constructor TSipHash2_4.Create;
+constructor TSipHash2_4.Create(ACompressionRounds, AFinalizationRounds: Int32);
 begin
 begin
-  Inherited Create(2, 4);
-
+  Inherited Create(8, 8);
+  FMagicXor := $FF;
+  FCompressionRounds := ACompressionRounds;
+  FFinalizationRounds := AFinalizationRounds;
 end;
 end;
 
 
 { TSipHash }
 { TSipHash }
 
 
 procedure TSipHash.Compress;
 procedure TSipHash.Compress;
+var
+  LV0, LV1, LV2, LV3: UInt64;
 begin
 begin
-  FV0 := FV0 + FV1;
-  FV2 := FV2 + FV3;
-  FV1 := TBits.RotateLeft64(FV1, 13);
-  FV3 := TBits.RotateLeft64(FV3, 16);
-  FV1 := FV1 xor FV0;
-  FV3 := FV3 xor FV2;
-  FV0 := TBits.RotateLeft64(FV0, 32);
-  FV2 := FV2 + FV1;
-  FV0 := FV0 + FV3;
-  FV1 := TBits.RotateLeft64(FV1, 17);
-  FV3 := TBits.RotateLeft64(FV3, 21);
-  FV1 := FV1 xor FV2;
-  FV3 := FV3 xor FV0;
-  FV2 := TBits.RotateLeft64(FV2, 32);
+  LV0 := FV0;
+  LV1 := FV1;
+  LV2 := FV2;
+  LV3 := FV3;
+
+  LV0 := LV0 + LV1;
+  LV2 := LV2 + LV3;
+  LV1 := TBits.RotateLeft64(LV1, 13);
+  LV3 := TBits.RotateLeft64(LV3, 16);
+  LV1 := LV1 xor LV0;
+  LV3 := LV3 xor LV2;
+  LV0 := TBits.RotateLeft64(LV0, 32);
+  LV2 := LV2 + LV1;
+  LV0 := LV0 + LV3;
+  LV1 := TBits.RotateLeft64(LV1, 17);
+  LV3 := TBits.RotateLeft64(LV3, 21);
+  LV1 := LV1 xor LV2;
+  LV3 := LV3 xor LV0;
+  LV2 := TBits.RotateLeft64(LV2, 32);
+
+  FV0 := LV0;
+  FV1 := LV1;
+  FV2 := LV2;
+  FV3 := LV3;
 end;
 end;
 
 
 procedure TSipHash.CompressTimes(ATimes: Int32);
 procedure TSipHash.CompressTimes(ATimes: Int32);
@@ -147,37 +164,9 @@ begin
   FV0 := FV0 xor ABlock;
   FV0 := FV0 xor ABlock;
 end;
 end;
 
 
-procedure TSipHash.ByteUpdate(AByte: Byte);
-var
-  LPtrBuffer: PByte;
-  LBlock: UInt64;
-begin
-  FBuffer[FIdx] := AByte;
-  System.Inc(FIdx);
-  if FIdx >= 8 then
-  begin
-    LPtrBuffer := PByte(FBuffer);
-    LBlock := TConverters.ReadBytesAsUInt64LE(LPtrBuffer, 0);
-    ProcessBlock(LBlock);
-    FIdx := 0;
-  end;
-end;
-
-constructor TSipHash.Create(ACompressionRounds, AFinalizationRounds: Int32);
+function TSipHash.ProcessFinalBlock: UInt64;
 begin
 begin
-  Inherited Create(8, 8);
-  FKey0 := KEY0;
-  FKey1 := KEY1;
-  FCompressionRounds := ACompressionRounds;
-  FFinalizationRounds := AFinalizationRounds;
-  System.SetLength(FBuffer, 8);
-end;
-
-procedure TSipHash.Finish;
-var
-  LFinalBlock: UInt64;
-begin
-  LFinalBlock := UInt64(FTotalLength and $FF) shl 56;
+  result := UInt64(FTotalLength and $FF) shl 56;
 
 
   if (FIdx <> 0) then
   if (FIdx <> 0) then
   begin
   begin
@@ -185,65 +174,83 @@ begin
 
 
       7:
       7:
         begin
         begin
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[6]) shl 48);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[5]) shl 40);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[4]) shl 32);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[3]) shl 24);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[2]) shl 16);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[1]) shl 8);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[0]));
+          result := result or (UInt64(FBuffer[6]) shl 48);
+          result := result or (UInt64(FBuffer[5]) shl 40);
+          result := result or (UInt64(FBuffer[4]) shl 32);
+          result := result or (UInt64(FBuffer[3]) shl 24);
+          result := result or (UInt64(FBuffer[2]) shl 16);
+          result := result or (UInt64(FBuffer[1]) shl 8);
+          result := result or (UInt64(FBuffer[0]));
         end;
         end;
       6:
       6:
         begin
         begin
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[5]) shl 40);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[4]) shl 32);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[3]) shl 24);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[2]) shl 16);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[1]) shl 8);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[0]));
+          result := result or (UInt64(FBuffer[5]) shl 40);
+          result := result or (UInt64(FBuffer[4]) shl 32);
+          result := result or (UInt64(FBuffer[3]) shl 24);
+          result := result or (UInt64(FBuffer[2]) shl 16);
+          result := result or (UInt64(FBuffer[1]) shl 8);
+          result := result or (UInt64(FBuffer[0]));
         end;
         end;
       5:
       5:
         begin
         begin
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[4]) shl 32);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[3]) shl 24);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[2]) shl 16);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[1]) shl 8);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[0]));
+          result := result or (UInt64(FBuffer[4]) shl 32);
+          result := result or (UInt64(FBuffer[3]) shl 24);
+          result := result or (UInt64(FBuffer[2]) shl 16);
+          result := result or (UInt64(FBuffer[1]) shl 8);
+          result := result or (UInt64(FBuffer[0]));
         end;
         end;
 
 
       4:
       4:
         begin
         begin
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[3]) shl 24);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[2]) shl 16);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[1]) shl 8);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[0]));
+          result := result or (UInt64(FBuffer[3]) shl 24);
+          result := result or (UInt64(FBuffer[2]) shl 16);
+          result := result or (UInt64(FBuffer[1]) shl 8);
+          result := result or (UInt64(FBuffer[0]));
         end;
         end;
 
 
       3:
       3:
         begin
         begin
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[2]) shl 16);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[1]) shl 8);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[0]));
+          result := result or (UInt64(FBuffer[2]) shl 16);
+          result := result or (UInt64(FBuffer[1]) shl 8);
+          result := result or (UInt64(FBuffer[0]));
         end;
         end;
 
 
       2:
       2:
         begin
         begin
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[1]) shl 8);
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[0]));
+          result := result or (UInt64(FBuffer[1]) shl 8);
+          result := result or (UInt64(FBuffer[0]));
         end;
         end;
 
 
       1:
       1:
         begin
         begin
-          LFinalBlock := LFinalBlock or (UInt64(FBuffer[0]));
+          result := result or (UInt64(FBuffer[0]));
         end;
         end;
     end;
     end;
   end;
   end;
+end;
 
 
-  FV3 := FV3 xor LFinalBlock;
-  CompressTimes(FCompressionRounds);
-  FV0 := FV0 xor LFinalBlock;
-  FV2 := FV2 xor $FF;
-  CompressTimes(FFinalizationRounds);
+procedure TSipHash.ByteUpdate(AByte: Byte);
+var
+  LPtrBuffer: PByte;
+  LBlock: UInt64;
+begin
+  FBuffer[FIdx] := AByte;
+  System.Inc(FIdx);
+  if FIdx >= 8 then
+  begin
+    LPtrBuffer := PByte(FBuffer);
+    LBlock := TConverters.ReadBytesAsUInt64LE(LPtrBuffer, 0);
+    ProcessBlock(LBlock);
+    FIdx := 0;
+  end;
+end;
+
+constructor TSipHash.Create(AHashSize, ABlockSize: Int32);
+begin
+  Inherited Create(AHashSize, ABlockSize);
+  FKey0 := KEY0;
+  FKey1 := KEY1;
+  System.SetLength(FBuffer, 8);
 end;
 end;
 
 
 function TSipHash.GetKey: THashLibByteArray;
 function TSipHash.GetKey: THashLibByteArray;
@@ -277,6 +284,15 @@ begin
   FV1 := FV1 xor FKey1;
   FV1 := FV1 xor FKey1;
   FV0 := FV0 xor FKey0;
   FV0 := FV0 xor FKey0;
 
 
+  FPartA := 0;
+
+  case HashSize of
+    16:
+      begin
+        FPartB := 0;
+        FV1 := FV1 xor $EE;
+      end;
+  end;
 end;
 end;
 
 
 procedure TSipHash.SetKey(const AValue: THashLibByteArray);
 procedure TSipHash.SetKey(const AValue: THashLibByteArray);
@@ -305,6 +321,7 @@ var
   LIdx, LLength, LBlockCount, LOffset: Int32;
   LIdx, LLength, LBlockCount, LOffset: Int32;
   LPtrData, LPtrBuffer: PByte;
   LPtrData, LPtrBuffer: PByte;
   LBlock: UInt64;
   LBlock: UInt64;
+  LPtrDataUInt64: PUInt64;
 begin
 begin
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
   System.Assert(AIndex >= 0);
   System.Assert(AIndex >= 0);
@@ -347,10 +364,10 @@ begin
   LBlockCount := LLength shr 3;
   LBlockCount := LLength shr 3;
 
 
   // body
   // body
-
+  LPtrDataUInt64 := PUInt64(LPtrData + AIndex);
   while LIdx < LBlockCount do
   while LIdx < LBlockCount do
   begin
   begin
-    LBlock := TConverters.ReadBytesAsUInt64LE(LPtrData, AIndex + (LIdx * 8));
+    LBlock := TConverters.ReadPUInt64AsUInt64LE(LPtrDataUInt64 + LIdx);
     ProcessBlock(LBlock);
     ProcessBlock(LBlock);
     System.Inc(LIdx);
     System.Inc(LIdx);
   end;
   end;
@@ -365,10 +382,47 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TSipHash.Finish;
+var
+  LFinalBlock: UInt64;
+begin
+  LFinalBlock := ProcessFinalBlock();
+
+  FV3 := FV3 xor LFinalBlock;
+  CompressTimes(FCompressionRounds);
+  FV0 := FV0 xor LFinalBlock;
+
+  FV2 := FV2 xor FMagicXor;
+  CompressTimes(FFinalizationRounds);
+  FPartA := FV0 xor FV1 xor FV2 xor FV3;
+
+  case HashSize of
+    16:
+      begin
+        FV1 := FV1 xor $DD;
+        CompressTimes(FFinalizationRounds);
+        FPartB := FV0 xor FV1 xor FV2 xor FV3;
+      end;
+  end;
+end;
+
 function TSipHash.TransformFinal: IHashResult;
 function TSipHash.TransformFinal: IHashResult;
+var
+  LBufferBytes: THashLibByteArray;
 begin
 begin
   Finish();
   Finish();
-  result := THashResult.Create(FV0 xor FV1 xor FV2 xor FV3);
+
+  System.SetLength(LBufferBytes, HashSize);
+  TConverters.ReadUInt64AsBytesLE(FPartA, LBufferBytes, 0);
+
+  case HashSize of
+    16:
+      begin
+        TConverters.ReadUInt64AsBytesLE(FPartB, LBufferBytes, 8);
+      end;
+  end;
+
+  result := THashResult.Create(LBufferBytes);
   Initialize();
   Initialize();
 end;
 end;
 
 

+ 63 - 0
src/libraries/hashlib4pascal/HlpSipHash128.pas

@@ -0,0 +1,63 @@
+unit HlpSipHash128;
+
+{$I HashLib.inc}
+
+interface
+
+uses
+{$IFDEF DELPHI}
+  HlpHash,
+{$ENDIF DELPHI}
+  HlpIHash,
+  HlpSipHash;
+
+type
+  /// <summary>
+  /// SipHash128 2 - 4 algorithm.
+  /// <summary>
+  TSipHash128_2_4 = class sealed(TSipHash)
+
+  public
+
+    constructor Create(ACompressionRounds: Int32 = 2;
+      AFinalizationRounds: Int32 = 4);
+    function Clone(): IHash; override;
+
+  end;
+
+implementation
+
+{ TSipHash128_2_4 }
+
+function TSipHash128_2_4.Clone: IHash;
+var
+  LHashInstance: TSipHash128_2_4;
+begin
+  LHashInstance := TSipHash128_2_4.Create();
+  LHashInstance.FV0 := FV0;
+  LHashInstance.FV1 := FV1;
+  LHashInstance.FV2 := FV2;
+  LHashInstance.FV3 := FV3;
+  LHashInstance.FKey0 := FKey0;
+  LHashInstance.FKey1 := FKey1;
+  LHashInstance.FPartA := FPartA;
+  LHashInstance.FPartB := FPartB;
+  LHashInstance.FTotalLength := FTotalLength;
+  LHashInstance.FCompressionRounds := FCompressionRounds;
+  LHashInstance.FFinalizationRounds := FFinalizationRounds;
+  LHashInstance.FIdx := FIdx;
+  LHashInstance.FBuffer := System.Copy(FBuffer);
+  result := LHashInstance as IHash;
+  result.BufferSize := BufferSize;
+end;
+
+constructor TSipHash128_2_4.Create(ACompressionRounds,
+  AFinalizationRounds: Int32);
+begin
+  Inherited Create(16, 8);
+  FMagicXor := $EE;
+  FCompressionRounds := ACompressionRounds;
+  FFinalizationRounds := AFinalizationRounds;
+end;
+
+end.

+ 6 - 9
src/libraries/hashlib4pascal/HlpSnefru.pas

@@ -10,7 +10,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpBits,
   HlpBits,
   HlpHashSize,
   HlpHashSize,
@@ -34,7 +33,7 @@ type
   strict private
   strict private
   var
   var
     FState: THashLibUInt32Array;
     FState: THashLibUInt32Array;
-    FSecurityLevel, FHashSize, FBlockSize: Int32;
+    FSecurityLevel: Int32;
 
 
   const
   const
     SShifts: array [0 .. 3] of Int32 = (16, 8, 16, 24);
     SShifts: array [0 .. 3] of Int32 = (16, 8, 16, 24);
@@ -90,7 +89,7 @@ function TSnefru.Clone(): IHash;
 var
 var
   LHashInstance: TSnefru;
   LHashInstance: TSnefru;
 begin
 begin
-  LHashInstance := TSnefru.Create(FSecurityLevel, GetSnefruHashSize(FHashSize));
+  LHashInstance := TSnefru.Create(FSecurityLevel, GetSnefruHashSize(HashSize));
   LHashInstance.FState := System.Copy(FState);
   LHashInstance.FState := System.Copy(FState);
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FBuffer := FBuffer.Clone();
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
   LHashInstance.FProcessedBytesCount := FProcessedBytesCount;
@@ -102,9 +101,7 @@ constructor TSnefru.Create(ASecurityLevel: Int32; AHashSize: THashSize);
 begin
 begin
   Inherited Create(Int32(AHashSize), 64 - (Int32(AHashSize)));
   Inherited Create(Int32(AHashSize), 64 - (Int32(AHashSize)));
   FSecurityLevel := Int32(ASecurityLevel);
   FSecurityLevel := Int32(ASecurityLevel);
-  FHashSize := HashSize;
-  FBlockSize := BlockSize;
-  System.SetLength(FState, FHashSize shr 2);
+  System.SetLength(FState, HashSize shr 2);
 end;
 end;
 
 
 procedure TSnefru.Finish;
 procedure TSnefru.Finish;
@@ -116,11 +113,11 @@ begin
   LBits := FProcessedBytesCount * 8;
   LBits := FProcessedBytesCount * 8;
   if FBuffer.Position > 0 then
   if FBuffer.Position > 0 then
   begin
   begin
-    LPadIndex := 2 * FBlockSize - FBuffer.Position - 8
+    LPadIndex := 2 * BlockSize - FBuffer.Position - 8
   end
   end
   else
   else
   begin
   begin
-    LPadIndex := FBlockSize - FBuffer.Position - 8;
+    LPadIndex := BlockSize - FBuffer.Position - 8;
   end;
   end;
 
 
   System.SetLength(LPad, LPadIndex + 8);
   System.SetLength(LPad, LPadIndex + 8);
@@ -232,7 +229,7 @@ begin
   FState[2] := FState[2] xor LWork[13];
   FState[2] := FState[2] xor LWork[13];
   FState[3] := FState[3] xor LWork[12];
   FState[3] := FState[3] xor LWork[12];
 
 
-  if (FHashSize = 32) then
+  if (HashSize = 32) then
   begin
   begin
     FState[4] := FState[4] xor LWork[11];
     FState[4] := FState[4] xor LWork[11];
     FState[5] := FState[5] xor LWork[10];
     FState[5] := FState[5] xor LWork[10];

+ 0 - 1
src/libraries/hashlib4pascal/HlpTiger.pas

@@ -9,7 +9,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpHashLibTypes,
   HlpHashLibTypes,
   HlpConverters,
   HlpConverters,

+ 0 - 1
src/libraries/hashlib4pascal/HlpTiger2.pas

@@ -9,7 +9,6 @@ uses
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
   HlpHash,
   HlpHash,
   HlpHashBuffer,
   HlpHashBuffer,
-  HlpBitConverter,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}
   HlpHashLibTypes,
   HlpHashLibTypes,
   HlpConverters,
   HlpConverters,

+ 0 - 1
src/libraries/hashlib4pascal/HlpWhirlPool.pas

@@ -10,7 +10,6 @@ uses
 {$ENDIF DELPHI2010}
 {$ENDIF DELPHI2010}
   HlpHashLibTypes,
   HlpHashLibTypes,
 {$IFDEF DELPHI}
 {$IFDEF DELPHI}
-  HlpBitConverter,
   HlpHashBuffer,
   HlpHashBuffer,
   HlpHash,
   HlpHash,
 {$ENDIF DELPHI}
 {$ENDIF DELPHI}

+ 26 - 21
src/libraries/hashlib4pascal/HlpXXHash32.pas

@@ -147,8 +147,9 @@ end;
 procedure TXXHash32.TransformBytes(const AData: THashLibByteArray;
 procedure TXXHash32.TransformBytes(const AData: THashLibByteArray;
   AIndex, ALength: Int32);
   AIndex, ALength: Int32);
 var
 var
-  V1, V2, V3, V4: UInt32;
+  LV1, LV2, LV3, LV4: UInt32;
   LPtrLimit, LPtrEnd, LPtrADataStart, LPtrMemoryStart, LPtrMemory: PByte;
   LPtrLimit, LPtrEnd, LPtrADataStart, LPtrMemoryStart, LPtrMemory: PByte;
+  LPtrADataStartCardinal: PCardinal;
 begin
 begin
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
   System.Assert(AIndex >= 0);
   System.Assert(AIndex >= 0);
@@ -193,33 +194,37 @@ begin
 
 
   if LPtrADataStart <= (LPtrEnd - 16) then
   if LPtrADataStart <= (LPtrEnd - 16) then
   begin
   begin
-    V1 := FState.FV1;
-    V2 := FState.FV2;
-    V3 := FState.FV3;
-    V4 := FState.FV4;
+    LV1 := FState.FV1;
+    LV2 := FState.FV2;
+    LV3 := FState.FV3;
+    LV4 := FState.FV4;
 
 
     LPtrLimit := LPtrEnd - 16;
     LPtrLimit := LPtrEnd - 16;
     repeat
     repeat
 
 
-      V1 := PRIME32_1 * TBits.RotateLeft32
-        (V1 + PRIME32_2 * TConverters.ReadBytesAsUInt32LE
-        (LPtrADataStart, 0), 13);
-      V2 := PRIME32_1 * TBits.RotateLeft32
-        (V2 + PRIME32_2 * TConverters.ReadBytesAsUInt32LE
-        (LPtrADataStart, 4), 13);
-      V3 := PRIME32_1 * TBits.RotateLeft32
-        (V3 + PRIME32_2 * TConverters.ReadBytesAsUInt32LE
-        (LPtrADataStart, 8), 13);
-      V4 := PRIME32_1 * TBits.RotateLeft32
-        (V4 + PRIME32_2 * TConverters.ReadBytesAsUInt32LE
-        (LPtrADataStart, 12), 13);
+      LPtrADataStartCardinal := PCardinal(LPtrADataStart);
+
+      LV1 := PRIME32_1 * TBits.RotateLeft32
+        (LV1 + PRIME32_2 * TConverters.ReadPCardinalAsUInt32LE
+        (LPtrADataStartCardinal), 13);
+      LV2 := PRIME32_1 * TBits.RotateLeft32
+        (LV2 + PRIME32_2 * TConverters.ReadPCardinalAsUInt32LE
+        (LPtrADataStartCardinal + 1), 13);
+      LV3 := PRIME32_1 * TBits.RotateLeft32
+        (LV3 + PRIME32_2 * TConverters.ReadPCardinalAsUInt32LE
+        (LPtrADataStartCardinal + 2), 13);
+      LV4 := PRIME32_1 * TBits.RotateLeft32
+        (LV4 + PRIME32_2 * TConverters.ReadPCardinalAsUInt32LE
+        (LPtrADataStartCardinal + 3), 13);
+
       System.Inc(LPtrADataStart, 16);
       System.Inc(LPtrADataStart, 16);
+
     until not(LPtrADataStart <= LPtrLimit);
     until not(LPtrADataStart <= LPtrLimit);
 
 
-    FState.FV1 := V1;
-    FState.FV2 := V2;
-    FState.FV3 := V3;
-    FState.FV4 := V4;
+    FState.FV1 := LV1;
+    FState.FV2 := LV2;
+    FState.FV3 := LV3;
+    FState.FV4 := LV4;
   end;
   end;
 
 
   if LPtrADataStart < LPtrEnd then
   if LPtrADataStart < LPtrEnd then

+ 43 - 36
src/libraries/hashlib4pascal/HlpXXHash64.pas

@@ -155,8 +155,9 @@ end;
 procedure TXXHash64.TransformBytes(const AData: THashLibByteArray;
 procedure TXXHash64.TransformBytes(const AData: THashLibByteArray;
   AIndex, ALength: Int32);
   AIndex, ALength: Int32);
 var
 var
-  V1, V2, V3, V4: UInt64;
+  LV1, LV2, LV3, LV4: UInt64;
   LPtrLimit, LPtrEnd, LPtrADataStart, LPtrMemoryStart, LPtrMemory: PByte;
   LPtrLimit, LPtrEnd, LPtrADataStart, LPtrMemoryStart, LPtrMemory: PByte;
+  LPtrADataStartUInt64: PUInt64;
 begin
 begin
 {$IFDEF DEBUG}
 {$IFDEF DEBUG}
   System.Assert(AIndex >= 0);
   System.Assert(AIndex >= 0);
@@ -200,33 +201,37 @@ begin
 
 
   if LPtrADataStart <= (LPtrEnd - 32) then
   if LPtrADataStart <= (LPtrEnd - 32) then
   begin
   begin
-    V1 := FState.FV1;
-    V2 := FState.FV2;
-    V3 := FState.FV3;
-    V4 := FState.FV4;
+    LV1 := FState.FV1;
+    LV2 := FState.FV2;
+    LV3 := FState.FV3;
+    LV4 := FState.FV4;
 
 
     LPtrLimit := LPtrEnd - 32;
     LPtrLimit := LPtrEnd - 32;
     repeat
     repeat
-      V1 := PRIME64_1 * TBits.RotateLeft64
-        (V1 + PRIME64_2 * TConverters.ReadBytesAsUInt64LE
-        (LPtrADataStart, 0), 31);
-      V2 := PRIME64_1 * TBits.RotateLeft64
-        (V2 + PRIME64_2 * TConverters.ReadBytesAsUInt64LE
-        (LPtrADataStart, 8), 31);
-      V3 := PRIME64_1 * TBits.RotateLeft64
-        (V3 + PRIME64_2 * TConverters.ReadBytesAsUInt64LE
-        (LPtrADataStart, 16), 31);
-      V4 := PRIME64_1 * TBits.RotateLeft64
-        (V4 + PRIME64_2 * TConverters.ReadBytesAsUInt64LE
-        (LPtrADataStart, 24), 31);
+
+      LPtrADataStartUInt64 := PUInt64(LPtrADataStart);
+
+      LV1 := PRIME64_1 * TBits.RotateLeft64
+        (LV1 + PRIME64_2 * TConverters.ReadPUInt64AsUInt64LE
+        (LPtrADataStartUInt64), 31);
+      LV2 := PRIME64_1 * TBits.RotateLeft64
+        (LV2 + PRIME64_2 * TConverters.ReadPUInt64AsUInt64LE
+        (LPtrADataStartUInt64 + 1), 31);
+      LV3 := PRIME64_1 * TBits.RotateLeft64
+        (LV3 + PRIME64_2 * TConverters.ReadPUInt64AsUInt64LE
+        (LPtrADataStartUInt64 + 2), 31);
+      LV4 := PRIME64_1 * TBits.RotateLeft64
+        (LV4 + PRIME64_2 * TConverters.ReadPUInt64AsUInt64LE
+        (LPtrADataStartUInt64 + 3), 31);
 
 
       System.Inc(LPtrADataStart, 32);
       System.Inc(LPtrADataStart, 32);
+
     until not(LPtrADataStart <= LPtrLimit);
     until not(LPtrADataStart <= LPtrLimit);
 
 
-    FState.FV1 := V1;
-    FState.FV2 := V2;
-    FState.FV3 := V3;
-    FState.FV4 := V4;
+    FState.FV1 := LV1;
+    FState.FV2 := LV2;
+    FState.FV3 := LV3;
+    FState.FV4 := LV4;
   end;
   end;
 
 
   if LPtrADataStart < LPtrEnd then
   if LPtrADataStart < LPtrEnd then
@@ -239,34 +244,36 @@ end;
 
 
 function TXXHash64.TransformFinal: IHashResult;
 function TXXHash64.TransformFinal: IHashResult;
 var
 var
-  V1, V2, V3, V4: UInt64;
+  LV1, LV2, LV3, LV4: UInt64;
   LPtrEnd, LPtrBuffer: PByte;
   LPtrEnd, LPtrBuffer: PByte;
 begin
 begin
 
 
   if FState.FTotalLength >= UInt64(32) then
   if FState.FTotalLength >= UInt64(32) then
   begin
   begin
-    V1 := FState.FV1;
-    V2 := FState.FV2;
-    V3 := FState.FV3;
-    V4 := FState.FV4;
+    LV1 := FState.FV1;
+    LV2 := FState.FV2;
+    LV3 := FState.FV3;
+    LV4 := FState.FV4;
 
 
-    FHash := TBits.RotateLeft64(V1, 1) + TBits.RotateLeft64(V2, 7) +
-      TBits.RotateLeft64(V3, 12) + TBits.RotateLeft64(V4, 18);
+    FHash := TBits.RotateLeft64(LV1, 1) + TBits.RotateLeft64(LV2, 7) +
+      TBits.RotateLeft64(LV3, 12) + TBits.RotateLeft64(LV4, 18);
 
 
-    V1 := TBits.RotateLeft64(V1 * PRIME64_2, 31) * PRIME64_1;
-    FHash := (FHash xor V1) * PRIME64_1 + PRIME64_4;
+    LV1 := TBits.RotateLeft64(LV1 * PRIME64_2, 31) * PRIME64_1;
+    FHash := (FHash xor LV1) * PRIME64_1 + PRIME64_4;
 
 
-    V2 := TBits.RotateLeft64(V2 * PRIME64_2, 31) * PRIME64_1;
-    FHash := (FHash xor V2) * PRIME64_1 + PRIME64_4;
+    LV2 := TBits.RotateLeft64(LV2 * PRIME64_2, 31) * PRIME64_1;
+    FHash := (FHash xor LV2) * PRIME64_1 + PRIME64_4;
 
 
-    V3 := TBits.RotateLeft64(V3 * PRIME64_2, 31) * PRIME64_1;
-    FHash := (FHash xor V3) * PRIME64_1 + PRIME64_4;
+    LV3 := TBits.RotateLeft64(LV3 * PRIME64_2, 31) * PRIME64_1;
+    FHash := (FHash xor LV3) * PRIME64_1 + PRIME64_4;
 
 
-    V4 := TBits.RotateLeft64(V4 * PRIME64_2, 31) * PRIME64_1;
-    FHash := (FHash xor V4) * PRIME64_1 + PRIME64_4;
+    LV4 := TBits.RotateLeft64(LV4 * PRIME64_2, 31) * PRIME64_1;
+    FHash := (FHash xor LV4) * PRIME64_1 + PRIME64_4;
   end
   end
   else
   else
+  begin
     FHash := FKey + PRIME64_5;
     FHash := FKey + PRIME64_5;
+  end;
 
 
   System.Inc(FHash, FState.FTotalLength);
   System.Inc(FHash, FState.FTotalLength);
 
 

+ 14 - 0
src/libraries/hashlib4pascal/README.md

@@ -90,6 +90,10 @@ Available Algorithms
  
  
  * `Keccak (224, 256, 288, 384, 512)`
  * `Keccak (224, 256, 288, 384, 512)`
 
 
+ * `Blake2BP`
+
+ * `Blake2SP`
+
 ### Key Derivation Functions
 ### Key Derivation Functions
 ----------------------------------------
 ----------------------------------------
 
 
@@ -108,11 +112,21 @@ Available Algorithms
 
 
 * `HMAC (all supported hashes)`
 * `HMAC (all supported hashes)`
 
 
+* `KMAC (KMAC128, KMAC256)`
+
+* `Blake2MAC (Blake2BMAC, Blake2SMAC)`
+
 ### XOF (Extendable Output Function)
 ### XOF (Extendable Output Function)
 ----------------------------------------
 ----------------------------------------
 
 
 * `Shake (Shake-128, Shake-256)`
 * `Shake (Shake-128, Shake-256)`
 
 
+* `CShake (CShake-128, CShake-256)`
+
+* `Blake2X (Blake2XS, Blake2XB)`
+
+* `KMACXOF (KMAC128XOF, KMAC256XOF)`
+
 ### Supported Compilers
 ### Supported Compilers
 ----------------------------------------
 ----------------------------------------