BLAKE hash function include (x86) (5 Jun 2015)

Share your advanced PureBasic knowledge/code with the community.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

BLAKE hash function include (x86) (5 Jun 2015)

Post by Inf0Byt3 »

Here's another crypto-related include, this time the BLAKE hash function. It was a SHA-3 finalist and can output hashes in 4 flavors: 224, 256, 384 and 512 bits (which might be great for generating encryption keys for example - of course with a suitable KDF scheme). Internally, it is based on Daniel Bernstein's ChaCha stream cipher which offers lots of speed. You can find more information about it here:

http://en.wikipedia.org/wiki/BLAKE_%28hash_function%29
https://131002.net/blake/

To test this implementation with the example below, you will need to download the test vectors found here : http://csrc.nist.gov/groups/ST/hash/sha ... nalRnd.zip. Unzip the file then go to the KAT_MCT folder and copy the following files in the same directory as the BLAKE_TestVect.pb file:
ShortMsgKAT_224.txt
ShortMsgKAT_256.txt
ShortMsgKAT_384.txt
ShortMsgKAT_512.txt
LongMsgKAT_224.txt
LongMsgKAT_256.txt
LongMsgKAT_384.txt
LongMsgKAT_512.txt
ExtremelyLongMsgKAT_224.txt
ExtremelyLongMsgKAT_256.txt
ExtremelyLongMsgKAT_384.txt
ExtremelyLongMsgKAT_512.txt
Enabling the extremely long message tests in BLAKE_TestVect.pb might make the test take several minutes more to complete. Another thing: before using this code, please confront it a bit to the original implementation found on the website. I tried my best not to make any mistakes, but these things happen.

BLAKE.pbi

Code: Select all

;/----------------------------------------------------------------------------------
;
; Include description : The BLAKE hash function
; Algo designers      : Jean-Philippe Aumasson, Luca Henzen
;                       Willi Meier, Raphael C.-W. Phan
; More info           : https://131002.net/blake/
; Impl. author        : Alexandru Trutia based on the original, public domain one
; Date                : 10 Jun 2014
; Version             : 1.0
; Target Compiler     : PureBasic 5.22+
; Target OS           : Windows x86 (not tested on any other operating systems)
; License             : Free, unrestricted, no warranty whatsoever
;                       Use at your own risk
; Additional info     : 1. BLAKE 224 and 256 use the same CTX (blake_state256) and
;                       BLAKE 384 and 512 use blake_state512. Make sure not to use
;                       the wrong structure or you'll get buffer underruns
;
;/----------------------------------------------------------------------------------

EnableExplicit

#BLAKE_224_DIGEST_SIZE = 28
#BLAKE_256_DIGEST_SIZE = 32
#BLAKE_384_DIGEST_SIZE = 48
#BLAKE_512_DIGEST_SIZE = 64

Structure asciiarray
  a.a[0]
EndStructure
Structure longarray
  l.l[0]
EndStructure
Structure quadarray
  q.q[0]
EndStructure
Structure blake_state256
  h.l[8]
  s.l[4]
  t.l[2]
  buflen.i
  nullt.i
  buf.a[64]
EndStructure
Structure blake_state512
  h.q[8]
  s.q[4]
  t.q[2]
  buflen.i
  nullt.i
  buf.a[128]
EndStructure

;-----------------------------------------------------------------------------------

Procedure.l _blake_ROTR32(val.l, count.l = 1)
  ;by mk-soft
  !mov eax, dword [p.v_val] 
  !mov ecx, dword [p.v_count]
  !ror eax, cl
  ProcedureReturn
EndProcedure

Procedure.l _blake_BSWAP32(val.l)
  ;by Rescator
  !mov eax,dword[p.v_val]
  !bswap eax
  ProcedureReturn
EndProcedure

Procedure.q _blake_ROTR64(val.q, n)
  ;based on rotl64 by wilbert
  !mov ecx, [p.v_n]
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rax, [p.v_val]
    !ror rax, cl
  CompilerElse
    !btr ecx, 5
    !jc rotr64_1
    !mov eax, [p.v_val]
    !mov edx, [p.v_val + 4]
    !jmp rotr64_2
    !rotr64_1:
    !mov edx, [p.v_val]
    !mov eax, [p.v_val + 4]
    !rotr64_2:
    !push ebx
    !mov ebx, eax
    !shrd eax, edx, cl
    !shrd edx, ebx, cl
    !pop ebx
  CompilerEndIf
  ProcedureReturn
EndProcedure

Procedure.q _blake_BSWAP64(val.q)
    ;by Rescator
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
        !mov rax,qword[p.v_val]
        !bswap rax
    CompilerElse
        !mov eax, [p.v_val + 4]
        !mov edx, [p.v_val]
        !bswap eax
        !bswap edx
    CompilerEndIf
    ProcedureReturn
EndProcedure

;-----------------------------------------------------------------------------------

