Seite 2 von 2

Re: SHA256?

Verfasst: 13.06.2011 20:42
von Helle
Danke für die Rückmeldung! Hier die 64-Bit-Windows-Version, ausgeführt für Files:

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
Für eine 4.6 GB große Datei werden ca. 43 Sekunden benötigt (Intel i7-2600).
Viel Spaß!
Helle

Edit: 14.6.2011, nur Kosmetik

Re: SHA256?

Verfasst: 13.06.2011 21:11
von SebastianJu2
Nicht schlecht auch noch für 64 Bit... :)

Ich habe mal versucht die erste Version in eine Prozedur umzuwandeln damit man es besser aufrufen kann. Dabei ist mir aufgefallen dass beim zweiten Aufruf des selben Strings ein anderes Ergebnis rauskommt. Es muss wohl an irgendwelchen Variablen liegen die noch gefüllt sind nehme ich an. Allerdings habe ich versucht alle Variablen welche in PB definiert sind bei der Definition auf 0 zu setzen um zu vermeiden dass das passiert. Es hat aber nichts gebracht. Kann das noch etwas im FASM sein das mit alten Variableninhalten arbeitet?

Hier mal meine leicht veränderte Version. Das FASM verstehe ich ohnehin noch nicht so weit als dass ich da etwas ändern könnte... :)

Code: Alles auswählen

EnableExplicit

;- SHA-256, Test für PB. Grundlage (Pseudo-Code) siehe engl. Wikipedia
;- "Helle" Klaus Helbing, 12.06.2011, PB4.51 (x86)
;- 32-Bit-Windows, kein Unicode
Procedure.s sha256(pSource)

  Global.l SourceLength, pAllBlocks, Chunks, pW, a, b, c, d, e, f, g, h, i
  Define.s Hash$
  
  SourceLength = Len(PeekS(pSource))                  ;Länge des Teststrings
  pAllBlocks = AllocateMemory(SourceLength + 128)     ;(großzügig bemessener) Speicher für die 512-Blöcke
  pW = AllocateMemory(256)
  
  ;der Einfachheit halber wird der Teststring in den 512-Bit-Block-Speicher umkopiert
  CopyMemory(pSource, pAllBlocks, SourceLength)
  
  !pushad
  ;Preprocessing, SourceLength wird auf Vielfaches von 512 Bit (64 Byte) gebracht (Blocklänge ist 512 Bit)
  !mov edi,[v_pAllBlocks]
  !mov eax,[v_SourceLength]
  !mov ebx,eax
  !mov esi,eax
  !shl esi,3                   ;Länge in Bits!
  !bswap esi                   ;SourceLength auf Big-Endian bringen
  
  !mov ecx,64                  ;512 Bit
  !cdq
  !div ecx                     ;Modulo steht in edx
  !inc eax                     ;eine Runde wollen wir ja wenigstens!
  !mov [v_Chunks],eax
  !mov eax,[v_SourceLength]
  !mov byte[edi+eax],80h       ;Bit mit Wert 1 anhängen (wird 1 durch bswap) 
  !or edx,edx                  ;edx=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 [edi+ebx+60],esi        ;Original-Länge als 64-Bit-Big-Endian-Wert anhängen
  !jmp End_Preprocessing
  !@@:
  !cmp edx,56                  ;448 Bit
  !jae @f
  ;2.Fall: Letzter 512-Bit-Block ist kleiner als 448 Bit (56 Byte), aber größer Null
  !sub ebx,edx
  !mov [edi+ebx+60],esi        ;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 ebx,edx
  !mov [edi+ebx+124],esi       ;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 ecx,16
  !mov esi,[v_pAllBlocks]
  !mov edi,[v_pW]
  !@@:
  !mov eax,[esi]               ;(erweiterten) Source einlesen
  !bswap eax                   ;auf Big-Endian bringen
  !mov [edi],eax
  !add edi,4
  !add esi,4
  !dec ecx
  !jnz @b
  
  ;W[16] bis W[63]
  !mov ecx,48
  !mov esi,[v_pW]
  !add esi,64
  !@@:
  ;s0
  !mov eax,[esi-60]
  !mov edx,eax
  !mov edi,eax
  !ror eax,7
  !ror edx,18
  !shr edi,3
  !xor eax,edx
  !xor edi,eax
  ;s1
  !mov eax,[esi-8]
  !mov edx,eax
  !mov ebx,eax
  !ror eax,17
  !ror edx,19
  !xor eax,edx
  !shr ebx,10
  !xor eax,ebx
  ;W[i]
  !mov edx,[esi-64]
  !add edx,edi                 ;edi=s0
  !add edx,[esi-28]
  !add edx,eax                 ;eax=s1
  !mov [esi],edx
  !add esi,4
  !dec ecx
  !jnz @b
  
  ;Initialisierung
  !lea esi,[h0]                ;siehe Data
  !mov eax,[esi]
  !mov [v_a],eax
  !mov eax,[esi+4]
  !mov [v_b],eax
  !mov eax,[esi+8]
  !mov [v_c],eax
  !mov eax,[esi+12]
  !mov [v_d],eax
  !mov eax,[esi+16]
  !mov [v_e],eax
  !mov eax,[esi+20]
  !mov [v_f],eax
  !mov eax,[esi+24]
  !mov [v_g],eax
  !mov eax,[esi+28]
  !mov [v_h],eax
  
  ;Main Loop
  !xor ecx,ecx                 ;hier mal so
  !lea esi,[k]                 ;siehe Data
  !@@:
  ;s0
  !mov eax,[v_a]
  !mov edx,eax
  !mov edi,eax
  !ror eax,2
  !ror edx,13
  !xor eax,edx
  !ror edi,22
  !xor edi,eax                 ;edi=s0
  ;maj (major)
  !mov eax,[v_a]
  !mov edx,[v_b]
  !mov ebx,eax
  !and ebx,edx
  !and eax,[v_c]               ;Verwendung von ebp habe ich mir verkniffen
  !xor ebx,eax
  !and edx,[v_c]
  !xor ebx,edx                 ;ebx=maj
  ;t2
  !add ebx,edi                 ;ebx=t2, edi=s0
  ;s1
  !mov eax,[v_e]
  !mov edx,eax
  !mov edi,eax
  !ror eax,6
  !ror edx,11
  !xor eax,edx
  !ror edi,25
  !xor edi,eax                 ;edi=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,edi                 ;s1
  !add eax,edx                 ;ch
  !add eax,[esi+ecx]           ;k[i]
  !mov edi,[v_pW]
  !add eax,[edi+ecx]           ;eax=t1, edi+ecx=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,ebx                 ;ebx=t2
  !mov [v_a],eax
  
  !add ecx,4
  !cmp ecx,256
  !jb @b
  
  ;am Ende jedes Chunks Hashs zu vorhandenen Werten aufaddieren
  !lea edi,[h0]
  !mov eax,[v_a]
  !add eax,[edi]
  !mov [edi],eax
  !mov eax,[v_b]
  !add eax,[edi+4]
  !mov [edi+4],eax
  !mov eax,[v_c]
  !add eax,[edi+8]
  !mov [edi+8],eax
  !mov eax,[v_d]
  !add eax,[edi+12]
  !mov [edi+12],eax
  !mov eax,[v_e]
  !add eax,[edi+16]
  !mov [edi+16],eax
  !mov eax,[v_f]
  !add eax,[edi+20]
  !mov [edi+20],eax
  !mov eax,[v_g]
  !add eax,[edi+24]
  !mov [edi+24],eax
  !mov eax,[v_h]
  !add eax,[edi+28]
  !mov [edi+28],eax
  
  !add [v_pAllBlocks],64       ;512 Bit (64 Byte) weiter, nächster Chunk
  
  !dec [v_Chunks]
  !jnz Next_Chunk
  
  !popad
  
  For i = 0 To 31 Step 4
    Hash$ + Hex(PeekL(?Hash + i) & $FFFFFFFF)
  Next
  ProcedureReturn Hash$
  End
  
