Code: Alles auswählen
;- SHA-256, Test für PB. Grundlage (Pseudo-Code) siehe engl. Wikipedia
;- "Helle" Klaus Helbing, 14.06.2011, PB 4.51 (x64)
;- 64-Bit-Windows-Version, hier für Dateien
Global Size.q
Global SizeAv.q
Global pSource.q
Global pAllBlocks.q
Global Chunks.q
Global ChunksSum.q
Global ChunksAll.q
Global pW.q
Global pHash.q
Global FreeMem.q
Global MemAv.q
Global a.l
Global b.l
Global c.l
Global d.l
Global e.l
Global f.l
Global g.l
Global h.l
If OpenWindow(0, 0, 0, 600, 400, "Helles SHA-256, 64-Bit-OS", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
  ;- freies RAM ermitteln
  SysInfo.SYSTEM_INFO
  Mem.MEMORYSTATUSEX
  ;- Größe der Struktur ermitteln und in ihr selbst speichern 
  Mem\dwLength = SizeOf(MEMORYSTATUSEX) 
  ;- vom System Speicherinfo holen
  GlobalMemoryStatusEx_(@Mem) 
  FreeMem = Mem\ullAvailPhys >> 1      ;halbieren  
  If FreeMem >= $40000000              ;1GB
    MemAv = $40000000
    Chunks = $1000000                  ;für 1GB
   ElseIf FreeMem >= $20000000         ;512MB
    MemAv = $20000000             
    Chunks = $800000                   ;für 512MB 
   Else
    MessageRequester("Abbruch !", "Ist mir zuwenig RAM !")
  EndIf
  ChunksOld = Chunks
  TextGadget(0, 10, 10, 230, 15, "Select a File :")
  ExplorerTreeGadget(1, 10, 30, 580, 360, "", #PB_Explorer_NoDriveRequester)   
  Repeat
    Event = WaitWindowEvent()
    If Event = #PB_Event_CloseWindow
      End
    EndIf
  Until EventType() = #PB_EventType_LeftDoubleClick And GetGadgetState(1) = #PB_Explorer_File
  File$ = GetGadgetText(1)
  FreeGadget(0) : FreeGadget(1)
  TA = ElapsedMilliseconds()
  TF = TA                              ;nur für Fortschritts-Balken
  ReadFile(0, File$)
  Size = Lof(0)
  SizeAv = Size
  ChunksAll = (Size / 64) + 1          ;nur für Fortschritts-Balken
  TextGadget(0, 10, 10, 560, 20, "File : " + File$)
  Size$ = Str(Size)                    ;für 1000-er Trennpunkte 
  LS = Len(Size$)
  LSMod = LS % 3
  If LSMod = 0
    LSMod = 3
  EndIf
  i = 3
  j = 1
  While LS - i > 0
    SizeP$ =  InsertString(Size$, ".", LSMod + j)
    i + 3
    Size$ = SizeP$
    j + 4
  Wend
  TextGadget(1, 10, 30, 560, 20, "File-Länge : " + SizeP$ + " Bytes")
  TextGadget(2, 25, 50, 550, 20, "Berechnungs-Fortschritt :", #PB_Text_Center)
  ProgressBarGadget(3, 25, 75, 550, 25, 0, 100, #PB_ProgressBar_Smooth)
  If Size <= MemAv
    MemAv = Size
  EndIf
  pW = AllocateMemory(256)
  pHash = AllocateMemory(32)           ;damit Hash-Startwerte erhalten bleiben
  CopyMemory(?HashBase, pHash, 32)
  pAllBlocks = AllocateMemory(MemAv + 128)  ;(großzügig bemessener) Speicher für die 512-Bit-Blöcke
  pAllBlocksOld = pAllBlocks
!File_Weiter:
  BytesRead = ReadData(0, pAllBlocks, MemAv)     ;Datei in Speicher einlesen
  Seek + BytesRead
  SizeAv - BytesRead
  If SizeAv = 0 
    CloseFile(0)
  EndIf
;Preprocessing, Size wird auf Vielfaches von 512 Bit (64 Byte) gebracht (Blocklänge ist 512 Bit)
!cmp [v_SizeAv],0
!jne End_Preprocessing
!mov r10,[v_pAllBlocks]
!mov rax,[v_MemAv]
!mov r8,rax
!mov r11,[v_Size]
!shl r11,3                   ;Länge in Bits!
!bswap r11                   ;Size auf Big-Endian bringen
!mov rcx,64                  ;512 Bit
!xor rdx,rdx                 ;hier mal so (ist ja unsigned)
!div rcx                     ;Modulo steht in rdx
!inc rax                     ;eine Runde wollen wir ja wenigstens! 
!mov [v_Chunks],rax
!mov rax,[v_MemAv]
!mov byte[r10+rax],80h       ;Bit mit Wert 1 anhängen (wird 1 durch bswap)  
!or rdx,rdx                  ;rdx=0?
!jnz @f                      ;nein
;1.Fall: Letzter 512-Bit-Block ist Vielfaches von 512 Bit (64 Byte). Es wird ein kompletter 512-Bit-Block angehängt 
!mov [r10+r8+56],r11         ;Original-Länge als 64-Bit-Big-Endian-Wert anhängen
!jmp End_Preprocessing
!@@:
!cmp rdx,56                  ;448 Bit
!jae @f
;2.Fall: Letzter 512-Bit-Block ist kleiner als 448 Bit (56 Byte), aber größer Null
!sub r8,rdx
!mov [r10+r8+56],r11         ;Original-Länge als 64-Bit-Big-Endian-Wert in den vorhandenen Block kopieren (Bytes 56-63)
!jmp End_Preprocessing
!@@:
;3.Fall: Letzter 512-Bit-Block ist größer/gleich als 448 Bit (56 Byte). Dieser Block wird aufgefüllt (Bitwert 1 drangehängt,
; Rest Null) und ein weiterer Block drangehängt mit Nullen und am Ende Original-Länge als 64-Bit-Big-Endian-Wert
!sub r8,rdx
!mov [r10+r8+120],r11        ;Original-Länge als 64-Bit-Big-Endian-Wert in den zusätzlichen Block kopieren (Bytes 56-63)
!inc [v_Chunks]              ;es wurde ja ein Block drangehängt
!End_Preprocessing:
!Next_Chunk:                 ;512 Bit (64 Byte)
;W[0] bis W[15]
!mov rcx,16
!mov r11,[v_pAllBlocks]
!mov r10,[v_pW]
!@@:
!mov eax,dword[r11]          ;(erweiterten) Source einlesen
!bswap eax                   ;auf Big-Endian bringen
!mov dword[r10],eax
!add r10,4
!add r11,4
!dec rcx
!jnz @b
;W[16] bis W[63]
!mov rcx,48
!mov r11,[v_pW]
!add r11,64
!@@:
;s0
!mov eax,dword[r11-60]
!mov edx,eax
!mov r10d,eax
!ror eax,7
!ror edx,18
!shr r10d,3
!xor eax,edx
!xor r10d,eax
;s1
!mov eax,dword[r11-8]
!mov edx,eax
!mov r8d,eax
!ror eax,17
!ror edx,19
!xor eax,edx
!shr r8d,10
!xor eax,r8d
;W[i]
!mov edx,dword[r11-64]
!add edx,r10d                ;r10d=s0
!add edx,dword[r11-28]
!add edx,eax                 ;eax=s1
!mov dword[r11],edx
!add r11,4
!dec rcx
!jnz @b
;Initialisierung
!mov r11,[v_pHash]                ;siehe Data
!mov eax,dword[r11]
!mov [v_a],eax
!mov eax,dword[r11+4]
!mov [v_b],eax
!mov eax,dword[r11+8]
!mov [v_c],eax
!mov eax,dword[r11+12]
!mov [v_d],eax
!mov eax,dword[r11+16]
!mov [v_e],eax
!mov eax,dword[r11+20]
!mov [v_f],eax
!mov eax,dword[r11+24]
!mov [v_g],eax
!mov eax,dword[r11+28]
!mov [v_h],eax
;Main Loop
!xor rcx,rcx                 ;hier mal so
!lea r11,[k]                 ;siehe Data
!@@:
;s0
!mov eax,[v_a]
!mov edx,eax
!mov r10d,eax
!ror eax,2
!ror edx,13
!xor eax,edx
!ror r10d,22
!xor r10d,eax                ;r10d=s0
;maj (major)
!mov eax,[v_a]
!mov edx,[v_b]
!mov r9d,[v_c]
!mov r8d,eax
!and r8d,edx
!and eax,r9d
!xor r8d,eax
!and edx,r9d
!xor r8d,edx                 ;r8d=maj
;t2
!add r8d,r10d                ;r8d=t2, r10d=s0
;s1
!mov eax,[v_e]
!mov edx,eax
!mov r10d,eax
!ror eax,6
!ror edx,11
!xor eax,edx
!ror r10d,25
!xor r10d,eax                ;r10d=s1
;ch
!mov eax,[v_e]
!mov edx,eax
!and edx,[v_f]
!not eax
!and eax,[v_g]
!xor edx,eax                 ;edx=ch
;t1
!mov eax,[v_h]
!add eax,r10d                ;s1
!add eax,edx                 ;ch
!add eax,dword[r11+rcx]      ;k[i]
!mov r10d,dword[v_pW]
!add eax,dword[r10+rcx]      ;eax=t1, r10+rcx=W[i]
;Vertauschungen
!mov edx,[v_g]
!mov [v_h],edx
!mov edx,[v_f]
!mov [v_g],edx
!mov edx,[v_e]
!mov [v_f],edx
!mov edx,[v_d]
!add edx,eax                 ;eax=t1
!mov [v_e],edx
!mov edx,[v_c]
!mov [v_d],edx
!mov edx,[v_b]
!mov [v_c],edx
!mov edx,[v_a]
!mov [v_b],edx
!add eax,r8d                 ;r8d=t2
!mov [v_a],eax
!add rcx,4
!cmp rcx,256
!jb @b
;am Ende jedes Chunks Hashs zu vorhandenen Werten aufaddieren
!mov r10,[v_pHash]
!mov eax,[v_a]
!add eax,dword[r10]
!mov [r10],eax
!mov eax,[v_b]
!add eax,dword[r10+4]
!mov [r10+4],eax
!mov eax,[v_c]
!add eax,dword[r10+8]
!mov [r10+8],eax
!mov eax,[v_d]
!add eax,dword[r10+12]
!mov [r10+12],eax
!mov eax,[v_e]
!add eax,dword[r10+16]
!mov [r10+16],eax
!mov eax,[v_f]
!add eax,dword[r10+20]
!mov [r10+20],eax
!mov eax,[v_g]
!add eax,dword[r10+24]
!mov [r10+24],eax
!mov eax,[v_h]
!add eax,dword[r10+28]
!mov dword[r10+28],eax
!add [v_pAllBlocks],64       ;512 Bit (64 Byte) weiter, nächster Chunk
!inc [v_ChunksSum]           ;nur für Fortschritts-Balken
  If ElapsedMilliseconds() - TF > 100
    TF = ElapsedMilliseconds()
    SetGadgetState(3, (ChunksSum * 100) / ChunksAll)
  EndIf
!dec [v_Chunks]
!jnz Next_Chunk
!cmp [v_SizeAv],0
!je @f
  FileSeek(0, Seek)
  pAllBlocks = pAllBlocksOld
  If SizeAv <= MemAv 
    MemAv = SizeAv
    FreeMemory(pAllBlocks)
    pAllBlocks = AllocateMemory(MemAv + 128)
   Else
    Chunks = ChunksOld
  EndIf
!jmp File_Weiter
!@@:
  FreeGadget(2) : FreeGadget(3)
  For i = 0 To 31 Step 4
    Hash$ + Hex(PeekL(pHash + i) & $FFFFFFFF)    ;bei Bedarf in Zwischenablage kopieren
  Next
  TE = ElapsedMilliseconds() - TA
  TextGadget(2, 10, 50, 560, 20, "SHA-256-Hash : " + Hash$)
  TE$ = Str(TE)                                  ;für 1000-er Trennpunkte 
  LT = Len(TE$)
  LTMod = LT % 3
  If LTMod = 0
    LTMod = 3
  EndIf
  i = 3
  j = 1
  While LT - i > 0
    TEP$ =  InsertString(TE$, ".", LTMod + j)
    i + 3
    TE$ = TEP$
    j + 4
  Wend
  TextGadget(3, 10, 70, 560, 20, "Benötigte Zeit : " +  TE$ + " ms")
 
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
End
DataSection
HashBase:
;!h0:                              ;Fractional_Parts_Square_2_19, Big-Endian!
  Data.l $6a09e667, $bb67ae85, $3c6ef372, $a54ff53a, $510e527f, $9b05688c, $1f83d9ab, $5be0cd19
!k:                               ;Fractional_Parts_Cube_2_311, Big-Endian!
  Data.l $428a2f98, $71374491, $b5c0fbcf, $e9b5dba5, $3956c25b, $59f111f1, $923f82a4, $ab1c5ed5
  Data.l $d807aa98, $12835b01, $243185be, $550c7dc3, $72be5d74, $80deb1fe, $9bdc06a7, $c19bf174
  Data.l $e49b69c1, $efbe4786, $0fc19dc6, $240ca1cc, $2de92c6f, $4a7484aa, $5cb0a9dc, $76f988da
  Data.l $983e5152, $a831c66d, $b00327c8, $bf597fc7, $c6e00bf3, $d5a79147, $06ca6351, $14292967
  Data.l $27b70a85, $2e1b2138, $4d2c6dfc, $53380d13, $650a7354, $766a0abb, $81c2c92e, $92722c85
  Data.l $a2bfe8a1, $a81a664b, $c24b8b70, $c76c51a3, $d192e819, $d6990624, $f40e3585, $106aa070
  Data.l $19a4c116, $1e376c08, $2748774c, $34b0bcb5, $391c0cb3, $4ed8aa4a, $5b9cca4f, $682e6ff3
  Data.l $748f82ee, $78a5636f, $84c87814, $8cc70208, $90befffa, $a4506ceb, $bef9a3f7, $c67178f2
EndDataSection
Viel Spaß!
Helle
Edit: 14.6.2011, nur Kosmetik