Macro _blake_G32(ax, bx, cx, dx, ex)
  v(ax) + (m(*sigma\a[(i * 16) + ex]) ! *u256\l[*sigma\a[(i * 16) + (ex + 1)]]) + v(bx)
  v(dx) = _blake_ROTR32(v(dx) ! v(ax), 16)
  v(cx) + v(dx)
  v(bx) = _blake_ROTR32(v(bx) ! v(cx), 12)
  v(ax) + (m(*sigma\a[(i * 16) + (ex + 1)]) ! *u256\l[*sigma\a[(i * 16) + ex]]) + v(bx)
  v(dx) = _blake_ROTR32(v(dx) ! v(ax), 8)
  v(cx) + v(dx)
  v(bx) = _blake_ROTR32(v(bx) ! v(cx), 7)
EndMacro

Macro _blake_G64(ax, bx, cx, dx, ex)
  v(ax) + (m(*sigma\a[(i * 16) + ex]) ! *u512\q[*sigma\a[(i * 16) + (ex + 1)]]) + v(bx)
  v(dx) = _blake_ROTR64(v(dx) ! v(ax), 32)
  v(cx) + v(dx)
  v(bx) = _blake_ROTR64(v(bx) ! v(cx), 25)
  v(ax) + (m(*sigma\a[(i * 16) + (ex + 1)]) ! *u512\q[*sigma\a[(i * 16) + ex]]) + v(bx)
  v(dx) = _blake_ROTR64(v(dx) ! v(ax), 16)
  v(cx) + v(dx)
  v(bx) = _blake_ROTR64(v(bx) ! v(cx), 11)
EndMacro

;-----------------------------------------------------------------------------------

Procedure _blake_init32(*S.blake_state256, bits)
  Select bits
    Case 224
      *S\h[0]   = $c1059ed8
      *S\h[1]   = $367cd507
      *S\h[2]   = $3070dd17
      *S\h[3]   = $f70e5939
      *S\h[4]   = $ffc00b31
      *S\h[5]   = $68581511
      *S\h[6]   = $64f98fa7
      *S\h[7]   = $befa4fa4
    Case 256
      *S\h[0]   = $6a09e667
      *S\h[1]   = $bb67ae85
      *S\h[2]   = $3c6ef372
      *S\h[3]   = $a54ff53a
      *S\h[4]   = $510e527f
      *S\h[5]   = $9b05688c
      *S\h[6]   = $1f83d9ab
      *S\h[7]   = $5be0cd19
  EndSelect
  *S\t[0]   = 0 
  *S\t[1]   = 0
  *S\buflen = 0
  *S\nullt  = 0
  *S\s[0]   = 0
  *S\s[1]   = 0
  *S\s[2]   = 0
  *S\s[3]   = 0
EndProcedure

Procedure _blake_compress32(*S.blake_state256, *block.longarray)
  ;Vars
  Protected *sigma.asciiarray, *u256.longarray, i
  ;Arrays
  Dim v.l(15)
  Dim m.l(15)
  ;Init
  *sigma = ?blake_sigma
  *u256 = ?blake_u256
  ;Begin
  m(0)  = _blake_BSWAP32(*block\l[ 0])
  m(1)  = _blake_BSWAP32(*block\l[ 1])
  m(2)  = _blake_BSWAP32(*block\l[ 2])
  m(3)  = _blake_BSWAP32(*block\l[ 3])
  m(4)  = _blake_BSWAP32(*block\l[ 4])
  m(5)  = _blake_BSWAP32(*block\l[ 5])
  m(6)  = _blake_BSWAP32(*block\l[ 6])
  m(7)  = _blake_BSWAP32(*block\l[ 7])
  m(8)  = _blake_BSWAP32(*block\l[ 8])
  m(9)  = _blake_BSWAP32(*block\l[ 9])
  m(10) = _blake_BSWAP32(*block\l[10])
  m(11) = _blake_BSWAP32(*block\l[11])
  m(12) = _blake_BSWAP32(*block\l[12])
  m(13) = _blake_BSWAP32(*block\l[13])
  m(14) = _blake_BSWAP32(*block\l[14])
  m(15) = _blake_BSWAP32(*block\l[15])
  v(0)  = *S\h[0]
  v(1)  = *S\h[1]
  v(2)  = *S\h[2]
  v(3)  = *S\h[3]
  v(4)  = *S\h[4]
  v(5)  = *S\h[5]
  v(6)  = *S\h[6]
  v(7)  = *S\h[7]
  v(8)  = *S\s[0] ! *u256\l[0]
  v(9)  = *S\s[1] ! *u256\l[1]
  v(10) = *S\s[2] ! *u256\l[2]
  v(11) = *S\s[3] ! *u256\l[3]
  v(12) = *u256\l[4]
  v(13) = *u256\l[5]
  v(14) = *u256\l[6]
  v(15) = *u256\l[7]
  ;Don't xor t when the block is only padding
  If *S\nullt = 0
    v(12) ! *S\t[0]
    v(13) ! *S\t[0]
    v(14) ! *S\t[1]
    v(15) ! *S\t[1]
  EndIf
  i = 0
  While i < 14
    ;Column step
    _blake_G32(0, 4, 8,  12,  0)
    _blake_G32(1, 5, 9,  13,  2)
    _blake_G32(2, 6, 10, 14,  4)
    _blake_G32(3, 7, 11, 15,  6)
    ;Diagonal step
    _blake_G32(0, 5, 10, 15,  8)
    _blake_G32(1, 6, 11, 12, 10)
    _blake_G32(2, 7, 8,  13, 12)
    _blake_G32(3, 4, 9,  14, 14)
    i + 1
  Wend
  ;Store result
  *S\h[0] ! v( 0)
  *S\h[1] ! v( 1)
  *S\h[2] ! v( 2)
  *S\h[3] ! v( 3)
  *S\h[4] ! v( 4)
  *S\h[5] ! v( 5)
  *S\h[6] ! v( 6)
  *S\h[7] ! v( 7)
  *S\h[0] ! v( 8)
  *S\h[1] ! v( 9)
  *S\h[2] ! v(10)
  *S\h[3] ! v(11)
  *S\h[4] ! v(12)
  *S\h[5] ! v(13)
  *S\h[6] ! v(14)
  *S\h[7] ! v(15)
  *S\h[0] ! *S\s[0]
  *S\h[1] ! *S\s[1]
  *S\h[2] ! *S\s[2]
  *S\h[3] ! *S\s[3]
  *S\h[4] ! *S\s[0]
  *S\h[5] ! *S\s[1]
  *S\h[6] ! *S\s[2]
  *S\h[7] ! *S\s[3]