;   Vergleichswerte:
;   "" = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
;   "abc" = BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD
;   "abcd" = 88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589
;   "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern"
;   = d32b568cd1b96d459e7291ebf4b25d007f275c9f13149beeb782fac0716613f8
;   "Frank jagt im komplett verwahrlosten Taxi quer durch Bayern"
;   = 78206a866dbb2bf017d8e34274aed01a8ce405b69d45db30bafa00f5eeed7d5e
  
  DataSection
  Hash:
  !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
EndProcedure


Debug sha256(@"Franz jagt im komplett verwahrlosten Taxi quer durch Bayern")
Debug sha256(@"Franz jagt im komplett verwahrlosten Taxi quer durch Bayern")

Re: SHA256?

Verfasst: 13.06.2011 21:40
von Helle
Nee, hat nichts mit FAsm zu tun :mrgreen: ! Die Werte h0 werden überschrieben (sind ja der Hashwert). Für den mehrmaligen Gebrauch (ohne Programm-Neustart) müssen sie wieder restauriert werden; zb.so:

Code: Alles auswählen

EnableExplicit

;- SHA-256, Test für PB. Grundlage (Pseudo-Code) siehe engl. Wikipedia
;- "Helle" Klaus Helbing, 12.06.2011, PB4.51 (x86)
;- 32-Bit-Windows, kein Unicode
Procedure.s sha256(pSource)

  Global.l SourceLength, pAllBlocks, Chunks, pW, a, b, c, d, e, f, g, h, i
  Define.s Hash$
 
  SourceLength = Len(PeekS(pSource))                  ;Länge des Teststrings
  pAllBlocks = AllocateMemory(SourceLength + 128)     ;(großzügig bemessener) Speicher für die 512-Blöcke
  pW = AllocateMemory(256)
 
  ;der Einfachheit halber wird der Teststring in den 512-Bit-Block-Speicher umkopiert
  CopyMemory(pSource, pAllBlocks, SourceLength)
 
  !pushad
  ;Preprocessing, SourceLength wird auf Vielfaches von 512 Bit (64 Byte) gebracht (Blocklänge ist 512 Bit)

  !lea esi,[h1]                ;siehe Data
  !lea edi,[h0]
  !mov eax,[esi]
  !mov [edi],eax
  !mov eax,[esi+4]
  !mov [edi+4],eax
  !mov eax,[esi+8]
  !mov [edi+8],eax
  !mov eax,[esi+12]
  !mov [edi+12],eax
  !mov eax,[esi+16]
  !mov [edi+16],eax
  !mov eax,[esi+20]
  !mov [edi+20],eax
  !mov eax,[esi+24]
  !mov [edi+24],eax
  !mov eax,[esi+28]
  !mov [edi+28],eax

  !mov edi,[v_pAllBlocks]
  !mov eax,[v_SourceLength]
  !mov ebx,eax
  !mov esi,eax
  !shl esi,3                   ;Länge in Bits!
  !bswap esi                   ;SourceLength auf Big-Endian bringen
 
  !mov ecx,64                  ;512 Bit
  !cdq
  !div ecx                     ;Modulo steht in edx
  !inc eax                     ;eine Runde wollen wir ja wenigstens!
  !mov [v_Chunks],eax
  !mov eax,[v_SourceLength]
  !mov byte[edi+eax],80h       ;Bit mit Wert 1 anhängen (wird 1 durch bswap)
  !or edx,edx                  ;edx=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 [edi+ebx+60],esi        ;Original-Länge als 64-Bit-Big-Endian-Wert anhängen
  !jmp End_Preprocessing
  !@@:
  !cmp edx,56                  ;448 Bit
  !jae @f
  ;2.Fall: Letzter 512-Bit-Block ist kleiner als 448 Bit (56 Byte), aber größer Null
  !sub ebx,edx
  !mov [edi+ebx+60],esi        ;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 ebx,edx
  !mov [edi+ebx+124],esi       ;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 ecx,16
  !mov esi,[v_pAllBlocks]
  !mov edi,[v_pW]
  !@@:
  !mov eax,[esi]               ;(erweiterten) Source einlesen
  !bswap eax                   ;auf Big-Endian bringen
  !mov [edi],eax
  !add edi,4
  !add esi,4
  !dec ecx
  !jnz @b
 
  ;W[16] bis W[63]
  !mov ecx,48
  !mov esi,[v_pW]
  !add esi,64
  !@@:
  ;s0
  !mov eax,[esi-60]
  !mov edx,eax
  !mov edi,eax
  !ror eax,7
  !ror edx,18
  !shr edi,3
  !xor eax,edx
  !xor edi,eax
  ;s1
  !mov eax,[esi-8]
  !mov edx,eax
  !mov ebx,eax
  !ror eax,17
  !ror edx,19
  !xor eax,edx
  !shr ebx,10
  !xor eax,ebx
  ;W[i]
  !mov edx,[esi-64]
  !add edx,edi                 ;edi=s0
  !add edx,[esi-28]
  !add edx,eax                 ;eax=s1
  !mov [esi],edx
  !add esi,4
  !dec ecx
  !jnz @b
 
  ;Initialisierung
  !lea esi,[h0]                ;siehe Data
  !mov eax,[esi]
  !mov [v_a],eax
  !mov eax,[esi+4]
  !mov [v_b],eax
  !mov eax,[esi+8]
  !mov [v_c],eax
  !mov eax,[esi+12]
  !mov [v_d],eax
  !mov eax,[esi+16]
  !mov [v_e],eax
  !mov eax,[esi+20]
  !mov [v_f],eax
  !mov eax,[esi+24]
  !mov [v_g],eax
  !mov eax,[esi+28]
  !mov [v_h],eax
 
  ;Main Loop
  !xor ecx,ecx                 ;hier mal so
  !lea esi,[k]                 ;siehe Data
  !@@:
  ;s0
  !mov eax,[v_a]
  !mov edx,eax
  !mov edi,eax
  !ror eax,2
  !ror edx,13
  !xor eax,edx
  !ror edi,22
  !xor edi,eax                 ;edi=s0
  ;maj (major)
  !mov eax,[v_a]
  !mov edx,[v_b]
  !mov ebx,eax
  !and ebx,edx
  !and eax,[v_c]               ;Verwendung von ebp habe ich mir verkniffen
  !xor ebx,eax
  !and edx,[v_c]
  !xor ebx,edx                 ;ebx=maj
  ;t2
  !add ebx,edi                 ;ebx=t2, edi=s0
  ;s1
  !mov eax,[v_e]
  !mov edx,eax
  !mov edi,eax
  !ror eax,6
  !ror edx,11
  !xor eax,edx
  !ror edi,25
  !xor edi,eax                 ;edi=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,edi                 ;s1
  !add eax,edx                 ;ch
  !add eax,[esi+ecx]           ;k[i]
  !mov edi,[v_pW]
  !add eax,[edi+ecx]           ;eax=t1, edi+ecx=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,ebx                 ;ebx=t2
  !mov [v_a],eax
 
  !add ecx,4
  !cmp ecx,256
  !jb @b
 
  ;am Ende jedes Chunks Hashs zu vorhandenen Werten aufaddieren
  !lea edi,[h0]
  !mov eax,[v_a]
  !add eax,[edi]
  !mov [edi],eax
  !mov eax,[v_b]
  !add eax,[edi+4]
  !mov [edi+4],eax
  !mov eax,[v_c]
  !add eax,[edi+8]
  !mov [edi+8],eax
  !mov eax,[v_d]
  !add eax,[edi+12]
  !mov [edi+12],eax
  !mov eax,[v_e]
  !add eax,[edi+16]
  !mov [edi+16],eax
  !mov eax,[v_f]
  !add eax,[edi+20]
  !mov [edi+20],eax
  !mov eax,[v_g]
  !add eax,[edi+24]
  !mov [edi+24],eax
  !mov eax,[v_h]
  !add eax,[edi+28]
  !mov [edi+28],eax
 
  !add [v_pAllBlocks],64       ;512 Bit (64 Byte) weiter, nächster Chunk
 
  !dec [v_Chunks]
  !jnz Next_Chunk
 
  !popad
 
  For i = 0 To 31 Step 4
    Hash$ + Hex(PeekL(?Hash + i) & $FFFFFFFF)
  Next
  ProcedureReturn Hash$
  End
 
