Browse Source

RandomHash: fix bug in optimised MemTransform3

Herman Schoenfeld 7 years ago
parent
commit
1059766bf0
2 changed files with 71 additions and 54 deletions
  1. 25 26
      src/core/URandomHash.pas
  2. 46 28
      src/tests/URandomHashTests.pas

+ 25 - 26
src/core/URandomHash.pas

@@ -143,15 +143,14 @@ type
     {$IFNDEF UNITTESTS}private{$ELSE}public{$ENDIF}
       FMurmurHash3_x86_32 : IHash;
       FHashAlg : array[0..17] of IHash;  // declared here to avoid race-condition during mining
-      function ContencateByteArrays(const AChunk1, AChunk2: TBytes): TBytes; inline;
-      procedure MemTransform1(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
-      procedure MemTransform2(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
-      procedure MemTransform3(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
-      procedure MemTransform4(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
-      procedure MemTransform5(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
-      procedure MemTransform6(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
-      procedure MemTransform7(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
-      procedure MemTransform8(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform1(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform2(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform3(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform4(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform5(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform6(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform7(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
+      procedure MemTransform8(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer); inline;
       function Expand(const AInput: TBytes; AExpansionFactor: Int32) : TBytes;
       function Compress(const AInputs: TArray<TBytes>): TBytes; inline;
       function ChangeNonce(const ABlockHeader: TBytes; ANonce: Int32): TBytes; inline;
@@ -691,14 +690,7 @@ begin
   end;
 end;
 
-function TRandomHashFast.ContencateByteArrays(const AChunk1, AChunk2: TBytes): TBytes;
-begin
-  SetLength(Result, Length(AChunk1) + Length(AChunk2));
-  Move(AChunk1[0], Result[0], Length(AChunk1));
-  Move(AChunk2[0], Result[Length(AChunk1)], Length(AChunk2));
-end;
-
-procedure TRandomHashFast.MemTransform1(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform1(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LReadEnd, LWriteEnd : UInt32;
   LState : UInt32;
@@ -718,7 +710,7 @@ begin
     ABuffer[i] := ABuffer[AReadStart + (TXorShift32.Next(LState) MOD ALength)];
 end;
 
-procedure TRandomHashFast.MemTransform2(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform2(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LReadEnd, LWriteEnd, LPivot, LOdd: Int32;
 begin
@@ -738,9 +730,10 @@ begin
     ABuffer[AWriteStart + LPivot] := ABuffer[AReadStart + LPivot];
 end;
 
-procedure TRandomHashFast.MemTransform3(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform3(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LReadEnd, LWriteEnd: Int32;
+  LReadPtr, LWritePtr : PByte;
 begin
   LReadEnd := AReadStart + ALength - 1;
   LWriteEnd := AWriteStart + ALength - 1;
@@ -749,11 +742,16 @@ begin
   if LWriteEnd >= Length(ABuffer) then
     raise EArgumentOutOfRangeException.Create(SBufferTooSmall);
 
-  for i := 0 to ALength do
-    ABuffer[AWriteStart + i] := ABuffer[AReadStart + ALength - i - 1];
+  LReadPtr := PByte(ABuffer) + AReadStart;
+  LWritePtr := PByte(ABuffer) + LWriteEnd;
+  for i := 0 to Pred(ALength) do begin
+    LWritePtr^ := LReadPtr^;
+    Inc(LReadPtr);
+    Dec(LWritePtr);
+  end;
 end;
 
-procedure TRandomHashFast.MemTransform4(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform4(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LReadEnd, LWriteEnd, LPivot, LOdd: Int32;
 begin
@@ -776,7 +774,7 @@ begin
     ABuffer[LWriteEnd] := ABuffer[AReadStart + LPivot];
 end;
 
-procedure TRandomHashFast.MemTransform5(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform5(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LReadEnd, LWriteEnd, LPivot, LOdd: Int32;
 begin
@@ -799,7 +797,7 @@ begin
     ABuffer[LWriteEnd] := ABuffer[AReadStart + LPivot];
 end;
 
-procedure TRandomHashFast.MemTransform6(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform6(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LReadEnd, LWriteEnd, LPivot, LOdd: Int32;
 begin
@@ -822,7 +820,7 @@ begin
     ABuffer[AWriteStart + LPivot] := ABuffer[AReadStart + ALength - 1];
 end;
 
-procedure TRandomHashFast.MemTransform7(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform7(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LReadEnd, LWriteEnd: Int32;
 begin
@@ -837,7 +835,7 @@ begin
     ABuffer[AWriteStart + i] := TBits.RotateLeft8(ABuffer[AReadStart + i], ALength - i);
 end;
 
-procedure TRandomHashFast.MemTransform8(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
+procedure TRandomHashFast.MemTransform8(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer);
 var
   i, LChunkLength, LReadEnd, LWriteEnd: Int32;
 begin
@@ -868,6 +866,7 @@ begin
   LReadEnd := LInputSize - 1;
   LCopyLen := LInputSize;
 
+
   while LReadEnd < Pred(Length(LOutput)) do
   begin
     if (LReadEnd + 1 + LCopyLen) > Length(LOutput) then

+ 46 - 28
src/tests/URandomHashTests.pas

@@ -22,9 +22,6 @@ type
   private
     procedure TestSubHash(AHasher : IHash; const ATestData : array of TTestItem<Integer, String>);
     procedure TestMemTransform(ATransform : TTransformProc; const ATestData : array of TTestItem<Integer, String>);
-  protected
-    procedure SetUp; override;
-    procedure TearDown; override;
   published
     procedure TestRandomHash_Standard;
     procedure TestRandomHash;
@@ -65,13 +62,10 @@ type
 
   TRandomHashFastTest = class(TPascalCoinUnitTest)
   public type
-    TFastTransformProc = procedure(const ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer) of object;
+    TFastTransformProc = procedure(var ABuffer: TBytes; AReadStart, AWriteStart, ALength : Integer) of object;
   private
     procedure TestMemTransform(ATransform : TFastTransformProc; const ATestData : array of TTestItem<Integer, String>);
     procedure TestMemTransform_Padding(ATransform : TFastTransformProc);
-  protected
-    procedure SetUp; override;
-    procedure TearDown; override;
   published
     procedure TestRandomHash_Standard;
     procedure TestRandomHash;
@@ -98,6 +92,14 @@ type
     procedure TestMemTransform8;
   end;
 
+  { TRandomHashStressTest }
+
+  TRandomHashStressTest = class(TPascalCoinUnitTest)
+  published
+    procedure Standard_1000_Hashes;
+    procedure Optimised_1000_Hashes;
+  end;
+
 implementation
 
 uses variants, UCommon, UCommon.Collections, UMemory, URandomHash, HlpHashFactory, HlpBitConverter, strutils;
@@ -771,16 +773,6 @@ const
 
 { TRandomHashTest }
 
-procedure TRandomHashTest.SetUp;
-begin
-  inherited;
-end;
-
-procedure TRandomHashTest.TearDown;
-begin
-  inherited;
-end;
-
 procedure TRandomHashTest.TestRandomHash_Standard;
 var
   LCase : TTestItem<String, String>;
@@ -1081,16 +1073,6 @@ end;
 
 { TRandomHashFastTest }
 
-procedure TRandomHashFastTest.SetUp;
-begin
-  inherited;
-end;
-
-procedure TRandomHashFastTest.TearDown;
-begin
-  inherited;
-end;
-
 procedure TRandomHashFastTest.TestRandomHash_Standard;
 var
   LCase : TTestItem<String, String>;
@@ -1215,7 +1197,6 @@ begin
   TestMemTransform_Padding(LHasher.MemTransform3);
 end;
 
-
 procedure TRandomHashFastTest.TestMemTransform4_Padding;
 var
   LHasher : TRandomHashFast;
@@ -1409,14 +1390,51 @@ begin
   end;
 end;
 
+{ TRandomHashStressTest }
+
+
+procedure TRandomHashStressTest.Standard_1000_Hashes;
+const
+  NUM_ITER = 1000;
+var
+  i : Integer;
+  LBuff : TBytes;
+  LHasher : TRandomHash;
+  LDisposables : TDisposables;
+begin
+  LBuff := ParseBytes(DATA_BYTES);
+  LHasher := LDisposables.AddObject( TRandomHash.Create ) as TRandomHash;
+  for i := 1 to NUM_ITER do
+    LBuff := LHasher.Hash(LBuff);
+  // no exceptions should occur
+end;
+
+procedure TRandomHashStressTest.Optimised_1000_Hashes;
+const
+  NUM_ITER = 1000;
+var
+  i : Integer;
+  LBuff : TBytes;
+  LHasher : TRandomHashFast;
+  LDisposables : TDisposables;
+begin
+  LBuff := ParseBytes(DATA_BYTES);
+  LHasher := LDisposables.AddObject( TRandomHashFast.Create ) as TRandomHashFast;
+  for i := 1 to NUM_ITER do
+    LBuff := LHasher.Hash(LBuff);
+  // no exceptions should occur
+end;
+
 initialization
 
 {$IFDEF FPC}
   RegisterTest(TRandomHashTest);
   RegisterTest(TRandomHashFastTest);
+  RegisterTest(TRandomHashStressTest);
 {$ELSE}
   TDUnitX.RegisterTextFixture(TRandomHashTest);
   TDUnitX.RegisterTextFixture(TRandomHashFastTest);
+  TDUnitX.RegisterTextFixture(TRandomHashStressTest);
 {$ENDIF FPC}
 
 end.