EndProcedure

Procedure _blake_update32(*S.blake_state256, *in, inlen)
  ;Vars
  Protected left, fill
  ;Init
  left = *S\buflen
  fill = 64 - left
  ;Data left and data received fill a block
  If left > 0 And inlen >= fill
    CopyMemory(*in, @*S\buf + left, fill)
    *S\t[0] + 512
    If *S\t[0] = 0
      *S\t[1] + 1
    EndIf
    _blake_compress32(*S, @*S\buf)
    *in + fill
    inlen - fill
    left = 0
  EndIf
  ;Compress blocks of data received
  While inlen >= 64
    *S\t[0] + 512
    If *S\t[0] = 0
      *S\t[1] + 1
    EndIf
    _blake_compress32(*S, *in)
    *in + 64
    inlen - 64
  Wend
  ;Store any data left
  If inlen > 0
    CopyMemory(*in, @*S\buf + left, inlen)
    *S\buflen = left + inlen
  Else 
    *S\buflen = 0
  EndIf
EndProcedure

Procedure _blake_final32(*S.blake_state256, *out.longarray, bits)
  ;Vars
  Protected zo.a, oo.a, lo.l, hi.l
  ;Arrays
  Dim msglen.l(1)
  Dim padding.a(128)
  ;Init
  padding(0) = $80
  Select bits
    Case 224
      zo = $00
      oo = $80
    Case 256
      zo = $01
      oo = $81
  EndSelect
  lo = *S\t[0] + (*S\buflen << 3)
  hi = *S\t[1]
  ;Support for hashing more than 2^32 bits
  If lo < (*S\buflen << 3)
    hi + 1
  EndIf
  msglen(0) = _blake_BSWAP32(hi)
  msglen(1) = _blake_BSWAP32(lo)
  If *S\buflen = 55 ;one padding byte
    *S\t[0] - 8
    _blake_update32(*S, @oo, 1)
  Else
    If (*S\buflen < 55 ) ;enough space to fill the block
      If *S\buflen = 0
        *S\nullt = 1
      EndIf
      *S\t[0] = *S\t[0] - (440 - (*S\buflen << 3))
      _blake_update32(*S, @padding(), 55 - *S\buflen)
    Else ;need 2 compressions
      *S\t[0] = *S\t[0] - (512 - (*S\buflen << 3))
      _blake_update32(*S, @padding(), 64 - *S\buflen)
      *S\t[0] - 440
      _blake_update32(*S, @padding() + 1, 55)
      *S\nullt = 1
    EndIf
    _blake_update32(*S, @zo, 1)
    *S\t[0] - 8
  EndIf
  *S\t[0] - 64
  _blake_update32(*S, @msglen(), 8)
  *out\l[0] = _blake_BSWAP32(*S\h[0])
  *out\l[1] = _blake_BSWAP32(*S\h[1])
  *out\l[2] = _blake_BSWAP32(*S\h[2])
  *out\l[3] = _blake_BSWAP32(*S\h[3])
  *out\l[4] = _blake_BSWAP32(*S\h[4])
  *out\l[5] = _blake_BSWAP32(*S\h[5])
  *out\l[6] = _blake_BSWAP32(*S\h[6])
  If bits = 256
    *out\l[7] = _blake_BSWAP32(*S\h[7])
  EndIf
EndProcedure

