BLAKE hash function include (x86) (5 Jun 2015)
Posted: Thu Jun 12, 2014 6:31 pm
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:
BLAKE.pbi
BLAKE_TestVect.pb
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:
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.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
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
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()