; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: OS independent hashes algorithm library.
;
;  Target OS: Any
;
;  Dependencies: memory.asm
;
;  Notes: Contains: MD5, ADLER32, FNV1b, CRC32
;
;_________________________________________________________________________________________

module "Hashes library"


; MD5 algorithm.
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

struct TContextMD5
    .__cntx rb 88
    .value  rb 16
ends


iglobal
  if used ___MD5InternalData
    ___MD5InternalData db     0,1,1,5,5,3,0,7, \
                              7,5,5,5,5,4,5,6, \
                              4,7,5,7,6,4,5,6
  end if
endg


uglobal
  if used ___MD5SineTable
    ___MD5SineTable  rd       65
  end if
endg



if used md5_Init
initialize ___md5_init
begin
        xor     eax, eax
        finit
        pushd   4F800000h
        pushd   0
        fstcw   word [esp+2]
        fstcw   word [esp]
        or      word [esp], 0F3Fh
        fldcw   word [esp]
        push    1
    @@: fild    dword [esp]
        fsin
        fabs
        fmul    dword [esp+8]
        fistp   qword [eax*4+___MD5SineTable]
        inc     dword [esp]
        inc     eax
        test    al, 40h
        jz      @b
        fldcw   word [esp+6]
        add     esp, 12
        return
endp
end if




;******************************************************
; Computes MD5 hash of the data block from [.pData] with
; length in [.pLen]
; Returns new string handle in eax containing the hash of
; the data.
;******************************************************
proc DataMD5, .pData, .pLen
begin
        push    ebx ecx esi edi

        stdcall md5_Init
        mov     ebx, eax

        stdcall md5_Update, ebx, [.pData], [.pLen]
        stdcall md5_GetValue, ebx

        stdcall StrNew
        mov     edi, eax
        lea     esi, [ebx+TContextMD5.value]
        mov     ecx, 16

.loop:
        movzx   eax, byte [esi]
        inc     esi
        stdcall NumToStr, eax, ntsUnsigned or ntsHex or ntsFixedWidth + 2
        push    eax
        stdcall StrCat, edi, eax
        stdcall StrDel ; from the stack
        loop    .loop

        stdcall StrLCase, edi
        stdcall FreeMem, ebx

        mov     eax, edi
        pop     edi esi ecx ebx
        return
endp






;............................................................................
; md5_Init is  used to allocate and initialize TContextMD5 structure for use with
; subsequent processing.
;
; Arguments:
;   no
;
; Return Value: EAX - pointer to the allocated TContextMD5 structure.
;
; Modifies Registers: EAX
;............................................................................
proc md5_Init
begin
        push    edi

        stdcall GetMem, sizeof.TContextMD5
        mov     edi, eax
        push    eax

        mov     al, 01h

    @@: stosb
        add     al, 22h
        jnc     @b

        mov     al, 0FEh
    @@: stosb
        sub     al, 22h
        jnc     @b

        xor     eax, eax
        stosd
        stosd

        pop     eax edi
        return
endp




;............................................................................
; md5_Update scans a  block of data and  updates the  working context.  Call it
; once on a single  block of data, or  call it multiple  times on consecutive
; blocks of data, before retrieving the MD5 signature with MD5_Digest
;
; Arguments:
;   lpMD5CTXT - address of an initialized MD5CTXT structure
;   lpBuf     - address of a contiguous block of data
;   bufLen    - the size, in bytes, of the block of data
;
; Return Value: None
;
; Modifies Registers: None
;............................................................................
proc md5_Update ;, .lpMD5CTXT, .lpBuf, .bufLen
begin
        pushad
        mov     esi, [esp+40]
        mov     ebp, [esp+36]
        lea     edi, [ebp+24]
        mov     edx, [esp+44]
        mov     ebx, edi
        mov     eax, edx
        shl     eax, 3
        mov     ecx, edx
        shr     ecx, 29
        push    dword [ebp+16]
        add     [ebp+16], eax
        adc     [ebp+20], ecx
        pop     eax
        shr     eax, 3
        and     eax, 3Fh
   .mn: xor     ecx, ecx
        mov     cl, 40h
        sub     ecx, eax
        cmp     ecx, edx
        jbe     @f
        mov     ecx, edx
    @@: sub     edx, ecx
        add     edi, eax
        add     eax, ecx
        rep     movsb
        mov     edi, ebx
        cmp     eax, 40h
        jb      @f

        stdcall ___md5_BTrnsf, ebp, edi

    @@: xor     eax, eax
        or      edx, edx
        jnz     .mn
        popad
        ret     12
endp