Procedure _blake_init64(*S.blake_state512, bits)
  Select bits
    Case 384
      *S\h[0]   = $cbbb9d5dc1059ed8
      *S\h[1]   = $629a292a367cd507
      *S\h[2]   = $9159015a3070dd17
      *S\h[3]   = $152fecd8f70e5939
      *S\h[4]   = $67332667ffc00b31
      *S\h[5]   = $8eb44a8768581511
      *S\h[6]   = $db0c2e0d64f98fa7
      *S\h[7]   = $47b5481dbefa4fa4
    Case 512
      *S\h[0]   = $6a09e667f3bcc908
      *S\h[1]   = $bb67ae8584caa73b
      *S\h[2]   = $3c6ef372fe94f82b
      *S\h[3]   = $a54ff53a5f1d36f1
      *S\h[4]   = $510e527fade682d1
      *S\h[5]   = $9b05688c2b3e6c1f
      *S\h[6]   = $1f83d9abfb41bd6b
      *S\h[7]   = $5be0cd19137e2179
  EndSelect
  *S\t[0]   = 0 
  *S\t[1]   = 0
  *S\buflen = 0
  *S\nullt  = 0
  *S\s[0]   = 0
  *S\s[1]   = 0
  *S\s[2]   = 0
  *S\s[3]   = 0
EndProcedure

Procedure _blake_compress64(*S.blake_state512, *block.quadarray)
  ;Vars
  Protected *sigma.asciiarray, *u512.quadarray, i
  ;Arrays
  Dim v.q(15)
  Dim m.q(15)
  ;Init
  *sigma = ?blake_sigma
  *u512 = ?blake_u512
  ;Begin
  m(0)  = _blake_BSWAP64(*block\q[ 0])
  m(1)  = _blake_BSWAP64(*block\q[ 1])
  m(2)  = _blake_BSWAP64(*block\q[ 2])
  m(3)  = _blake_BSWAP64(*block\q[ 3])
  m(4)  = _blake_BSWAP64(*block\q[ 4])
  m(5)  = _blake_BSWAP64(*block\q[ 5])
  m(6)  = _blake_BSWAP64(*block\q[ 6])
  m(7)  = _blake_BSWAP64(*block\q[ 7])
  m(8)  = _blake_BSWAP64(*block\q[ 8])
  m(9)  = _blake_BSWAP64(*block\q[ 9])
  m(10) = _blake_BSWAP64(*block\q[10])
  m(11) = _blake_BSWAP64(*block\q[11])
  m(12) = _blake_BSWAP64(*block\q[12])
  m(13) = _blake_BSWAP64(*block\q[13])
  m(14) = _blake_BSWAP64(*block\q[14])
  m(15) = _blake_BSWAP64(*block\q[15])
  v(0)  = *S\h[0]
  v(1)  = *S\h[1]
  v(2)  = *S\h[2]
  v(3)  = *S\h[3]
  v(4)  = *S\h[4]
  v(5)  = *S\h[5]
  v(6)  = *S\h[6]
  v(7)  = *S\h[7]
  v(8)  = *S\s[0] ! *u512\q[0]
  v(9)  = *S\s[1] ! *u512\q[1]
  v(10) = *S\s[2] ! *u512\q[2]
  v(11) = *S\s[3] ! *u512\q[3]
  v(12) = *u512\q[4]
  v(13) = *u512\q[5]
  v(14) = *u512\q[6]
  v(15) = *u512\q[7]
  ;Don't xor t when the block is only padding
  If *S\nullt = 0
    v(12) ! *S\t[0]
    v(13) ! *S\t[0]
    v(14) ! *S\t[1]
    v(15) ! *S\t[1]
  EndIf
  i = 0
  While i < 16
    ;Column step
    _blake_G64(0, 4, 8,  12,  0)
    _blake_G64(1, 5, 9,  13,  2)
    _blake_G64(2, 6, 10, 14,  4)
    _blake_G64(3, 7, 11, 15,  6)
    ;Diagonal step
    _blake_G64(0, 5, 10, 15,  8)
    _blake_G64(1, 6, 11, 12, 10)
    _blake_G64(2, 7, 8,  13, 12)
    _blake_G64(3, 4, 9,  14, 14)
    i + 1
  Wend
  ;Store result
  *S\h[0] ! v( 0)
  *S\h[1] ! v( 1)
  *S\h[2] ! v( 2)
  *S\h[3] ! v( 3)
  *S\h[4] ! v( 4)
  *S\h[5] ! v( 5)
  *S\h[6] ! v( 6)
  *S\h[7] ! v( 7)
  *S\h[0] ! v( 8)
  *S\h[1] ! v( 9)
  *S\h[2] ! v(10)
  *S\h[3] ! v(11)
  *S\h[4] ! v(12)
  *S\h[5] ! v(13)
  *S\h[6] ! v(14)
  *S\h[7] ! v(15)
  *S\h[0] ! *S\s[0]
  *S\h[1] ! *S\s[1]
  *S\h[2] ! *S\s[2]
  *S\h[3] ! *S\s[3]
  *S\h[4] ! *S\s[0]
  *S\h[5] ! *S\s[1]
  *S\h[6] ! *S\s[2]
  *S\h[7] ! *S\s[3]
EndProcedure