;   Vergleichswerte:
;   "" = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
;   "abc" = BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD
;   "abcd" = 88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589
;   "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern"
;   = d32b568cd1b96d459e7291ebf4b25d007f275c9f13149beeb782fac0716613f8
;   "Frank jagt im komplett verwahrlosten Taxi quer durch Bayern"
;   = 78206a866dbb2bf017d8e34274aed01a8ce405b69d45db30bafa00f5eeed7d5e
 
  DataSection
  Hash:
  !h0:                              ;Fractional_Parts_Square_2_19, Big-Endian!
    Data.l $6a09e667, $bb67ae85, $3c6ef372, $a54ff53a, $510e527f, $9b05688c, $1f83d9ab, $5be0cd19
  !h1:                              ;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
EndProcedure


Debug sha256(@"Franz jagt im komplett verwahrlosten Taxi quer durch Bayern")
Debug sha256(@"Franz jagt im komplett verwahrlosten Taxi quer durch Bayern")
h0 kann dann natürlich anders angelegt werden; es war halt nur erstmal ein Test, ob die richtigen Hash-Werte rauskommen.
Gruß
Helle

Re: SHA256?

Verfasst: 13.06.2011 22:13
von SebastianJu2
Das hat geklappt... super... :) Den 64bit-Code kann ich auf meinem 32bit-System zwar jetzt nicht testen aber den könnte ich bei Bedarf auf einem anderen Rechner noch testen...

