Code: Select all
;======================================================================
; Module: SHA3.pbi
;
; Author: sec, wilbert
; Date: Sep 11, 2013
; Version: 1.4.8
; Target Compiler: PureBasic 5.20+
; Target OS: All
; License: Free, unrestricted, no warranty whatsoever
; Use at your own risk
;======================================================================
DeclareModule SHA3
#Keccakf_MMX = 1 ; 1 for CPU with MMX - 0 for oringal
Structure SHA3Context
state.q[25]
pos.a
rsiz.a ; number of message bytes processed by permutation
hsiz.a ; size of hash in bytes
EndStructure
;-Exported functions
Declare$ Fingerprint(*Buffer, Size, Mode=224)
Declare$ FileFingerprint(Filename$, Mode=224, Offset.q=0, Length.q=0, ProgressBarGadgetNr=-1)
Declare SHA3_init(*ctx.SHA3Context, hsiz.i)
Declare SHA3_update(*ctx.SHA3Context, *Data, len)
Declare$ SHA3_final(*ctx.SHA3Context)
EndDeclareModule
Module SHA3
EnableExplicit
;- Variable, Structure, Data
;credit: Danilo
Structure QuadArray
q.q[0]
EndStructure
Structure WordArray
w.w[0]
EndStructure
Structure AArray
a.a[0]
EndStructure
DataSection
_rndc:
!dq 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000, 0x000000000000808B, 0x0000000080000001
!dq 0x8000000080008081, 0x8000000000008009, 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A
!dq 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 0x8000000000000080
!dq 0x000000000000800A, 0x800000008000000A, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
_rotc:
!dq 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14
!dq 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
_piln:
!dq 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
_hex_bytes:
!db '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
!db '202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f'
!db '404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f'
!db '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f'
!db '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
!db 'a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf'
!db 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf'
!db 'e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'
EndDataSection
Procedure BufferXOR(*Src, *Dest, Length)
!mov ecx, [p.v_Length]
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov r8, [p.p_Src]
!mov r9, [p.p_Dest]
CompilerElse
!mov eax, [p.p_Src]
!mov edx, [p.p_Dest]
!push ebx
CompilerEndIf
!cmp ecx, 1
!jge sha3.l_bufferxor_loop0_ep
!jmp sha3.l_bufferxor_exit
!sha3.l_bufferxor_loop0:
!dec ecx
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov al, [r8 + rcx]
!xor [r9 + rcx], al
CompilerElse
!mov bl, [eax + ecx]
!xor [edx + ecx], bl
CompilerEndIf
!sha3.l_bufferxor_loop0_ep:
!test ecx, 7
!jz sha3.l_bufferxor_loop1_ep
!jmp sha3.l_bufferxor_loop0
!sha3.l_bufferxor_loop1:
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rax, [r8 + rcx]
!xor [r9 + rcx], rax
CompilerElse
!mov ebx, [eax + ecx]
!xor [edx + ecx], ebx
!mov ebx, [eax + ecx + 4]
!xor [edx + ecx + 4], ebx
CompilerEndIf
!sha3.l_bufferxor_loop1_ep:
!sub ecx, 8
!jnc sha3.l_bufferxor_loop1
!sha3.l_bufferxor_exit:
CompilerIf #PB_Compiler_Processor <> #PB_Processor_x64
!pop ebx
CompilerEndIf
EndProcedure
CompilerIf #Keccakf_MMX = 1
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
Macro KECCAKF_M_MEM2MM(mm_reg, offset)
!movq mm_reg, [rdx + offset]
EndMacro
Macro KECCAKF_M_MM2MEM(mm_reg, offset)
!movq [rdx + offset], mm_reg
EndMacro
Macro KECCAKF_M_THETA_XOR(reg, offset)
!pxor reg, [rdx + rcx + offset]
EndMacro
CompilerElse
Macro KECCAKF_M_MEM2MM(mm_reg, offset)
!movq mm_reg, [edx + offset]
EndMacro
Macro KECCAKF_M_MM2MEM(mm_reg, offset)
!movq [edx + offset], mm_reg
EndMacro
Macro KECCAKF_M_THETA_XOR(reg, offset)
!pxor reg, [edx + ecx + offset]
EndMacro
CompilerEndIf
Macro KECCAKF_M_THETA_(offset)
KECCAKF_M_MEM2MM(mm6, offset)
!pxor mm6, mm5
KECCAKF_M_MM2MEM(mm6, offset)
EndMacro
Macro KECCAKF_M_THETA(reg1, reg2, offset)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!movq r9, reg2
!rol r9, 1
!movq mm5, r9
CompilerElse
!movq mm5, reg2
!movq mm6, mm5
!psllq mm5, 1
!psrlq mm6, 63
!por mm5, mm6
CompilerEndIf
!pxor mm5, reg1
KECCAKF_M_THETA_(offset)
KECCAKF_M_THETA_(offset + 40)
KECCAKF_M_THETA_(offset + 80)
KECCAKF_M_THETA_(offset + 120)
KECCAKF_M_THETA_(offset + 160)
EndMacro
Macro KECCAKF_M_RHO_PHI(piln, rotc)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!movq r9, mm7
!rol r9, rotc
!movq mm7, [rdx + piln * 8]
!mov [rdx + piln * 8], r9
CompilerElse
!movq mm6, mm7
!movq mm5, mm6
!psllq mm5, rotc
!psrlq mm6, 64-rotc
!por mm5, mm6
!movq mm7, [edx + piln * 8]
!movq [edx + piln * 8], mm5
CompilerEndIf
EndMacro
Macro KECCAKF_M_CHI_(reg1, reg2, reg3, offset)
!movq mm5, reg1
!pandn mm5, reg2
!pxor mm5, reg3
KECCAKF_M_MM2MEM(mm5, offset)
EndMacro
Macro KECCAKF_M_CHI(offset)
KECCAKF_M_MEM2MM(mm0, offset)
KECCAKF_M_MEM2MM(mm1, offset + 8)
KECCAKF_M_MEM2MM(mm2, offset + 16)
KECCAKF_M_MEM2MM(mm3, offset + 24)
KECCAKF_M_MEM2MM(mm4, offset + 32)
KECCAKF_M_CHI_(mm1, mm2, mm0, offset)
KECCAKF_M_CHI_(mm2, mm3, mm1, offset + 8)
KECCAKF_M_CHI_(mm3, mm4, mm2, offset + 16)
KECCAKF_M_CHI_(mm4, mm0, mm3, offset + 24)
KECCAKF_M_CHI_(mm0, mm1, mm4, offset + 32)
EndMacro
Procedure keccakf(*st); mmx version (mm0 - mm4 = bc)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!lea r8, [sha3.l__rndc]
!mov rdx, [p.p_st]
CompilerElse
!mov edx, [p.p_st]
CompilerEndIf
!xor eax, eax
!sha3.l_keccakf_loop:
;Theta
KECCAKF_M_MEM2MM(mm0, 0)
KECCAKF_M_MEM2MM(mm1, 8)
KECCAKF_M_MEM2MM(mm2, 16)
KECCAKF_M_MEM2MM(mm3, 24)
KECCAKF_M_MEM2MM(mm4, 32)
!mov ecx, 160
!sha3.l_keccakf_theta_loop:
KECCAKF_M_THETA_XOR(mm0, 0)
KECCAKF_M_THETA_XOR(mm1, 8)
KECCAKF_M_THETA_XOR(mm2, 16)
KECCAKF_M_THETA_XOR(mm3, 24)
KECCAKF_M_THETA_XOR(mm4, 32)
!sub ecx, 40
!jnz sha3.l_keccakf_theta_loop
KECCAKF_M_THETA(mm4, mm1, 0)
KECCAKF_M_THETA(mm0, mm2, 8)
KECCAKF_M_THETA(mm1, mm3, 16)
KECCAKF_M_THETA(mm2, mm4, 24)
KECCAKF_M_THETA(mm3, mm0, 32)
;Rho Pi
KECCAKF_M_MEM2MM(mm7, 8)
KECCAKF_M_RHO_PHI(10, 1)
KECCAKF_M_RHO_PHI(7, 3)
KECCAKF_M_RHO_PHI(11, 6)
KECCAKF_M_RHO_PHI(17, 10)
KECCAKF_M_RHO_PHI(18, 15)
KECCAKF_M_RHO_PHI(3, 21)
KECCAKF_M_RHO_PHI(5, 28)
KECCAKF_M_RHO_PHI(16, 36)
KECCAKF_M_RHO_PHI(8, 45)
KECCAKF_M_RHO_PHI(21, 55)
KECCAKF_M_RHO_PHI(24, 2)
KECCAKF_M_RHO_PHI(4, 14)
KECCAKF_M_RHO_PHI(15, 27)
KECCAKF_M_RHO_PHI(23, 41)
KECCAKF_M_RHO_PHI(19, 56)
KECCAKF_M_RHO_PHI(13, 8)
KECCAKF_M_RHO_PHI(12, 25)
KECCAKF_M_RHO_PHI(2, 43)
KECCAKF_M_RHO_PHI(20, 62)
KECCAKF_M_RHO_PHI(14, 18)
KECCAKF_M_RHO_PHI(22, 39)
KECCAKF_M_RHO_PHI(9, 61)
KECCAKF_M_RHO_PHI(6, 20)
KECCAKF_M_RHO_PHI(1, 44)
;Chi
KECCAKF_M_CHI(0)
KECCAKF_M_CHI(40)
KECCAKF_M_CHI(80)
KECCAKF_M_CHI(120)
KECCAKF_M_CHI(160)
;Iota
KECCAKF_M_MEM2MM(mm5, 0)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!pxor mm5, [r8 + rax * 8]
CompilerElse
!pxor mm5, [sha3.l__rndc + eax * 8]
CompilerEndIf
KECCAKF_M_MM2MEM(mm5, 0)
!inc eax
!cmp eax, 24; keccak rounds
!jne sha3.l_keccakf_loop
!emms
EndProcedure
CompilerElse
Procedure.q Rotl64(val.q, n)
!mov ecx, [p.v_n]
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rax, [p.v_val]
!rol rax, cl
CompilerElse
!btr ecx, 5
!jc rotl64_1
!mov eax, [p.v_val]
!mov edx, [p.v_val + 4]
!jmp rotl64_2
!rotl64_1:
!mov edx, [p.v_val]
!mov eax, [p.v_val + 4]
!rotl64_2:
!push ebx
!mov ebx, eax
!shld eax, edx, cl
!shld edx, ebx, cl
!pop ebx
CompilerEndIf
ProcedureReturn
EndProcedure
Procedure keccakf(*st.QuadArray)
Define *rndc.QuadArray = ?_rndc
Define *rotc.QuadArray = ?_rotc
Define *piln.QuadArray = ?_piln
Define.i i, j, round
Define.q t
Dim bc.q(5-1)
For round = 0 To 23
;Theta
For i = 0 To 4
bc(i) = *st\q[i] ! *st\q[i + 5] ! *st\q[i + 10] ! *st\q[i + 15] ! *st\q[i + 20]
Next
For i = 0 To 4
t = bc((i + 4) % 5) ! ROTL64(bc((i + 1) % 5), 1)
For j = 0 To 24 Step 5
*st\q[j + i] ! t
Next
Next
;Rho Pi
t = *st\q[1]
For i = 0 To 23
j = *piln\q[i]
bc(0) = *st\q[j]
*st\q[j] = ROTL64(t, *rotc\q[i])
t = bc(0)
Next
;Chi
For j = 0 To 24 Step 5
For i = 0 To 4
bc(i) = *st\q[j + i]
Next
For i = 0 To 4
*st\q[j + i] ! ((~bc((i + 1) % 5)) & bc((i + 2) % 5))
Next
Next
;Iota
*st\q[0] ! *rndc\q[round]
Next
EndProcedure
CompilerEndIf
Procedure SHA3_init(*ctx.SHA3Context, hsiz.i)
FillMemory(*ctx, SizeOf(SHA3Context))
Select hsiz
Case 512
*ctx\hsiz = 64
*ctx\rsiz = 72
Case 384
*ctx\hsiz = 48
*ctx\rsiz = 104
Case 256
*ctx\hsiz = 32
*ctx\rsiz = 136
Default; 224
*ctx\hsiz = 28
*ctx\rsiz = 144
EndSelect
EndProcedure
Procedure SHA3_update(*ctx.SHA3Context, *Data, len)
Define.i absorb
While len
absorb = *ctx\rsiz - *ctx\pos
If len < absorb
absorb = len
EndIf
BufferXOR(*Data, *ctx + *ctx\pos, absorb)
*Data + absorb
len - absorb
*ctx\pos + absorb
If *ctx\pos = *ctx\rsiz
keccakf(*ctx)
*ctx\pos = 0
EndIf
Wend
EndProcedure
Procedure$ SHA3_final(*ctx.SHA3Context)
Dim hash.w(64)
Define *hex_bytes.WordArray = ?_hex_bytes
Define *st.AArray = *ctx
Define.i i
*st\a[*ctx\pos] ! 1
*st\a[*ctx\rsiz - 1] ! $80
keccakf(*ctx)
While i < *ctx\hsiz
hash(i) = *hex_bytes\w[*st\a[i]]
i + 1
Wend
ProcedureReturn PeekS(@hash(), -1, #PB_Ascii)
EndProcedure
;-Exported functions
Procedure$ FileFingerprint(Filename$, Mode=224, Offset.q=0, Length.q=0, ProgressBarGadgetNr=-1)
#gnChunkSize = 1024 * 32; 32 KiB
Dim DataChunk.q(#gnChunkSize >> 3)
Define hash.s, file.i, error.i, ctx.SHA3Context
Define.q nBytes, nTotalBytes, nTotalBytesRead
file = ReadFile(#PB_Any, Filename$)
If file
nTotalBytes = Lof(file)
If Offset < nTotalBytes
FileSeek(file, Offset)
If Length = 0
Length = nTotalBytes
EndIf
If Offset + Length > nTotalBytes
Length = nTotalBytes - Offset
EndIf
nTotalBytes = Length
SHA3_init(@ctx, Mode)
While Length > 0
nBytes = ReadData(file, @DataChunk(), #gnChunkSize)
If nBytes
If nBytes > Length
nBytes = Length
EndIf
SHA3_update(@ctx, @DataChunk(), nBytes)
Length - nBytes
nTotalBytesRead + nBytes
If ProgressBarGadgetNr >= 0 And IsGadget(ProgressBarGadgetNr)
SetGadgetState(ProgressBarGadgetNr, 100 * nTotalBytesRead / nTotalBytes)
EndIf
Else
error = #True
Break
EndIf
Wend
If error <> #True
hash = SHA3_final(@ctx)
EndIf
EndIf
CloseFile(file)
EndIf
ProcedureReturn hash
EndProcedure
Procedure$ Fingerprint(*Buffer, Size, Mode=224)
Define ctx.SHA3Context
SHA3_init(@ctx, Mode)
SHA3_update(@ctx, *Buffer, Size)
ProcedureReturn SHA3_final(@ctx)
EndProcedure
EndModule
Version: 1.4.1
- initiation
Version: 1.4.2
- Threadsafe (remove Global variables)
Version: 1.4.3
- Remove junks
Version: 1.4.4
- use PeekA instead of PeekC (@wilbert)
Version: 1.4.5
- add support CPU MMX it's 20x faster, #Keccakf_MMX switch and turn on by default
- add wilbert to author
Version: 1.4.6
- Many things changed, the sha3 function has better speed than the popular hash on internet (hat off to guru wilbert )
- Here is exported functions, structure, const:
- Remove junks#Keccakf_MMX = 1 ; 1 for CPU with MMX - 0 for oringal
Structure SHA3Context
state.q[25]
pos.a
rsiz.a ; number of message bytes processed by permutation
hsiz.a ; size of hash in bytes
EndStructure
;-Exported functions
Declare$ Fingerprint(*Buffer, Size, Mode=224)
Declare$ FileFingerprint(Filename$, Mode=224, Offset.q=0, Length.q=0, ProgressBarGadgetNr=-1)
Declare SHA3_init(*ctx.SHA3Context, hsiz.i)
Declare SHA3_update(*ctx.SHA3Context, *Data, len)
Declare$ SHA3_final(*ctx.SHA3Context)
Version: 1.4.7
- optimize the 64 bit code by guru wilbert
Version: 1.4.8
- another update improving speed by wilbert