;............................................................................
; md5_GetValue is used to retrieve the MD5 hash for the working context. It may
; be called at any point during a buffer read to get the current MD5 hash for
; all data scanned up to that point.  It does not modify the contexutal data,
; so this procedure may be called as many times as needed.
; The value is stored in the context structure TContextMD5.value
;
; Arguments:
;   .pContextMD5 - address of an TContextMD5 structure
;
; Return Value: None
;
; Modifies Registers: None
;............................................................................
proc md5_GetValue   ;, .pContextMD5
begin
        pushad
        mov     esi, dword [esp+36]
        lea     edi, [esi+TContextMD5.value]
        lea     ebp, [esi+16]
        mov     ebx, edi
        sub     esp, 64
        movsd
        movsd
        movsd
        movsd
        lodsd
        shr     eax, 3
        add     esi, 4
        and     eax, 3Fh
        mov     edi, esp
        mov     ecx, eax
        rep     movsb
        inc     eax
        sub     ecx, eax
        mov     al, 80h
        stosb
        xor     eax, eax
        cmp     ecx, -56
        jae     @f
        xor     eax, eax
        add     ecx, 64
        rep     stosb
        mov     edi, esp

        stdcall ___md5_BTrnsf, ebx, edi

    @@: xor     eax, eax
        add     ecx, 56
        rep     stosb
        mov     esi, ebp
        movsd
        movsd

        stdcall ___md5_BTrnsf, ebx, esp

        add     esp, 64
        popad
        ret     4
endp




proc ___md5_BTrnsf   ;, .phash, .lpBlock
begin
        pushad
        mov     eax, dword [esp+36]
        xor     ecx, ecx
        mov     cl, 4
    @@: push    dword [eax]
        add     eax, 4
        loop    @b
   .mn: mov     ebp, ecx
        shr     ebp, 12
        add     dl, dh
        and     dl, 0Fh
        test    ch, 03h
        jnz     @f
        xor     cl, cl
        test    ch, 0Fh
        jnz     @f
        mov     esi, ___MD5InternalData
        mov     edx, dword [esi+ebp*2]
        mov     ebx, dword [esi+ebp*4+8]
    @@: add     cl, bl
        ror     ebx, 8
        push    edx
        push    ecx
        push    ebx
        mov     ebx, dword [esp+20]
        mov     ecx, dword [esp+16]
        mov     edx, dword [esp+12]
        test    ebp, 02h
        jnz     .hi
        test    ebp, 01h
        jnz     @f
        mov     eax, ebx
        and     ebx, ecx
        not     eax
        and     eax, edx
        or      eax, ebx
        jmp     .fghi
    @@: mov     eax, edx
        and     edx, ebx
        not     eax
        and     eax, ecx
        or      eax, edx
        jmp     .fghi
   .hi: test    ebp, 01h
        jnz     @f
        mov     eax, ebx
        xor     eax, ecx
        xor     eax, edx
        jmp     .fghi
    @@: mov     eax, edx
        not     eax
        or      eax, ebx
        xor     eax, ecx
 .fghi: pop     ebx
        pop     ecx
        pop     edx
        add     eax, dword [esp+12]
        mov     esi, dword [esp+56]
        movzx   edi, dl
        add     eax, dword [esi+edi*4]
        movzx   esi, ch
        add     eax, dword [___MD5SineTable+esi*4]
        rol     eax, cl
        add     eax, dword [esp+8]
        mov     dword [esp+12], eax
        mov     esi, esp
        mov     edi, esp
        lodsd
        movsd
        movsd
        movsd
        stosd
        inc     ch
        test    ch, 40h
        jz      .mn
        mov     eax, dword [esp+52]
        xor     ecx, ecx
        mov     cl, 4
        sub     eax, ecx
    @@: pop     edx
        add     dword [eax+ecx*4], edx
        loop    @b
        popad
        ret     8
endp



; ADLER32 algorithm.
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


iAdlerBase = 65521

if used DataAdler32

DataAdler32:        ;, .pBuffer, .length

        pop     eax     ; return address
        push    1       ; one more argument
        push    eax

end if

if used DataAdler32 | used adler32_Update

adler32_Update:          ;, .adler, .pBuffer, .length

virtual at esp+4+32
  .adler   dd ?
  .pBuffer dd ?
  .length  dd ?
end virtual

        pushad

        mov     ebx, [.adler]
        mov     eax, ebx

        and     ebx, $ffff      ; ebx = s1
        shr     eax, 16         ; eax = s2

        mov     esi, [.pBuffer]
        mov     edi, [.length]
        add     edi, esi

        mov     ecx, iAdlerBase

.loop:
        cmp     esi, edi
        jae     .mod           ; last mod

        test    eax, eax
        jns     .not_yet       ; there is still not overflow.

.mod:
        xor     edx, edx
        div     ecx
        mov     eax, ebx
        mov     ebx, edx        ; ebx is s2 now
        xor    edx, edx
        div     ecx             ; edx is s1 now

        cmp     esi, edi
        jae     .end_loop

        mov     eax, ebx    ; eax = s2
        mov     ebx, edx    ; ebx = s1

.not_yet:
        movzx   edx, byte [esi]
        add     ebx, edx
        add     eax, ebx
        inc     esi
        jmp     .loop

.end_loop:
        shl     ebx, 16
        or      ebx, edx
        mov     [esp+4*regEAX], ebx

        popad
        retn    3*4

end if



; FNV-1b algorithm
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