Re: SHA256?

Verfasst: 14.06.2011 17:45
von Helle
Hier eine leicht optimierte 64-Bit-Variante (besseres Speicher-Management, Nutzung von SSE2):

Code: Alles auswählen

;- SHA-256, Test für PB. Grundlage (Pseudo-Code) siehe engl. Wikipedia
;- "Helle" Klaus Helbing, 22.06.2011, PB 4.51 (x64)
;- 64-Bit-Windows-Version, hier für Dateien. SSE2-Version

Global Size.q
Global SizeAv.q
Global pSource.q
Global pAllBlocksA.q
Global Chunks.q
Global ChunksSum.q
Global ChunksAll.q
Global pWA.q
Global pHashA.q
Global p_a_h_A.q
Global MemAv.q
Global pBSWAPA.q

If OpenWindow(0, 0, 0, 600, 400, "Helles SHA-256, 64-Bit-Windows", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)

  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()
  TF1 = TA                             ;nur für Fortschritts-Balken
  TF2 = TA                             ;für Durchsatz

  ReadFile(0, File$)
  Size = Lof(0)
  SizeAv = Size
  ChunksAll = (Size / 64) + 1          ;nur für Fortschritts-Balken
  
  If Size > $40000 
    MemAv = $40000
    Chunks = $1000
    ChunksOld = Chunks
   Else
    MemAv = Size
    ChunksOld = ChunksAll
  EndIf

  SizeP$ = Str(Size)                   ;für Anzeige File-Länge < 1000 Bytes

  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, 10, 50, 100, 20, "Durchsatz (MB/s) : ")
  TextGadget(3, 110, 50, 100, 20, "")
  TextGadget(4, 25, 70, 550, 20, "Berechnungs-Fortschritt :", #PB_Text_Center)
  ProgressBarGadget(5, 25, 95, 550, 25, 0, 100, #PB_ProgressBar_Smooth)

  If Size <= MemAv
    MemAv = Size
  EndIf

  pBSWAP = AllocateMemory(16 + 16)     ;BSWAP-Ersatz mit SSE
  i = pBSWAP % 16
  pBSWAPA = pBSWAP - i + 16
!mov r9,[v_pBSWAPA]
!mov dword[r9],00010203h               ;mittels Shuffle werden für 16 Byte BSWAP emuliert 
!mov dword[r9+4],04050607h
!mov dword[r9+8],08090A0Bh
!mov dword[r9+12],0C0D0E0Fh

  pW = AllocateMemory(256 + 16)
  i = pW % 16
  pWA = pW - i + 16
 
  p_a_h = AllocateMemory(36 + 16)      ;für a-h, 36 wegen verschobenes Rückkopieren beim Vertauschen
  i = p_a_h % 16
  p_a_h_A = p_a_h - i + 16             ;jetzt 16-Byte-Alignment

  pHash = AllocateMemory(32 + 16)      ;damit Hash-Startwerte erhalten bleiben
  i = pHash % 16
  pHashA = pHash - i + 16

  CopyMemory(?HashBase, pHashA, 32)

  pAllBlocks = AllocateMemory(MemAv + 128 + 16)  ;(großzügig bemessener) Speicher für die 512-Bit-Blöcke
  i = pAllBlocks % 16
  pAllBlocksA = pAllBlocks - i + 16
  pAllBlocksOld = pAllBlocksA

!File_Weiter:

  BytesRead = ReadData(0, pAllBlocksA, 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_pAllBlocksA]
!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

!add rax,1                   ;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)
!add [v_Chunks],1            ;es wurde ja ein Block drangehängt

!End_Preprocessing:

!Next_Chunk:                 ;512 Bit (64 Byte)
;W[0] bis W[15]
!mov r9,[v_pBSWAPA]
!movdqa xmm1,[r9]
!mov r11,[v_pAllBlocksA]
!mov r10,[v_pWA]
!mov rcx,4
!@@:
!movdqa xmm0,[r11]
!pshufb xmm0, xmm1           ;BSWAP-"Ersatz"
!movdqa [r10],xmm0
!add r10,16
!add r11,16
!sub rcx,1
!jnz @b
;W[16] bis W[63]             ;es lassen sich nur 2 "benachbarte" DWords gleichzeitig bearbeiten. SSE brachte deshalb keinen Gewinn
!mov rcx,48
!mov r11,[v_pWA]
!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
!sub rcx,1
!jnz @b
;Initialisierung
!mov r9,[v_p_a_h_A]          ;wegen der PB-Einschübe hierhin (Neu-Initialisierung)
!mov r11,[v_pHashA]
!movdqa xmm0,[r11]
!movdqa xmm1,[r11+16]
!movdqa [r9],xmm0
!movdqa [r9+16],xmm1
!Align 8
;Main Loop
!xor rcx,rcx                 ;hier mal so
!lea r11,[k]                 ;siehe Data
!@@:
;s0
!mov eax,[r9]
!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)                 maj = (a and b) + (c and (a xor b)) NEU!
!mov eax,[r9]                ;a
!mov edx,eax
!mov r8d,[r9+4]              ;b
!xor eax,r8d                 ;(a xor b)
!and r8d,edx                 ;(a and b)
!and eax,[r9+8]              ;c
!add r8d,eax                 ;r8d=maj
;t2
!add r8d,r10d                ;r8d=t2, r10d=s0
;s1
!mov eax,[r9+16]
!mov edx,eax
!mov r10d,eax
!ror eax,6
!ror edx,11
!xor eax,edx
!ror r10d,25
!xor r10d,eax                ;r10d=s1
;ch                           ch = g xor (e and (f xor g)) NEU!
!mov eax,[r9+24]             ;g
!mov edx,eax
!xor edx,[r9+20]             ;f
!and edx,[r9+16]             ;e
!xor edx,eax
;t1
!mov eax,[r9+28]
!add eax,r10d                ;s1
!add eax,edx                 ;ch
!add eax,dword[r11+rcx]      ;k[i]
!mov r10d,dword[v_pWA]
!add eax,dword[r10+rcx]      ;eax=t1, r10+rcx=W[i]
;Vertauschungen              wegen dieser Vertauschungen habe ich bisher keine Idee betr. SSE in Main Loop gehabt 
!mov edx,[r9+12]             ;"altes" d
!add edx,eax                 ;eax=t1
!movdqa xmm0,[r9]
!movdqa xmm1,[r9+16]
!movdqu [r9+4],xmm0          ;mit Versatz von 4 Bytes zurückkopieren 
!movdqu [r9+20],xmm1
!add eax,r8d                 ;eax=t1, r8d=t2
!mov [r9],eax                ;"neues" a
!mov [r9+16],edx             ;"neues" e 

