; Implementation of SHA-256 hash algorithm.
; Written by diamond in 2007.

iglobal
align 4
sha256_start_digest:
        dd      0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A
        dd      0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
sha256_const:
        dd      0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5
        dd      0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5
        dd      0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3
        dd      0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174
        dd      0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC
        dd      0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA
        dd      0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7
        dd      0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967
        dd      0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13
        dd      0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85
        dd      0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3
        dd      0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070
        dd      0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5
        dd      0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3
        dd      0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208
        dd      0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
endg

uglobal
align 4
sha256_buf      rb      64
sha256_digest   rd      8
sha256_count    dd      ?
sha256_size     dq      ?
endg

sha256_init:
        mov     edi, sha256_digest
        mov     esi, sha256_start_digest
        push    8
        pop     ecx
        rep     movsd
        xor     eax, eax
        stosd           ; 0 bytes in buffer
        stosd
        stosd           ; 0 bytes processed
        ret

; Core of SHA-256: transform 64-byte 'sha256_buf' to updated 'sha256_digest'
sha256_transform:
        mov     esi, sha256_buf
        mov     edi, esi
rept 16
{
        lodsd
        bswap   eax
        stosd
}
        push    ebp
        mov     ebp, [esi+7*4]
        mov     edi, [esi+6*4]
        push    dword [esi+5*4]
        push    dword [esi+4*4]
        push    dword [esi+3*4]
        push    dword [esi+2*4]
        push    dword [esi+1*4]
        push    dword [esi+0*4]
        xor     ecx, ecx
.loop:
macro cmd1 cmd,a,b
{
if (b and 7) = 7
        cmd     a, ebp
else if (b and 7) = 6
        cmd     a, edi
else
        cmd     a, [esp+(b and 7)*4]
end if
}
macro cmd2 cmd,a,b
{
if (a and 7) = 7
        cmd     ebp, b
else if (a and 7) = 6
        cmd     edi, b
else
        cmd     [esp+(a and 7)*4], b
end if
}
rept 16 counter
{
cmd1    mov,    eax, (5-counter)
        ror     eax, 6
        mov     edx, eax
        ror     eax, 5
        xor     edx, eax
        ror     eax, 14
        xor     edx, eax
cmd1    mov,    eax, (6-counter)
cmd1    mov,    esi, (7-counter)
        xor     eax, esi
cmd1    and,    eax, (5-counter)
        xor     eax, esi
        add     edx, eax
        add     edx, [sha256_const+ecx+(counter-1)*4]
        add     edx, dword [sha256_buf+(counter-1)*4]
        test    ecx, ecx
        jz      @f
        mov     eax, dword [sha256_buf+((counter-3) and 15)*4]
        mov     esi, eax
        ror     eax, 17
        shr     esi, 10
        xor     esi, eax
        ror     eax, 2
        xor     esi, eax
        add     esi, dword [sha256_buf+((counter-8) and 15)*4]
        mov     eax, dword [sha256_buf+(counter and 15)*4]
        mov     ebx, eax
        ror     eax, 7
        shr     ebx, 3
        xor     ebx, eax
        ror     eax, 11
        xor     ebx, eax
        add     esi, ebx
        add     dword [sha256_buf+(counter-1)*4], esi
        add     edx, esi
@@:
cmd1    add,    edx, (8-counter)
cmd2    mov,    (8-counter), edx
cmd2    add,    (4-counter), edx
cmd1    mov,    ebx, (1-counter)
        mov     eax, ebx
cmd1    mov,    edx, (2-counter)
        mov     esi, ebx
        ror     eax, 2
        or      esi, edx
        and     ebx, edx
cmd1    and,    esi, (3-counter)
        mov     edx, eax
        or      esi, ebx
        ror     eax, 11
        xor     edx, eax
        ror     eax, 9
        xor     edx, eax
        add     esi, edx
cmd2    add,    (8-counter), esi
}
purge cmd1,cmd2
        add     cl, 64
        jnz     .loop
        mov     esi, sha256_digest
        pop     eax
        add     [esi+0*4], eax
        pop     eax
        add     [esi+1*4], eax
        pop     eax
        add     [esi+2*4], eax
        pop     eax
        add     [esi+3*4], eax
        pop     eax
        add     [esi+4*4], eax
        pop     eax
        add     [esi+5*4], eax
        add     [esi+6*4], edi
        add     [esi+7*4], ebp
        pop     ebp
        ret

sha256_update.transform:
        push    esi edx
        call    sha256_transform
        pop     edx esi
        mov     [sha256_count], ecx

sha256_update:
; in: esi->data, edx=size
        mov     eax, 64
        sub     eax, [sha256_count]
        sub     eax, edx
        sbb     ecx, ecx
        and     ecx, eax
        add     ecx, edx
        sub     edx, ecx
        mov     edi, sha256_buf
        add     edi, [sha256_count]
        add     [sha256_count], ecx
        add     dword [sha256_size], ecx
        adc     dword [sha256_size+4], 0
        rep     movsb
        cmp     edi, sha256_buf+64
        jz      .transform
.ret:
        ret

sha256_final:
; out: edi->digest
        push    edi
        mov     eax, [sha256_count]
        mov     [sha256_buf+eax], 0x80
        inc     eax
        cmp     al, 64-8
        jbe     @f
        lea     edi, [sha256_buf+eax]
        push    64
        pop     ecx
        sub     ecx, eax
        xor     eax, eax
        rep     stosb
        push    edx
        call    sha256_transform
        pop     edx
        xor     eax, eax
@@:
        push    64-8
        pop     ecx
        sub     ecx, eax
        lea     edi, [sha256_buf+eax]
        xor     eax, eax
        rep     stosb
        mov     eax, dword [sha256_size]
        mov     edx, dword [sha256_size+4]
        shld    edx, eax, 3
        shl     eax, 3
        bswap   edx
        bswap   eax
        xchg    eax, edx
        stosd
        xchg    eax, edx
        stosd
        call    sha256_transform
        mov     esi, sha256_digest
        mov     cl, 8
        pop     edi
@@:
        lodsd
        bswap   eax
        stosd
        loop    @b
        ret