Procedure _blake_update64(*S.blake_state512, *in, inlen)
  ;Vars
  Protected left, fill
  ;Init
  left = *S\buflen
  fill = 128 - left
  ;Data left and data received fill a block
  If left > 0 And inlen >= fill
    CopyMemory(*in, @*S\buf + left, fill)
    *S\t[0] + 1024
    If *S\t[0] = 0
      *S\t[1] + 1
    EndIf
    _blake_compress64(*S, @*S\buf)
    *in + fill
    inlen - fill
    left = 0
  EndIf
  ;compress blocks of data received
  While inlen >= 128
    *S\t[0] + 1024
    If *S\t[0] = 0
      *S\t[1] + 1
    EndIf
    _blake_compress64(*S, *in)
    *in + 128
    inlen - 128
  Wend
  ;store any data left
  If inlen > 0
    CopyMemory(*in, @*S\buf + left, inlen)
    *S\buflen = left + inlen
  Else 
    *S\buflen = 0
  EndIf
EndProcedure

Procedure _blake_final64(*S.blake_state512, *out.quadarray, bits)
  ;Vars
  Protected zo.a, oo.a, lo.q, hi.q
  ;Arrays
  Dim msglen.q(1)
  Dim padding.a(128)
  ;Init
  padding(0) = $80
  Select bits
    Case 384
      zo = $00
      oo = $80
    Case 512
      zo = $01
      oo = $81
  EndSelect
  lo = *S\t[0] + (*S\buflen << 3)
  hi = *S\t[1]
  ;Support for hashing more than 2^32 bits
  If lo < (*S\buflen << 3)
    hi + 1
  EndIf
  msglen(0) = _blake_BSWAP64(hi)
  msglen(1) = _blake_BSWAP64(lo)
  If *S\buflen = 111 ;one padding byte
    *S\t[0] - 8
    _blake_update64(*S, @oo, 1)
  Else
    If (*S\buflen < 111 ) ;enough space to fill the block
      If *S\buflen = 0
        *S\nullt = 1
      EndIf
      *S\t[0] = *S\t[0] - (888 - (*S\buflen << 3))
      _blake_update64(*S, @padding(), 111 - *S\buflen)
    Else ;need 2 compressions
      *S\t[0] = *S\t[0] - (1024 - (*S\buflen << 3))
      _blake_update64(*S, @padding(), 128 - *S\buflen)
      *S\t[0] - 888
      _blake_update64(*S, @padding() + 1, 111)
      *S\nullt = 1
    EndIf
    _blake_update64(*S, @zo, 1)
    *S\t[0] - 8
  EndIf
  *S\t[0] - 128
  _blake_update64(*S, @msglen(), 16)
  *out\q[0] = _blake_BSWAP64(*S\h[0])
  *out\q[1] = _blake_BSWAP64(*S\h[1])
  *out\q[2] = _blake_BSWAP64(*S\h[2])
  *out\q[3] = _blake_BSWAP64(*S\h[3])
  *out\q[4] = _blake_BSWAP64(*S\h[4])
  *out\q[5] = _blake_BSWAP64(*S\h[5])
  If bits = 512
    *out\q[6] = _blake_BSWAP64(*S\h[6])
    *out\q[7] = _blake_BSWAP64(*S\h[7])
  EndIf
EndProcedure

;-----------------------------------------------------------------------------------

Procedure blake224_init(*S)
  ProcedureReturn _blake_init32(*S, 224)
EndProcedure

Procedure blake224_update(*S, *in, inlen)
  ProcedureReturn _blake_update32(*S, *in, inlen)
EndProcedure

Procedure blake224_final(*S, *out)
  ProcedureReturn _blake_final32(*S, *out, 224)
EndProcedure

Procedure blake256_init(*S)
  ProcedureReturn _blake_init32(*S, 256)
EndProcedure

Procedure blake256_update(*S, *in, inlen)
  ProcedureReturn _blake_update32(*S, *in, inlen)
EndProcedure

Procedure blake256_final(*S, *out)
  ProcedureReturn _blake_final32(*S, *out, 256)
EndProcedure

Procedure blake384_init(*S)
  ProcedureReturn _blake_init64(*S, 384)
EndProcedure

Procedure blake384_update(*S, *in, inlen)
  ProcedureReturn _blake_update64(*S, *in, inlen)
EndProcedure

Procedure blake384_final(*S, *out)
  ProcedureReturn _blake_final64(*S, *out, 384)
EndProcedure

Procedure blake512_init(*S)
  ProcedureReturn _blake_init64(*S, 512)
EndProcedure

Procedure blake512_update(*S, *in, inlen)
  ProcedureReturn _blake_update64(*S, *in, inlen)
EndProcedure

Procedure blake512_final(*S, *out)
  ProcedureReturn _blake_final64(*S, *out, 512)
EndProcedure

;-----------------------------------------------------------------------------------

DisableExplicit