!add rcx,4
!cmp rcx,256
!jb @b

;am Ende jedes Chunks Hashs zu vorhandenen Werten aufaddieren (Überträge werden ignoriert!)
!mov r10,[v_pHashA]
!movdqa xmm0,[r10]
!paddd xmm0,[r9]
!movdqa [r10],xmm0
!movdqa xmm0,[r10+16]
!paddd xmm0,[r9+16]
!movdqa [r10+16],xmm0

!add [v_pAllBlocksA],64      ;512 Bit (64 Byte) weiter, nächster Chunk

!add [v_ChunksSum],1         ;nur für Fortschritts-Balken

  TF = ElapsedMilliseconds()
  If TF - TF1 > 100
    If TF - TF2 > 500
      SetGadgetText(3, StrF((ChunksSum - ChunksSum1) * 0.064 / (TF - TF2), 3))
      TF2 = TF
      ChunksSum1 = ChunksSum
    EndIf 
    TF1 = TF
    SetGadgetState(5, (ChunksSum * 100) / ChunksAll)
  EndIf

!sub [v_Chunks],1
!jnz Next_Chunk

!cmp [v_SizeAv],0
!je @f

  FileSeek(0, Seek)
  pAllBlocksA = pAllBlocksOld
  If SizeAv <= MemAv 
    MemAv = SizeAv
    FreeMemory(pAllBlocks)
    pAllBlocks = AllocateMemory(MemAv + 128 + 16)
    i = pAllBlocks % 16
    pAllBlocksA = pAllBlocks - i + 16
   Else
    Chunks = ChunksOld
  EndIf

