Skip to content

Commit 9367b14

Browse files
committed
SHA1 SIMD Implementation
1 parent 8348f7d commit 9367b14

10 files changed

Lines changed: 1316 additions & 7 deletions

File tree

HashLib.Benchmark/Delphi/PerformanceBenchmarkConsole.dpr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ uses
4141
HlpRIPEMD320 in '..\..\HashLib\src\Crypto\HlpRIPEMD320.pas',
4242
HlpSHA0 in '..\..\HashLib\src\Crypto\HlpSHA0.pas',
4343
HlpSHA1 in '..\..\HashLib\src\Crypto\HlpSHA1.pas',
44+
HlpSHA1Dispatch in '..\..\HashLib\src\Crypto\HlpSHA1Dispatch.pas',
4445
HlpSHA2_224 in '..\..\HashLib\src\Crypto\HlpSHA2_224.pas',
4546
HlpSHA2_256 in '..\..\HashLib\src\Crypto\HlpSHA2_256.pas',
4647
HlpSHA2_256Dispatch in '..\..\HashLib\src\Crypto\HlpSHA2_256Dispatch.pas',

HashLib.Benchmark/Delphi/PerformanceBenchmarkFMX.dpr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ uses
4040
HlpRIPEMD320 in '..\..\HashLib\src\Crypto\HlpRIPEMD320.pas',
4141
HlpSHA0 in '..\..\HashLib\src\Crypto\HlpSHA0.pas',
4242
HlpSHA1 in '..\..\HashLib\src\Crypto\HlpSHA1.pas',
43+
HlpSHA1Dispatch in '..\..\HashLib\src\Crypto\HlpSHA1Dispatch.pas',
4344
HlpSHA2_224 in '..\..\HashLib\src\Crypto\HlpSHA2_224.pas',
4445
HlpSHA2_256 in '..\..\HashLib\src\Crypto\HlpSHA2_256.pas',
4546
HlpSHA2_256Dispatch in '..\..\HashLib\src\Crypto\HlpSHA2_256Dispatch.pas',

HashLib/src/Crypto/HlpSHA1.pas

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@ interface
66

77
uses
88
HlpBits,
9+
HlpHashLibTypes,
910
HlpSHA0,
10-
HlpIHash;
11+
HlpIHash,
12+
HlpSHA1Dispatch;
1113

1214
type
1315
TSHA1 = class sealed(TSHA0)
1416

1517
strict protected
1618
procedure Expand(AData: PCardinal); override;
19+
procedure TransformBlock(AData: PByte; ADataLength: Int32;
20+
AIndex: Int32); override;
1721

1822
public
19-
// Not really needed because there is an Intristic default constructor always
20-
// called for classes if none is defined by the developer but I just put it
21-
// for readability reasons.
2223
constructor Create();
2324
function Clone(): IHash; override;
25+
procedure TransformBytes(const AData: THashLibByteArray;
26+
AIndex, ALength: Int32); override;
2427

2528
end;
2629

@@ -45,6 +48,51 @@ constructor TSHA1.Create;
4548
inherited Create();
4649
end;
4750

