В процессоры была добавлена поддержка инструкций хеширования включая SHA1 и SHA256 https://en.wikipedia.org/wiki/Intel_SHA_extensions
Как показала практика на процессоре вычисление SHA1 выполняется примерно в 3 раза быстрее чем функциями PB.
Нужна версия PB не ниже 6.00 (или придется заменить компилятор фасма на версию из 6.00).
CompilerIf #PB_Compiler_Processor <> #PB_Processor_x64
CompilerError "Поддерживается только x64 платформа"
CompilerEndIf
CompilerIf #PB_Compiler_Version>=600
CompilerIf #PB_Compiler_Backend <> #PB_Backend_Asm
CompilerError "Поддерживается только компилятор ассемблера"
CompilerEndIf
CompilerElse
CompilerError "FASM не поддерживает SHA1 инструкции"
CompilerEndIf
DeclareModule CPU_SHA1
Declare IsCPU_SHA()
Declare CPU_StartFingerprint()
Declare CPU_CopyInstance(*Sha)
Declare CPU_AddFingerprintBuffer(*Sha, *Buffer, Size)
Declare.s CPU_GetSHA(*Sha)
Declare.s CPU_FinishFingerprint(*Sha)
Declare.s CPU_Fingerprint(*Buffer, Size)
Declare.s CPU_StringFingerprint(s.s)
EndDeclareModule
Module CPU_SHA1
EnableExplicit
#SHA1_ChunksSize = 64
Structure SHA_Data Align #PB_Structure_AlignC
xmm0.M128A
xmm1.M128A
AllSize.q
Buff.a[#SHA1_ChunksSize]
BuffSize.a
EndStructure
Procedure SetReg(*Sha.SHA_Data)
Protected xmm.M128A, *p
xmm = *Sha\xmm0
!movdqu xmm0, dqword[p.v_xmm]
xmm = *Sha\xmm1
!movdqu xmm1, dqword[p.v_xmm]
*p = ?PSHUFFLE_BYTE_FLIP_MASK
!mov rdi,[p.p_p]
!movdqu xmm7,[rdi]
DataSection
PSHUFFLE_BYTE_FLIP_MASK:
Data.q $08090a0b0c0d0e0f, $0001020304050607 ; like "bswap"
EndDataSection
EndProcedure
Procedure GetReg(*Sha.SHA_Data)
Protected *xmm.M128A
*xmm = *Sha\xmm0
!mov rdi,[p.p_xmm]
!movdqu [rdi],xmm0
*xmm = *Sha\xmm1
!mov rdi,[p.p_xmm]
!movdqu [rdi],xmm1
EndProcedure
Procedure SHA1_Calc(*Buff, CountChunks)
!mov rsi,[p.p_Buff]
!mov rcx,[p.v_CountChunks]
!@@:
!movdqa xmm8,xmm1
!movdqa xmm9,xmm0
;Rounds 0-3
!movdqu xmm3,[rsi]
!pshufb xmm3,xmm7
!paddd xmm1,xmm3
!movdqa xmm2,xmm0
!sha1rnds4 xmm0,xmm1,0
;Rounds 4-7
!movdqu xmm4,[rsi+16]
!pshufb xmm4,xmm7
!sha1nexte xmm2,xmm4
!movdqa xmm1,xmm0
!sha1rnds4 xmm0,xmm2,0
!sha1msg1 xmm3,xmm4
;Rounds 8-11
!movdqu xmm5,[rsi+32]
!pshufb xmm5,xmm7
!sha1nexte xmm1,xmm5
!movdqa xmm2,xmm0
!sha1rnds4 xmm0,xmm1,0
!sha1msg1 xmm4,xmm5
!pxor xmm3,xmm5
;Rounds 12-15
!movdqu xmm6,[rsi+48]
!pshufb xmm6,xmm7
!sha1nexte xmm2,xmm6
!movdqa xmm1,xmm0
!sha1msg2 xmm3,xmm6
!sha1rnds4 xmm0,xmm2,0
!sha1msg1 xmm5,xmm6
!pxor xmm4,xmm6
;Rounds 16-19
!sha1nexte xmm1,xmm3
!movdqa xmm2,xmm0
!sha1msg2 xmm4,xmm3
!sha1rnds4 xmm0,xmm1,0
!sha1msg1 xmm6,xmm3
!pxor xmm5,xmm3
;Rounds 20-23
!sha1nexte xmm2,xmm4
!movdqa xmm1,xmm0
!sha1msg2 xmm5,xmm4
!sha1rnds4 xmm0,xmm2,1
!sha1msg1 xmm3,xmm4
!pxor xmm6,xmm4
;Rounds 24-27
!sha1nexte xmm1,xmm5
!movdqa xmm2,xmm0
!sha1msg2 xmm6,xmm5
!sha1rnds4 xmm0,xmm1,1
!sha1msg1 xmm4,xmm5
!pxor xmm3,xmm5
;Rounds 28-31
!sha1nexte xmm2,xmm6
!movdqa xmm1,xmm0
!sha1msg2 xmm3,xmm6
!sha1rnds4 xmm0,xmm2,1
!sha1msg1 xmm5,xmm6
!pxor xmm4,xmm6
;Rounds 32-35
!sha1nexte xmm1,xmm3
!movdqa xmm2,xmm0
!sha1msg2 xmm4,xmm3
!sha1rnds4 xmm0,xmm1,1
!sha1msg1 xmm6,xmm3
!pxor xmm5,xmm3
;Rounds 36-39
!sha1nexte xmm2,xmm4
!movdqa xmm1,xmm0
!sha1msg2 xmm5,xmm4
!sha1rnds4 xmm0,xmm2,1
!sha1msg1 xmm3,xmm4
!pxor xmm6,xmm4
;Rounds 40-43
!sha1nexte xmm1,xmm5
!movdqa xmm2,xmm0
!sha1msg2 xmm6,xmm5
!sha1rnds4 xmm0,xmm1,2
!sha1msg1 xmm4,xmm5
!pxor xmm3,xmm5
;Rounds 44-47
!sha1nexte xmm2,xmm6
!movdqa xmm1,xmm0
!sha1msg2 xmm3,xmm6
!sha1rnds4 xmm0,xmm2,2
!sha1msg1 xmm5,xmm6
!pxor xmm4,xmm6
;Rounds 48-51
!sha1nexte xmm1,xmm3
!movdqa xmm2,xmm0
!sha1msg2 xmm4,xmm3
!sha1rnds4 xmm0,xmm1,2
!sha1msg1 xmm6,xmm3
!pxor xmm5,xmm3
;Rounds 52-55
!sha1nexte xmm2,xmm4
!movdqa xmm1,xmm0
!sha1msg2 xmm5,xmm4
!sha1rnds4 xmm0,xmm2,2
!sha1msg1 xmm3,xmm4
!pxor xmm6,xmm4
;Rounds 56-59
!sha1nexte xmm1,xmm5
!movdqa xmm2,xmm0
!sha1msg2 xmm6,xmm5
!sha1rnds4 xmm0,xmm1,2
!sha1msg1 xmm4,xmm5
!pxor xmm3,xmm5
;Rounds 60-63
!sha1nexte xmm2,xmm6
!movdqa xmm1,xmm0
!sha1msg2 xmm3,xmm6
!sha1rnds4 xmm0,xmm2,3
!sha1msg1 xmm5,xmm6
!pxor xmm4,xmm6
;Rounds 64-67
!sha1nexte xmm1,xmm3
!movdqa xmm2,xmm0
!sha1msg2 xmm4,xmm3
!sha1rnds4 xmm0,xmm1,3
!sha1msg1 xmm6,xmm3
!pxor xmm5,xmm3
;Rounds 68-71
!sha1nexte xmm2,xmm4
!movdqa xmm1,xmm0
!sha1msg2 xmm5,xmm4
!sha1rnds4 xmm0,xmm2,3
!pxor xmm6,xmm4
;Rounds 72-75
!sha1nexte xmm1,xmm5
!movdqa xmm2,xmm0
!sha1msg2 xmm6,xmm5
!sha1rnds4 xmm0,xmm1,3
;Rounds 76-79
!sha1nexte xmm2,xmm6
!movdqa xmm1,xmm0
!sha1rnds4 xmm0,xmm2,3
;Add current hash values with previously saved
!sha1nexte xmm1,xmm8
!paddd xmm0,xmm9
!add rsi,64
!dec rcx ;Chunks
!jnz @b
EndProcedure
; *****************
;- **** Public ****
; *****************
Procedure IsCPU_SHA()
Protected x.l=0
!mov eax,7
!xor ecx,ecx
!cpuid
!mov dword [p.v_x], ebx
ProcedureReturn Bool(x & $20000000)
EndProcedure
Procedure CPU_StartFingerprint()
Protected *p.SHA_Data = 0
*p = AllocateStructure(SHA_Data)
If *p
With *p
\BuffSize=0
\AllSize=0
CopyMemory(?CONST_H0_H4, @\xmm0, 16)
CopyMemory(?CONST_H0_H4+16, @\xmm1, 16)
EndWith
EndIf
ProcedureReturn *p
DataSection
CONST_H0_H4:
Data.l $10325476, $98BADCFE, $0EFCDAB89, $67452301, 0, 0, 0, $0C3D2E1F0 ; Start-Values H0-H4
EndDataSection
EndProcedure
Procedure CPU_CopyInstance(*Sha.SHA_Data)
Protected *p=0
If *Sha
*p = AllocateStructure(SHA_Data)
If *p
CopyStructure(*Sha, *p, SHA_Data)
EndIf
EndIf
ProcedureReturn *p
EndProcedure
Procedure CPU_AddFingerprintBuffer(*Sha.SHA_Data, *Buffer, Size)
Protected r = #False, *p=0, x, BuffPos=0
If *Sha And *Buffer And Size>0
r = #True
With *Sha
If \BuffSize>0
If \BuffSize+Size<=#SHA1_ChunksSize
CopyMemory(*Buffer, @\Buff[\BuffSize], Size)
\BuffSize+Size
Size=0
Else
x=#SHA1_ChunksSize-\BuffSize
CopyMemory(*Buffer, @\Buff[\BuffSize], x)
SetReg(*Sha)
SHA1_Calc(@\Buff, 1)
GetReg(*Sha)
\AllSize + #SHA1_ChunksSize
\BuffSize=0
BuffPos = x
Size - x
EndIf
EndIf
If Size>0
x = Size / #SHA1_ChunksSize
If x > 0
SetReg(*Sha)
SHA1_Calc(*Buffer + BuffPos, x)
GetReg(*Sha)
\AllSize + x * #SHA1_ChunksSize
EndIf
x = Size % #SHA1_ChunksSize
If x>0
CopyMemory(*Buffer + BuffPos + (Size-x), @\Buff[\BuffSize], x)
\BuffSize+x
EndIf
EndIf
EndWith
EndIf
ProcedureReturn r
EndProcedure
Procedure.s CPU_GetSHA(*Sha.SHA_Data)
Protected r.s, Size, *p=0, i
If *Sha
*p = AllocateMemory(#SHA1_ChunksSize)
If *p
With *Sha
If (\BuffSize=0 Or \BuffSize>=56) And \BuffSize<#SHA1_ChunksSize
\Buff[\BuffSize]=$80
For i=\BuffSize+1 To #SHA1_ChunksSize-1
\Buff[i]=0
Next
i=\AllSize+\BuffSize
!mov rax,[p.v_i]
!shl rax,3
!bswap rax
!mov [p.v_i],rax ;Bits to encoded
If \BuffSize=0
PokeB(*p, $80)
EndIf
PokeQ(*p + #SHA1_ChunksSize - 8, i)
SetReg(*Sha)
If \BuffSize>0
SHA1_Calc(@\Buff, 1)
EndIf
SHA1_Calc(*p, 1)
ElseIf \BuffSize<56
\Buff[\BuffSize]=$80
i=\AllSize+\BuffSize
!mov rax,[p.v_i]
!shl rax,3
!bswap rax
!mov [p.v_i],rax ;Bits to encoded
PokeQ(@\Buff[56], i)
SetReg(*Sha)
SHA1_Calc(@\Buff, 1)
Else
CallDebugger
EndIf
EndWith
!mov rdi,[p.p_p]
!pshufd xmm0,xmm0,1bh
!movdqu [rdi],xmm0
!pextrd [rdi+16],xmm1,3
For i = 0 To 16 Step 4
r + RSet(Hex(PeekL(*p + i) & $FFFFFFFF), 8, "0")
Next
FreeMemory(*p)
EndIf
EndIf
ProcedureReturn r
EndProcedure
Procedure.s CPU_FinishFingerprint(*Sha.SHA_Data)
Protected r.s
If *Sha
r = CPU_GetSHA(*Sha)
FreeStructure(*Sha)
EndIf
ProcedureReturn r
EndProcedure
Procedure.s CPU_Fingerprint(*Buffer, Size)
Protected r.s, *p
*p=CPU_StartFingerprint()
If *p
CPU_AddFingerprintBuffer(*p, *Buffer, Size)
r = CPU_FinishFingerprint(*p)
EndIf
ProcedureReturn r
EndProcedure
Procedure.s CPU_StringFingerprint(s.s)
Protected r.s, *p=UTF8(s)
If *p
r = CPU_Fingerprint(*p, MemorySize(*p)-1)
FreeMemory(*p)
EndIf
ProcedureReturn r
EndProcedure
EndModuleВ первую очередь проверьте поддерживает ли процессор необходимые инструкции.
UseModule CPU_SHA1 If IsCPU_SHA() Debug "SHA инструкции поддерживаются" Else Debug "SHA инструкции НЕ поддерживаются" EndIf
Если не поддерживает, значит пора обновлять комп.
Стандартный тест из вики
UseSHA1Fingerprint() UseModule CPU_SHA1 s.s="В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!" Debug CPU_StringFingerprint(s) Debug StringFingerprint(s, #PB_Cipher_SHA1)
Тоже с лисицей и собакой
UseSHA1Fingerprint() UseModule CPU_SHA1 s.s="The quick brown fox jumps over the lazy dog." Debug CPU_StringFingerprint(s) Debug StringFingerprint(s, #PB_Cipher_SHA1)
Хеширование 1 ГБ случайных данных для сравнения скорости CPU и функций PB.
UseSHA1Fingerprint()
UseModule CPU_SHA1
Count = 100
Size=10*1024*1024
*Buff = AllocateMemory(Size)
If *Buff
RandomData(*Buff, Size)
Define sPB.s, sCPU.s, tPB, tCPU, i
tPB = ElapsedMilliseconds()
If StartFingerprint(0, #PB_Cipher_SHA1)
For i = 1 To Count
AddFingerprintBuffer(0, *Buff, Size)
Next
sPB = UCase(FinishFingerprint(0))
EndIf
tPB = ElapsedMilliseconds() - tPB
tCPU = ElapsedMilliseconds()
*p=CPU_StartFingerprint()
If *p
For i = 1 To Count
CPU_AddFingerprintBuffer(*p, *Buff, Size)
Next
sCPU = CPU_FinishFingerprint(*p)
EndIf
tCPU = ElapsedMilliseconds() - tCPU
MessageRequester("",~"PB \nВремя = "+tPB+~" мс\n"+sPB+~"\n\nCPU\nВремя = "+tCPU+~" мс\n"+sCPU)
FreeMemory(*Buff)
EndIf