DataSection
  blake_sigma:
  Data.a $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F
  Data.a $0E,$0A,$04,$08,$09,$0F,$0D,$06,$01,$0C,$00,$02,$0B,$07,$05,$03
  Data.a $0B,$08,$0C,$00,$05,$02,$0F,$0D,$0A,$0E,$03,$06,$07,$01,$09,$04
  Data.a $07,$09,$03,$01,$0D,$0C,$0B,$0E,$02,$06,$05,$0A,$04,$00,$0F,$08
  Data.a $09,$00,$05,$07,$02,$04,$0A,$0F,$0E,$01,$0B,$0C,$06,$08,$03,$0D
  Data.a $02,$0C,$06,$0A,$00,$0B,$08,$03,$04,$0D,$07,$05,$0F,$0E,$01,$09
  Data.a $0C,$05,$01,$0F,$0E,$0D,$04,$0A,$00,$07,$06,$03,$09,$02,$08,$0B
  Data.a $0D,$0B,$07,$0E,$0C,$01,$03,$09,$05,$00,$0F,$04,$08,$06,$02,$0A
  Data.a $06,$0F,$0E,$09,$0B,$03,$00,$08,$0C,$02,$0D,$07,$01,$04,$0A,$05
  Data.a $0A,$02,$08,$04,$07,$06,$01,$05,$0F,$0B,$09,$0E,$03,$0C,$0D,$00
  Data.a $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F
  Data.a $0E,$0A,$04,$08,$09,$0F,$0D,$06,$01,$0C,$00,$02,$0B,$07,$05,$03
  Data.a $0B,$08,$0C,$00,$05,$02,$0F,$0D,$0A,$0E,$03,$06,$07,$01,$09,$04
  Data.a $07,$09,$03,$01,$0D,$0C,$0B,$0E,$02,$06,$05,$0A,$04,$00,$0F,$08
  Data.a $09,$00,$05,$07,$02,$04,$0A,$0F,$0E,$01,$0B,$0C,$06,$08,$03,$0D
  Data.a $02,$0C,$06,$0A,$00,$0B,$08,$03,$04,$0D,$07,$05,$0F,$0E,$01,$09
  blake_u256:
  Data.l $243f6a88, $85a308d3, $13198a2e, $03707344
  Data.l $a4093822, $299f31d0, $082efa98, $ec4e6c89
  Data.l $452821e6, $38d01377, $be5466cf, $34e90c6c
  Data.l $c0ac29b7, $c97c50dd, $3f84d5b5, $b5470917
  blake_u512:
  Data.q $243f6a8885a308d3, $13198a2e03707344, $a4093822299f31d0, $082efa98ec4e6c89
  Data.q $452821e638d01377, $be5466cf34e90c6c, $c0ac29b7c97c50dd, $3f84d5b5b5470917
  Data.q $9216d5d98979fb1b, $d1310ba698dfb5ac, $2ffd72dbd01adfb7, $b8e1afed6a267e96
  Data.q $ba7c9045f12c7f99, $24a19947b3916cf7, $0801f2e2858efc16, $636920d871574e69
EndDataSection
BLAKE_TestVect.pb

Code: Select all

;Tests from: http://csrc.nist.gov/groups/ST/hash/sha-3/Round3/documents/Blake_FinalRnd.zip

XIncludeFile "BLAKE.pbi"

EnableExplicit
DisableDebugger ;Need for speed

Structure BlakeTestFile
  File.s
  Bits.i
EndStructure
Structure BlakeTest
  Type.i
  Len.i
  Msg.s
  Digest.s
  RepeatNum.i
EndStructure
Structure chararray
  c.c[0]
EndStructure

NewList TestF.BlakeTestFile()
NewList Tests.BlakeTest()

Define Line.s, Len, Msg.s, Digest.s, DigestSize, RepeatNum, Text.s, Total, Pass
Define *Ctx, *Out, *Expected, *Buff, Rep, TotalData.q

AddElement(TestF()) : TestF()\File = "ShortMsgKAT_224.txt" : TestF()\Bits = 224
AddElement(TestF()) : TestF()\File = "ShortMsgKAT_256.txt" : TestF()\Bits = 256
AddElement(TestF()) : TestF()\File = "ShortMsgKAT_384.txt" : TestF()\Bits = 384
AddElement(TestF()) : TestF()\File = "ShortMsgKAT_512.txt" : TestF()\Bits = 512
AddElement(TestF()) : TestF()\File = "LongMsgKAT_224.txt"  : TestF()\Bits = 224
AddElement(TestF()) : TestF()\File = "LongMsgKAT_256.txt"  : TestF()\Bits = 256
AddElement(TestF()) : TestF()\File = "LongMsgKAT_384.txt"  : TestF()\Bits = 384
AddElement(TestF()) : TestF()\File = "LongMsgKAT_512.txt"  : TestF()\Bits = 512

;[!] Don't uncomment these unless you want to grow a beard waiting for the results
;Adding these files into question will make the program process an extra 4 GB of data

AddElement(TestF()) : TestF()\File = "ExtremelyLongMsgKAT_224.txt" : TestF()\Bits = 224
AddElement(TestF()) : TestF()\File = "ExtremelyLongMsgKAT_256.txt" : TestF()\Bits = 256
AddElement(TestF()) : TestF()\File = "ExtremelyLongMsgKAT_384.txt" : TestF()\Bits = 384
AddElement(TestF()) : TestF()\File = "ExtremelyLongMsgKAT_512.txt" : TestF()\Bits = 512