51+
procedure TSHA1.TransformBlock(AData: PByte; ADataLength: Int32;
52+
AIndex: Int32);
53+
begin
54+
SHA1_Compress(@FState[0], AData + AIndex, 1);
55+
end;
56+
57+
procedure TSHA1.TransformBytes(const AData: THashLibByteArray;
58+
AIndex, ALength: Int32);
59+
var
60+
LPtrData: PByte;
61+
LBlockCount: Int32;
62+
begin
63+
{$IFDEF DEBUG}
64+
System.Assert(AIndex >= 0);
65+
System.Assert(ALength >= 0);
66+
System.Assert(AIndex + ALength <= System.Length(AData));
67+
{$ENDIF DEBUG}
68+
LPtrData := PByte(AData);
69+
70+
if (not FBuffer.IsEmpty) then
71+
begin
72+
if (FBuffer.Feed(LPtrData, System.Length(AData), AIndex, ALength,
73+
FProcessedBytesCount)) then
74+
begin
75+
TransformBuffer();
76+
end;
77+
end;
78+
79+
LBlockCount := ALength div FBuffer.Length;
80+
if LBlockCount > 0 then
81+
begin
82+
FProcessedBytesCount := FProcessedBytesCount +
83+
UInt64(LBlockCount) * UInt64(FBuffer.Length);
84+
SHA1_Compress(@FState[0], LPtrData + AIndex, UInt32(LBlockCount));
85+
AIndex := AIndex + (LBlockCount * FBuffer.Length);
86+
ALength := ALength - (LBlockCount * FBuffer.Length);
87+
end;
88+
89+
if (ALength > 0) then
90+
begin
91+
FBuffer.Feed(LPtrData, System.Length(AData), AIndex, ALength,
92+
FProcessedBytesCount);
93+
end;
94+
end;
95+
4896
procedure TSHA1.Expand(AData: PCardinal);
4997
var
5098
{$IFNDEF USE_UNROLLED_VARIANT}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
unit HlpSHA1Dispatch;
2+
3+
{$I ..\Include\HashLib.inc}
4+
5+
interface
6+
7+
type
8+
TSHA1CompressProc = procedure(AState, AData: Pointer; ANumBlocks: UInt32);
9+
10+
var
11+
SHA1_Compress: TSHA1CompressProc;
12+
13+
const
14+
// BSWAP32 mask for pshufb: reverses bytes within each dword (big-endian to little-endian)
15+
K_SHA1: array [0 .. 3] of UInt32 = (
16+
$00010203, $04050607, $08090A0B, $0C0D0E0F
17+
);
18+
19+
implementation
20+
21+
uses
22+
HlpBits,
23+
HlpConverters,
24+
HlpSimd;
25+
26+
// =============================================================================
27+
// Scalar fallback implementation
28+
// =============================================================================
29+
30+
procedure SHA1_Compress_Scalar(AState, AData: Pointer; ANumBlocks: UInt32);
31+
var
32+
LPState: PCardinal;
33+
LPData: PByte;
34+
LA, LB, LC, LD, LE, LT: UInt32;
35+
LW: array [0 .. 79] of UInt32;
36+
LRound: Int32;
37+
begin
38+
LPState := PCardinal(AState);
39+
LPData := PByte(AData);
40+
41+
while ANumBlocks > 0 do
42+
begin
43+
TConverters.be32_copy(LPData, 0, @LW[0], 0, 64);
44+
45+
for LRound := 16 to 79 do
46+
begin
47+
LT := LW[LRound - 3] xor LW[LRound - 8] xor LW[LRound - 14]
48+
xor LW[LRound - 16];
49+
LW[LRound] := TBits.RotateLeft32(LT, 1);
50+
end;
51+
52+
LA := LPState[0]; LB := LPState[1]; LC := LPState[2];
53+
LD := LPState[3]; LE := LPState[4];
54+
55+
for LRound := 0 to 19 do
56+
begin
57+
LT := TBits.RotateLeft32(LA, 5) + (LD xor (LB and (LC xor LD)))
58+
+ LE + $5A827999 + LW[LRound];
59+
LE := LD; LD := LC; LC := TBits.RotateLeft32(LB, 30);
60+
LB := LA; LA := LT;
61+
end;
62+
63+
for LRound := 20 to 39 do
64+
begin
65+
LT := TBits.RotateLeft32(LA, 5) + (LB xor LC xor LD)
66+
+ LE + $6ED9EBA1 + LW[LRound];
67+
LE := LD; LD := LC; LC := TBits.RotateLeft32(LB, 30);
68+
LB := LA; LA := LT;
69+
end;
70+
71+
for LRound := 40 to 59 do
72+
begin
73+
LT := TBits.RotateLeft32(LA, 5) +
74+
((LB and LC) or (LD and (LB or LC)))
75+
+ LE + $8F1BBCDC + LW[LRound];
76+
LE := LD; LD := LC; LC := TBits.RotateLeft32(LB, 30);
77+
LB := LA; LA := LT;
78+
end;
79+
80+
for LRound := 60 to 79 do
81+
begin
82+
LT := TBits.RotateLeft32(LA, 5) + (LB xor LC xor LD)
83+
+ LE + $CA62C1D6 + LW[LRound];
84+
LE := LD; LD := LC; LC := TBits.RotateLeft32(LB, 30);
85+
LB := LA; LA := LT;
86+
end;
87+
88+
LPState[0] := LPState[0] + LA; LPState[1] := LPState[1] + LB;
89+
LPState[2] := LPState[2] + LC; LPState[3] := LPState[3] + LD;
90+
LPState[4] := LPState[4] + LE;
91+
92+
System.FillChar(LW, System.SizeOf(LW), 0);
93+
System.Inc(LPData, 64);
94+
System.Dec(ANumBlocks);
95+
end;
96+
end;
97+
98+
// =============================================================================
99+
// SIMD implementations (x86-64 only)
100+
// =============================================================================
101+
102+
{$IFDEF HASHLIB_X86_64}
103+
104+
procedure SHA1_Compress_shani(AState, AData: Pointer; ANumBlocks: UInt32;
105+
AConstants: Pointer);
106+
{$I ..\Include\Simd\Common\SimdProc4Begin.inc}
107+
{$I ..\Include\Simd\SHA1\SHA1CompressShaNi.inc}
108+
end;
109+
110+
procedure SHA1_Compress_shani_wrap(AState, AData: Pointer; ANumBlocks: UInt32);
111+
begin
112+
SHA1_Compress_shani(AState, AData, ANumBlocks, @K_SHA1);
113+
end;
114+
115+
procedure SHA1_Compress_ssse3(AState, AData: Pointer; ANumBlocks: UInt32;
116+
AConstants: Pointer);
117+
{$I ..\Include\Simd\Common\SimdProc4Begin.inc}
118+
{$I ..\Include\Simd\SHA1\SHA1CompressSsse3.inc}
119+
end;
120+
121+
procedure SHA1_Compress_ssse3_wrap(AState, AData: Pointer; ANumBlocks: UInt32);
122+
begin
123+
SHA1_Compress_ssse3(AState, AData, ANumBlocks, @K_SHA1);
124+
end;
125+
126+
{$IFDEF HASHLIB_AVX2_ASM_SUPPORTED}
127+
128+
procedure SHA1_Compress_avx2(AState, AData: Pointer; ANumBlocks: UInt32;
129+
AConstants: Pointer);
130+
{$I ..\Include\Simd\Common\SimdProc4Begin.inc}
131+
{$I ..\Include\Simd\SHA1\SHA1CompressAvx2.inc}
132+
end;
133+
134+
procedure SHA1_Compress_avx2_wrap(AState, AData: Pointer; ANumBlocks: UInt32);
135+
begin
136+
SHA1_Compress_avx2(AState, AData, ANumBlocks, @K_SHA1);
137+
end;
138+
139+
{$ENDIF HASHLIB_AVX2_ASM_SUPPORTED}
140+
141+
{$ENDIF HASHLIB_X86_64}
142+
143+
// =============================================================================
144+
// Dispatch initialization
145+
// =============================================================================
146+
147+
procedure InitDispatch();
148+
begin
149+
{$IFDEF HASHLIB_X86_64}
150+
if TSimd.HasSHANI() and (TSimd.GetActiveLevel() >= TSimdLevel.SSSE3) then
151+
begin
152+
SHA1_Compress := @SHA1_Compress_shani_wrap;
153+
Exit;
154+
end;
155+
{$IFDEF HASHLIB_AVX2_ASM_SUPPORTED}
156+
if TSimd.GetActiveLevel() >= TSimdLevel.AVX2 then
157+
begin
158+
SHA1_Compress := @SHA1_Compress_avx2_wrap;
159+
Exit;
160+
end;
161+
{$ENDIF HASHLIB_AVX2_ASM_SUPPORTED}
162+
if TSimd.GetActiveLevel() >= TSimdLevel.SSSE3 then
163+
begin
164+
SHA1_Compress := @SHA1_Compress_ssse3_wrap;
165+
Exit;
166+
end;
167+
{$ENDIF}
168+
SHA1_Compress := @SHA1_Compress_Scalar;
169+
end;
170+
171+
initialization
172+
InitDispatch();
173+
174+
end.

0 commit comments

Comments
 (0)