!jmp File_Weiter
!@@:

  FreeGadget(4) : FreeGadget(5)

  For i = 0 To 28 Step 4
    Hash$ + RSet(Hex(PeekL(pHashA + i) & $FFFFFFFF), 8, "0")    ;bei Bedarf in Zwischenablage kopieren
  Next

  TE = ElapsedMilliseconds() - TA

  TextGadget(4, 10, 70, 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
  SetGadgetText(3, StrF(Size / ((TE + 1) * 1000), 3)) ;Durchsatz-Angabe war für Tests von längeren Files gedacht (Optimierung)  
  TextGadget(5, 10, 90, 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
SSE2 ist für die 64-Bit-Versionen von Vista/Win7 Grundvoraussetzung; so das es hier keine Probleme gibt. Der Performance-Gewinn entspricht zwar nicht meinen Erwartungen, aber immerhin wurde der Code kürzer :mrgreen: !
Viel Spaß!
Helle

Edit: 22.06.2011: Kosmetik und leichte Speed-Optimierung

Re: SHA256?

Verfasst: 14.06.2011 22:35
von SebastianJu2
Danke... :)

Re: SHA256?

Verfasst: 27.06.2011 10:03
von SebastianJu2
@Helle

Mir ist im 32bit Code (also der erste Code) ein Fehler aufgefallen und eine kleine Änderung wird nötig wenn man Binärdaten hashen will.

Die Funktion hat Hashs von 61-64 Zeichen Länge ausgegeben. Das kann man beheben indem man beim Ende den Code mit RSet erweitert:

Code: Alles auswählen

  For i = 0 To 31 Step 4
    Hash$ + RSet(Hex(PeekL(?Hash + i) & $FFFFFFFF),8,"0")
  Next
Dann wollte ich Binärdaten hashen was eine Änderung erforderlich macht weil sonst bei Chr(0) der Eingabestring als beendet angesehen wird.

Code: Alles auswählen

Procedure.s sha256(pSource, Length=0)

  Global.l SourceLength, pAllBlocks, Chunks, pW, a, b, c, d, e, f, g, h, i
  Define.s Hash$
  
  If Length <> 0
    SourceLength = Length                  ;Länge des Teststrings
  Else
    SourceLength = Len(PeekS(pSource))                  ;Länge des Teststrings
  EndIf
Ich bin mir zwar noch nicht sicher ob die Binärdaten damit auch korrekt gehasht werden aber immerhin ändert die Änderung einer übergebenen Längenangabe die auf einen Datenstring aus und Chr(1) und Chr(0) verweist den Hash. Zusätzliche Chr(0) verändern das Ergebnis. Sicher bin ich mir aber noch nicht ob das Ergebnis damit korrekt ist.

Re: SHA256?

Verfasst: 01.07.2011 16:29
von Helle
Wie schon geschrieben war die 32-Bit-Version ein Algo-Test (wo mich führende Nullen nicht die Bohne interessiert haben :mrgreen: ; siehe aber die 64-Bit-Version!). Zur allgemeinen Erbauung hier eine 32-Bit-Version für Files/Binärdaten:

Code: Alles auswählen

;- SHA-256, Grundlage (Pseudo-Code) siehe engl. Wikipedia
;- "Helle" Klaus Helbing, 01.07.2011, PB 4.51 (x86)
;- 32-Bit-Windows-Version mit Nutzung von SSE2

Global ChunksSum.d           ;für Fortschrittsbalken größere Dateien
Global ChunksAll.d
Global Seek.q
Global Size.q
Global SizeAv.q
Global Chunks.l
Global MemAv.l
Global p_a_h_A.l
Global pAllBlocksA.l
Global pHashA.l
Global pSource.l
Global pWA.l

Procedure Padding()
  ;Size wird auf Vielfaches von 512 Bit (64 Byte) gebracht (Blocklänge ist 512 Bit)
  !push edi  
  !push esi

  !mov edi,[v_pAllBlocksA]
  !mov eax,[v_MemAv]
  !mov esi,eax

  !mov ecx,64                ;512 Bit
  !xor edx,edx               ;hier mal so (ist ja unsigned)
  !div ecx                   ;Modulo steht in edx

  !inc eax                   ;eine Runde wollen wir ja wenigstens! 
  !mov [v_Chunks],eax
  !mov eax,[v_MemAv]
  !mov byte[edi+eax],80h     ;1 gesetztes Bit anhängen
  !or edx,edx                ;edx=0?
  ;1.Fall: EDX=0. Letzter 512-Bit-Block ist Vielfaches von 512 Bit (64 Byte). Es wird ein kompletter 512-Bit-Block angehängt   
  !jz @f 
  ;2.Fall: EDX<56. Letzter 512-Bit-Block ist kleiner als 448 Bit (56 Byte), aber größer Null
  !sub esi,edx
  !cmp edx,56                ;448 Bit
  !jb @f
  ;3.Fall: EDX>=56. 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
  !add edi,64
  !add [v_Chunks],1          ;es wurde ja ein Block drangehängt
!@@:  
  !add edi,esi

  !mov edx,8
  !mov eax,dword[v_Size]     ;Size ist Quad!
  !mul edx                   ;nicht SHL bei großen Dateien
  !mov ecx,eax
  !mov esi,edx

  !mov edx,8                 ;"Kaskadierung" für größere Dateien 
  !mov eax,dword[v_Size+4]   ;Size ist Quad!
  !mul edx         

  !add eax,esi               ;reicht so für heutige Festplatten/Filelängen

  !bswap ecx
  !bswap eax
  !mov [edi+56],eax          ;Original-Länge als 64-Bit-Big-Endian-Wert anhängen
  !mov [edi+60],ecx 
  
  !pop esi
  !pop edi

EndProcedure 

Procedure Main()
  !push ebx
  !push edi  
  !push esi
  ;W[0] bis W[15]
  !mov esi,[v_pAllBlocksA]
  !mov edi,[v_pWA]
  !mov ecx,8
!@@:
  !mov eax,[esi]
  !mov edx,[esi+4]
  !bswap eax
  !bswap edx
  !mov [edi],eax 
  !mov [edi+4],edx
  !add edi,8
  !add esi,8
  !dec ecx
  !jnz @b
  ;W[16] bis W[63]
  !mov ecx,48
  !mov esi,[v_pWA]
  !add esi,64
!@@:
  ;s0
  !mov eax,dword[esi-60]
  !mov edx,eax
  !mov edi,eax
  !ror eax,7
  !ror edx,18 
  !shr edi,3
  !xor eax,edx
  !xor edi,eax
  ;s1
  !mov eax,dword[esi-8]
  !mov edx,eax
  !mov ebx,eax
  !ror eax,17
  !ror edx,19
  !xor eax,edx
  !shr ebx,10
  !xor eax,ebx
  ;W[i]
  !mov edx,dword[esi-64]
  !add edx,edi               ;edi=s0
  !add edx,dword[esi-28]
  !add edx,eax               ;eax=s1
  !mov dword[esi],edx
  !add esi,4
  !dec ecx
  !jnz @b
  ;Initialisierung
  !mov esi,[v_p_a_h_A]       ;wegen der PB-Einschübe hierhin (Neu-Initialisierung)
  !mov eax,[v_pHashA]
  !movdqa xmm0,[eax]
  !movdqa xmm1,[eax+16]
  !movdqa [esi],xmm0
  !movdqa [esi+16],xmm1
  ;Main Loop
  !xor ecx,ecx               ;hier mal so
!@@:
  ;s0
  !mov eax,[esi]
  !mov edx,eax
  !mov edi,eax
  !ror eax,2
  !ror edx,13
  !xor eax,edx
  !ror edi,22
  !xor edi,eax               ;edi=s0
  ;maj (major)               maj = (a and b) + (c and (a xor b)) NEU!
  !mov eax,[esi]             ;a
  !mov edx,eax
  !mov ebx,[esi+4]            ;b
  !xor eax,ebx               ;(a xor b)
  !and ebx,edx               ;(a and b)
  !and eax,[esi+8]           ;c
  !add ebx,eax               ;ebx=maj
  ;t2
  !add ebx,edi               ;ebx=t2, edi=s0
  ;s1
  !mov eax,[esi+16]
  !mov edx,eax
  !mov edi,eax
  !ror eax,6
  !ror edx,11
  !xor eax,edx
  !ror edi,25
  !xor edi,eax               ;edi=s1
  ;ch                         ch = g xor (e and (f xor g)) NEU!
  !mov eax,[esi+24]          ;g
  !mov edx,eax
  !xor edx,[esi+20]          ;f
  !and edx,[esi+16]          ;e
  !xor edx,eax
  ;t1
  !mov eax,[esi+28]
  !add eax,edi               ;s1
  !add eax,edx               ;ch
  !lea edi,[k_224_256]       ;siehe Data
  !add eax,dword[edi+ecx]    ;k[i]
  !mov edi,dword[v_pWA]
  !add eax,dword[edi+ecx]    ;eax=t1, edi+ecx=W[i]
  ;Vertauschungen
  !mov edx,[esi+12]          ;"altes" d
  !add edx,eax               ;eax=t1
  !movdqa xmm0,[esi]
  !movdqa xmm1,[esi+16]
  !movdqu [esi+4],xmm0       ;mit Versatz von 4 Bytes zurückkopieren 
  !movdqu [esi+20],xmm1
  !add eax,ebx               ;eax=t1, ebx=t2
  !mov [esi],eax             ;"neues" a
  !mov [esi+16],edx          ;"neues" e 

  !add ecx,4
  !cmp ecx,256
  !jb @b
  ;am Ende jedes Chunks Hashs zu vorhandenen Werten aufaddieren (Überträge werden ignoriert!)
  !mov edi,[v_pHashA]
  !movdqa xmm0,[edi]
  !paddd xmm0,[esi]
  !movdqa [edi],xmm0
  !movdqa xmm0,[edi+16]
  !paddd xmm0,[esi+16]
  !movdqa [edi+16],xmm0

  !add [v_pAllBlocksA],64    ;512 Bit (64 Byte) weiter, nächster Chunk
   
  !pop esi
  !pop edi
  !pop ebx
EndProcedure   

If OpenWindow(0, 0, 0, 600, 400, "Helles SHA-256, 32-Bit-Windows", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)

  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()
  TF1 = TA                             ;nur für Fortschritts-Balken
  TF2 = TA                             ;für Durchsatz

  ReadFile(0, File$)
  Size = Lof(0)
  SizeAv = Size
  ChunksAll = (Size / 64) + 1          ;nur für Fortschritts-Balken
  
  If Size > $40000 
    MemAv = $40000
    Chunks = $1000
    ChunksOld = Chunks
   Else
    MemAv = Size
    ChunksOld = ChunksAll
  EndIf

  SizeP$ = Str(Size)                   ;für Anzeige File-Länge < 1000 Bytes

  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, 10, 50, 100, 20, "Durchsatz (MB/s) : ")
  TextGadget(3, 110, 50, 100, 20, "")
  TextGadget(4, 225, 70, 200, 20, "Berechnungs-Fortschritt :")
  ProgressBarGadget(5, 25, 95, 550, 25, 0, 100, #PB_ProgressBar_Smooth)
  TextGadget(6, 350, 70, 50, 20, "")  
  
  If Size <= MemAv
    MemAv = Size
  EndIf

  pW = AllocateMemory(256 + 16)
  i = pW % 16
  pWA = pW - i + 16
 
  p_a_h = AllocateMemory(36 + 16)      ;für a-h, 36 wegen verschobenes Rückkopieren beim Vertauschen
  i = p_a_h % 16
  p_a_h_A = p_a_h - i + 16             ;jetzt 16-Byte-Alignment

  pHash = AllocateMemory(32 + 16)      ;damit Hash-Startwerte erhalten bleiben
  i = pHash % 16
  pHashA = pHash - i + 16

  CopyMemory(?HashBase_256, pHashA, 32)

  pAllBlocks = AllocateMemory(MemAv + 128 + 16)  ;(großzügig bemessener) Speicher für die 512-Bit-Blöcke
  i = pAllBlocks % 16
  pAllBlocksA = pAllBlocks - i + 16
  pAllBlocksOld = pAllBlocksA
  
  If Size = 0                          ;damit auch Länge=0 berücksichtigt wird
    CloseFile(0)
    Padding()
    Main()
  EndIf  
    
  While SizeAv
    BytesRead = ReadData(0, pAllBlocksA, MemAv)  ;Datei in Speicher einlesen
    Seek + BytesRead
    FileSeek(0, Seek)        
    SizeAv - BytesRead

    If SizeAv = 0 
      CloseFile(0)
      Padding()  
    EndIf

    While Chunks                       ;512 Bit (64 Byte)
      Main()
      ChunksSum + 1                    ;nur für Fortschritts-Balken
      TF = ElapsedMilliseconds()
      If TF - TF1 > 100
        If TF - TF2 > 500
          SetGadgetText(3, StrF((ChunksSum - ChunksSum1) * 0.064 / (TF - TF2), 3))
          SetGadgetText(6, StrD((ChunksSum / ChunksAll) * 100, 1) + "%")
          TF2 = TF
          ChunksSum1 = ChunksSum
        EndIf 
        TF1 = TF
        SetGadgetState(5, (ChunksSum / ChunksAll) * 100)
      EndIf
      Chunks - 1
    Wend

    pAllBlocksA = pAllBlocksOld
    If SizeAv <= MemAv 
      MemAv = SizeAv
      FreeMemory(pAllBlocks)
      pAllBlocks = AllocateMemory(MemAv + 128 + 16)
      i = pAllBlocks % 16
      pAllBlocksA = pAllBlocks - i + 16
     Else
      Chunks = ChunksOld
    EndIf

  Wend 

  FreeGadget(4) : FreeGadget(5) : FreeGadget(6)

  For i = 0 To 28 Step 4
    Hash$ + RSet(Hex(PeekL(pHashA + i) & $FFFFFFFF), 8, "0")    ;bei Bedarf in Zwischenablage kopieren
  Next

  TE = ElapsedMilliseconds() - TA

  TextGadget(4, 10, 70, 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
  SetGadgetText(3, StrF(Size / ((TE + 1) * 1000), 3))
  TextGadget(5, 10, 90, 560, 20, "Benötigte Zeit : " +  TE$ + " ms")
 
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow

EndIf
End

DataSection
HashBase_256: ;The first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19, Big-Endian!
  Data.l $6a09e667, $bb67ae85, $3c6ef372, $a54ff53a, $510e527f, $9b05688c, $1f83d9ab, $5be0cd19
!k_224_256:                          ;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

Re: SHA256?

Verfasst: 01.07.2011 19:48
von SebastianJu2
War auch nicht als Kritik gemeint... ;) Ich werde mir die neue Version mal ansehen...