Procedure.i pokehex(*buff.asciiarray, *hexstring.chararray, hexstringlen)
  Protected byte1.c, byte2.c, counter1, counter2
  Repeat
    byte1 = *hexstring\c[counter1] - 48
    byte2 = *hexstring\c[counter1 + 1] - 48
    If byte1 > 10 : byte1 - 7 : EndIf
    If byte2 > 10 : byte2 - 7 : EndIf
    *buff\a[counter2] = (byte1 * 16) + byte2
    counter1 + 2
    counter2 + 1
  Until counter1 = hexstringlen
  ProcedureReturn counter2
EndProcedure

OpenConsole()
PrintN("------------------------")
PrintN("BLAKE hash function for PureBasic vector tests")
PrintN("------------------------")

;Read the files
PrintN("Reading files...")
ForEach TestF()
  PrintN("Read: "+TestF()\File)
  If ReadFile(0, TestF()\File)
    While Not Eof(0)
      Line = ReadString(0)
      If Left(Line, 1) <> "#"
        If Line <> ""
          If Left(Line, 5) = "Len ="
            Len = Val(Trim(StringField(Line, 2, "=")))
          EndIf
          If Left(Line, 5) = "Msg ="
            Msg = Trim(StringField(Line, 2, "="))
          EndIf
          If Left(Line, 4) = "MD ="
            Digest = Trim(StringField(Line, 2, "="))
          EndIf
          If Left(Line, 8) = "Repeat ="
            RepeatNum = Val(Trim(StringField(Line, 2, "=")))
          EndIf
          If Left(Line, 6) = "Text ="
            Text = Trim(StringField(Line, 2, "="))
          EndIf
          If Msg <> "" And Digest <> "" And Text = ""
            ;The implementation from the test suit could be used to
            ;calculate hashes at bit-level. This implementation however
            ;works at byte-level so we will only test the vectors that
            ;have a bit-size that's multiple of 8.
            If Len % 8 = 0
              AddElement(Tests()) : Tests()\Type = TestF()\Bits : Tests()\Len = Len / 8 
              Tests()\Msg = Msg : Tests()\Digest = Digest: TotalData + Tests()\Len
            EndIf
            Len = -1 : Msg = "" : Digest = ""
          ElseIf Msg = "" And Digest <> "" And Text <> "" And RepeatNum > 0
            AddElement(Tests()) : Tests()\Type = TestF()\Bits : Tests()\Len = Len(Text)
            Tests()\Msg = Text : Tests()\Digest = Digest : Tests()\RepeatNum = RepeatNum
            TotalData + (Tests()\Len * RepeatNum) : Len = -1 : Msg = "" : Digest = "" : RepeatNum = -1
          EndIf
        EndIf
      EndIf
    Wend
  Else
    Debug "Error! Cannot read test file: "+TestF()\File
  EndIf