proc DataFNV1b, .ptrData, .len
begin
        push    ecx edx esi

        mov     esi, [.ptrData]
        mov     ecx, [.len]
        mov     eax, $811C9DC5                  ; 2166136261              ; FNV offset basis
        inc     ecx

.hashloop:
        dec     ecx
        jz      .exit
        movzx   edx, byte [esi]
        xor     eax, edx
        inc     esi
        imul    eax, $01000193    ;              ;   16777619              ; FNV prime
        jmp     .hashloop

.exit:
        pop     esi edx ecx
        return
endp


; CRC32B algorithm, as needed for PNG handling.
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


uglobal
  if used __CRC32Table
    __CRC32Table rd 256
  end if
endg


if used crc32_Update
initialize InitCRC32Table
begin
        mov     edi, __CRC32Table
        xor     ecx, ecx

.outer:
        movzx   eax, cl
        mov     ch, 8

.inner:
        shr     eax, 1
        jnc     @f
        xor     eax, $edb88320
@@:
        dec     ch
        jnz     .inner

        mov     [__CRC32Table+4*ecx], eax

        dec     cl
        jnz     .outer

        return
endp
end if



proc crc32_Update, .crc, .pBuffer, .length
begin
        push    esi edx

        mov     esi, [.pBuffer]
        add     [.length], esi
        mov     eax, [.crc]

.loop:
        cmp     esi, [.length]
        jae     .finish

        movzx   edx, byte [esi]
        inc     esi
        xor     dl, al
        shr     eax, 8
        mov     edx, [__CRC32Table+4*edx]
        xor     eax, edx
        jmp     .loop

.finish:
        pop     edx esi
        return
endp



proc DataCRC32, .pBuffer, .length
begin
        xor     eax, eax
        dec     eax
        stdcall crc32_Update, eax, [.pBuffer], [.length]
        not     eax
        return
endp




; Pearson hash function.





proc PearsonHash, .pData, .DataSize, .pFuncTable, .pResult, .ResultSize
begin
        pushad

        mov     ebx, [.pFuncTable]
        mov     esi, [.pData]
        mov     edi, [.pResult]
        mov     edx, [.ResultSize]

        xor     eax, eax

.outer_loop:
        dec     edx
        js      .finish

        mov     ecx, [.DataSize]
        jecxz   .byte_ok

        add     al, dl
        xor     al, [esi]
        mov     al, [ebx+eax]

.inner_loop:
        dec     ecx
        jz      .byte_ok

        xor     al, byte [esi+ecx]
        mov     al, [ebx+eax]
        jmp     .inner_loop

.byte_ok:
        mov     [edi+edx], al
        jmp     .outer_loop

.finish:
        popad
        return
endp



;
;
; Gets the array of strings and generates a table for PersonHash, that
; allows non-collision hash of the given set.
;
; Arguments:
;
;    .pStringArray - TArray of dword containing the strings of the set.
;
; Returns:
;
;    eax: pointer to a 256 byte table fill of values for using as a
;    .pFuncTable parameter in PearsonHash procedure.
;
;


proc GeneratePerfectPearsonFunction, .pStringArray
begin









        int3
        return
endp



if used test_func

test_func db 141, 227, 251,   2, 201, 179,  30,  63,  93, 145,  92,  46,   6,  95, 105,   1
          db  90, 112,  60,  84, 110, 205,   0, 253, 215, 118, 244, 218, 231,  31, 192,  67
          db 189,  23,  66, 144,  59, 115, 248, 237, 216,  82, 217,  72, 147, 143, 125, 170
          db 152, 154,  57,   4,  44, 131, 157, 111, 209, 185,  35,  81,  41, 182, 202, 176
          db 113, 193, 114, 254,  39, 194,  94, 190,  37,  42,  15, 195, 188, 169,  12,   7
          db 175,  88, 245, 127, 203, 135, 181, 178,  99, 164,  76, 235,  21,  86, 160, 243
          db 223, 126, 136, 129,  77, 239, 132, 174, 122, 233,  87, 108,  47, 146, 158, 128
          db  97, 162, 219,  91, 229, 222, 104,  71, 150,  55, 242,  75, 151, 206, 119,  36
          db  58, 236, 117,  43,  74, 155, 246, 116, 153, 148,  68, 159, 210, 161,  19,  64
          db 247, 186,  83,  29,   5, 249, 177, 196, 250, 197, 167, 230,  26, 134, 124, 240
          db  69, 149,  65,  62, 101,  38, 183,  45,  24, 166,  33, 123, 207, 107, 241, 191
          db 208,  85,  78, 184,  32,  89,  20, 165,  27,  22,  11, 130,  98,  80,  17, 198
          db 200, 211,  16, 100,  51, 232,   3,  96,  73, 187,  14,  53, 121, 199,  18, 103
          db 228, 180, 156, 252, 168,  49,   8, 171,  79, 204,  10, 139,  40,  61, 220, 212
          db  13, 221, 109,  25, 255, 120,  70,  28,  48, 213, 234,  50, 138,   9,  52, 142
          db 225, 172, 106,  54, 214, 163, 140,  34, 238, 224,  56, 226, 102, 137, 133, 173

end if







endmodule