Next
PrintN("Starting tests:")
ForEach Tests() ;Run the tests
  Select Tests()\Type
    Case 224
      PrintN("Length "+Str(Tests()\Len)+", vector: "+Tests()\Digest)
      *Ctx = AllocateMemory(SizeOf(blake_state256))
      *Out = AllocateMemory(#BLAKE_224_DIGEST_SIZE)
      *Expected = AllocateMemory(#BLAKE_224_DIGEST_SIZE)
      *Buff = AllocateMemory(Tests()\Len + 2)
      pokehex(*Expected, @Tests()\Digest, Len(Tests()\Digest))
      blake224_init(*Ctx)
      If Tests()\RepeatNum > 0
        PrintN("Note! This is an extremely long message, please wait!")
        PokeS(*Buff, Tests()\Msg, Tests()\Len, #PB_Ascii)
        Rep = 0
        While Rep < Tests()\RepeatNum
          blake224_update(*Ctx, *Buff, Len(Tests()\Msg))
          Rep + 1
        Wend
      Else
        pokehex(*Buff, @Tests()\Msg, Len(Tests()\Msg))
        blake224_update(*Ctx, *Buff, Tests()\Len)
      EndIf
      blake224_final(*Ctx, *Out)
      If CompareMemory(*Out, *Expected, #BLAKE_224_DIGEST_SIZE) = 1 : Pass + 1 : Else : PrintN("Error!") : Break : EndIf
      FreeMemory(*Ctx) : FreeMemory(*Out) : FreeMemory(*Expected) : FreeMemory(*Buff)
    Case 256
      PrintN("Length "+Str(Tests()\Len)+", vector: "+Tests()\Digest)
      *Ctx = AllocateMemory(SizeOf(blake_state256))
      *Out = AllocateMemory(#BLAKE_256_DIGEST_SIZE)
      *Expected = AllocateMemory(#BLAKE_256_DIGEST_SIZE)
      *Buff = AllocateMemory(Tests()\Len + 2)
      pokehex(*Expected, @Tests()\Digest, Len(Tests()\Digest))
      blake256_init(*Ctx)
      If Tests()\RepeatNum > 0
        PrintN("Note! This is an extremely long message, please wait!")
        PokeS(*Buff, Tests()\Msg, Tests()\Len, #PB_Ascii)
        Rep = 0
        While Rep < Tests()\RepeatNum
          blake256_update(*Ctx, *Buff, Len(Tests()\Msg))
          Rep + 1
        Wend
      Else
        pokehex(*Buff, @Tests()\Msg, Len(Tests()\Msg))
        blake256_update(*Ctx, *Buff, Tests()\Len)
      EndIf
      blake256_final(*Ctx, *Out)
      If CompareMemory(*Out, *Expected, #BLAKE_256_DIGEST_SIZE) = 1 : Pass + 1 : Else 
      PrintN("Error!") : Break : EndIf
      FreeMemory(*Ctx) : FreeMemory(*Out) : FreeMemory(*Expected) : FreeMemory(*Buff)
    Case 384
      PrintN("Length "+Str(Tests()\Len)+", vector: "+Tests()\Digest)
      *Ctx = AllocateMemory(SizeOf(blake_state512))
      *Out = AllocateMemory(#BLAKE_384_DIGEST_SIZE)
      *Expected = AllocateMemory(#BLAKE_384_DIGEST_SIZE)
      *Buff = AllocateMemory(Tests()\Len + 2)
      pokehex(*Expected, @Tests()\Digest, Len(Tests()\Digest))
      blake384_init(*Ctx)
      If Tests()\RepeatNum > 0
        PrintN("Note! This is an extremely long message, please wait!")
        PokeS(*Buff, Tests()\Msg, Tests()\Len, #PB_Ascii)
        Rep = 0
        While Rep < Tests()\RepeatNum
          blake384_update(*Ctx, *Buff, Len(Tests()\Msg))
          Rep + 1
        Wend
      Else
        pokehex(*Buff, @Tests()\Msg, Len(Tests()\Msg))
        blake384_update(*Ctx, *Buff, Tests()\Len)
      EndIf
      blake384_final(*Ctx, *Out)
      If CompareMemory(*Out, *Expected, #BLAKE_384_DIGEST_SIZE) = 1 : Pass + 1 : Else : PrintN("Error!") : Break : EndIf
      FreeMemory(*Ctx) : FreeMemory(*Out) : FreeMemory(*Expected) : FreeMemory(*Buff)
    Case 512
      PrintN("Length "+Str(Tests()\Len)+", vector: "+Tests()\Digest)
      *Ctx = AllocateMemory(SizeOf(blake_state512))
      *Out = AllocateMemory(#BLAKE_512_DIGEST_SIZE)
      *Expected = AllocateMemory(#BLAKE_512_DIGEST_SIZE)
      *Buff = AllocateMemory(Tests()\Len + 2)
      pokehex(*Expected, @Tests()\Digest, Len(Tests()\Digest))
      blake512_init(*Ctx)
      If Tests()\RepeatNum > 0
        PrintN("Note! This is an extremely long message, please wait!")
        PokeS(*Buff, Tests()\Msg, Tests()\Len, #PB_Ascii)
        Rep = 0
        While Rep < Tests()\RepeatNum
          blake512_update(*Ctx, *Buff, Len(Tests()\Msg))
          Rep + 1
        Wend
      Else
        pokehex(*Buff, @Tests()\Msg, Len(Tests()\Msg))
        blake512_update(*Ctx, *Buff, Tests()\Len)
      EndIf
      blake512_final(*Ctx, *Out)
      If CompareMemory(*Out, *Expected, #BLAKE_512_DIGEST_SIZE) = 1 : Pass + 1 : Else : PrintN("Error!") : Break : EndIf
      FreeMemory(*Ctx) : FreeMemory(*Out) : FreeMemory(*Expected) : FreeMemory(*Buff)
  EndSelect
Next
If Pass = ListSize(Tests())
  PrintN("All tests passed! ("+Str(Pass)+")") : Beep_(1300,150):Delay(15):Beep_(1600,150):Delay(15):Beep_(1900,150):Delay(15)
Else
  PrintN("Not all tests passed, sorry.") : Beep_(1500,150):Delay(15):Beep_(1400,150):Delay(15):Beep_(1300,150):Delay(15)
EndIf
PrintN(Str(TotalData)+" bytes processed (~" + Str((TotalData / 1024 / 1024) + 1)+" MB)")
Input()
Last edited by Inf0Byt3 on Fri Jun 05, 2015 1:54 am, edited 2 times in total.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: BLAKE hash function include (x86) (12 Jun 2014)

Post by coco2 »

Nice! Thank you
marroh
User
User
Posts: 72
Joined: Wed Aug 06, 2008 8:21 am

Re: BLAKE hash function include (x86) (12 Jun 2014)

Post by marroh »

Thanks for share. :)
PureBASIC v5.41 LTS , Windows v8.1 x64
Forget UNICODE - Keep it BASIC !
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: BLAKE hash function include (x86) (12 Jun 2014)

Post by Keya »

Hello! Thankyou Inf0Byt3. Ive tried your code on Mac 64bit, but there is a bug but Im not quite sure where, can anyone find it?
It does all the 224 and 256 ones fine, but when it gets up to 384 it successfully does the first one where string length = 0, but then fails?
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Re: BLAKE hash function include (x86) (12 Jun 2014)

Post by Inf0Byt3 »

Hi. Found the problem. It seems that I forgot to write ProcedureReturn in _blake_BSWAP64() :P. Updated the code in the first post and it passes the test vectors now (tested on Debian 64bit with PB 5.31).
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Post Reply