Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created January 7, 2013 08:37
Show Gist options
  • Select an option

  • Save ynkdir/4473374 to your computer and use it in GitHub Desktop.

Select an option

Save ynkdir/4473374 to your computer and use it in GitHub Desktop.
blake2.vim
" This is an implementation of Blake2b.
" XXX: not complete and not tested
function! Blake2(data)
let bytes = (type(a:data) == type("") ? s:strtobytes(a:data) : a:data)
return s:blake2(bytes)
endfunction
function! Blake2Test()
let s = ''
let h = Blake2(s)
if h ==? '786A02F742015903C6C6FD852552D272912F4740E15847618A86E217F71F5419D25E1031AFEE585313896444934EB04B903A685B1448B755D56F701AFE9BE2CE'
echo printf('"%s" => %s', s, h)
else
echoerr printf('"%s" => %s', s, h)
endif
let s = 'The quick brown fox jumps over the lazy dog'
let h = Blake2(s)
if h ==? 'A8ADD4BDDDFD93E4877D2746E62817B116364A1FA7BC148D95090BC7333B3673F82401CF7AA2E4CB1ECD90296E3F14CB5413F8ED77BE73045B13914CDCD6A918'
echo printf('"%s" => %s', s, h)
else
echoerr printf('"%s" => %s', s, h)
endif
endfunction
let s:IV = [
\ [0xf3bcc908, 0x6a09e667], [0x84caa73b, 0xbb67ae85],
\ [0xfe94f82b, 0x3c6ef372], [0x5f1d36f1, 0xa54ff53a],
\ [0xade682d1, 0x510e527f], [0x2b3e6c1f, 0x9b05688c],
\ [0xfb41bd6b, 0x1f83d9ab], [0x137e2179, 0x5be0cd19]
\ ]
let s:Sigma = [
\ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ] ,
\ [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] ,
\ [ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ] ,
\ [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ] ,
\ [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ] ,
\ [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ] ,
\ [ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ] ,
\ [ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ] ,
\ [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ] ,
\ [ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 ] ,
\ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ] ,
\ [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ]
\ ]
let s:State = {
\ "f": [[0,0],[0,0]],
\ "t": [[0,0],[0,0]],
\ "h": [[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],
\ }
let s:BLOCKBYTES = 128
let s:OUTBYTES = 64
function! s:blake2(bytes)
let S = deepcopy(s:State)
call s:init(S)
let bytes = copy(a:bytes)
while len(bytes) > s:BLOCKBYTES
let block = remove(bytes, 0, s:BLOCKBYTES - 1)
call s:increment_counter(S, [s:BLOCKBYTES, 0])
call s:compress(S, block)
endwhile
if len(bytes) != 0 || len(a:bytes) == 0
let block = bytes + repeat([0], s:BLOCKBYTES - len(a:bytes) % s:BLOCKBYTES)
call s:increment_counter(S, [len(bytes), 0])
call s:set_lastblock(S)
call s:compress(S, block)
endif
let hash = []
for i in range(8)
call extend(hash, s:uint64_to_bytes(S.h[i]))
endfor
return s:bytestohex(hash)
endfunction
function! s:init(S)
let digest_length = [s:OUTBYTES]
let key_length = [0]
let fanout = [1]
let depth = [1]
let leaf_length = [0, 0, 0, 0]
let node_offset = [0, 0, 0, 0, 0, 0, 0, 0]
let node_depth = [0]
let inner_length = [0]
let reserved = repeat([0], 14)
let salt = repeat([0], 48)
let personal = repeat([0], 64)
let config = digest_length + key_length + fanout + depth + leaf_length
\ + node_offset + node_depth + inner_length + reserved
\ + salt + personal
for i in range(8)
let a:S.h[i] = s:IV[i]
endfor
for i in range(8)
let a:S.h[i] = s:xor64(a:S.h[i], s:bytes_to_uint64(config[i * 8 : i * 8 + 7]))
endfor
endfunction
function! s:set_lastblock(S)
" TODO: lastnode?
"let a:S.f[1] = s:invert64([0, 0])
let a:S.f[0] = s:invert64([0, 0])
endfunction
function! s:increment_counter(S, inc)
let a:S.t[0] = s:add64(a:S.t[0], a:inc)
if s:cmp64(a:S.t[0], a:inc) < 0
let a:S.t[1] = s:add64(a:S.t[1], [1, 0])
endif
endfunction
function! s:G(a, b, c, d, m, r, i)
let [a, b, c, d, m, r, i] = [a:a, a:b, a:c, a:d, a:m, a:r, a:i]
let a = s:add64(s:add64(a, b), m[s:Sigma[r][2 * i]])
let d = s:rotateright(s:xor64(d, a), 32)
let c = s:add64(c, d)
let b = s:rotateright(s:xor64(b, c), 24)
let a = s:add64(s:add64(a, b), m[s:Sigma[r][2 * i + 1]])
let d = s:rotateright(s:xor64(d, a), 16)
let c = s:add64(c, d)
let b = s:rotateright(s:xor64(b, c), 63)
return [a, b, c, d]
endfunction
function! s:compress(S, block)
let v = repeat([[0,0]], 16)
let m = repeat([[0,0]], 16)
for i in range(16)
let m[i] = s:bytes_to_uint64(a:block[i * 8 : i * 8 + 7])
endfor
let v[0] = a:S.h[0]
let v[1] = a:S.h[1]
let v[2] = a:S.h[2]
let v[3] = a:S.h[3]
let v[4] = a:S.h[4]
let v[5] = a:S.h[5]
let v[6] = a:S.h[6]
let v[7] = a:S.h[7]
let v[8] = s:IV[0]
let v[9] = s:IV[1]
let v[10] = s:IV[2]
let v[11] = s:IV[3]
let v[12] = s:xor64(a:S.t[0], s:IV[4])
let v[13] = s:xor64(a:S.t[1], s:IV[5])
let v[14] = s:xor64(a:S.f[0], s:IV[6])
let v[15] = s:xor64(a:S.f[1], s:IV[7])
for r in range(12)
let [v[ 0], v[ 4], v[ 8], v[12]] = s:G(v[ 0], v[ 4], v[ 8], v[12], m, r, 0)
let [v[ 1], v[ 5], v[ 9], v[13]] = s:G(v[ 1], v[ 5], v[ 9], v[13], m, r, 1)
let [v[ 2], v[ 6], v[10], v[14]] = s:G(v[ 2], v[ 6], v[10], v[14], m, r, 2)
let [v[ 3], v[ 7], v[11], v[15]] = s:G(v[ 3], v[ 7], v[11], v[15], m, r, 3)
let [v[ 0], v[ 5], v[10], v[15]] = s:G(v[ 0], v[ 5], v[10], v[15], m, r, 4)
let [v[ 1], v[ 6], v[11], v[12]] = s:G(v[ 1], v[ 6], v[11], v[12], m, r, 5)
let [v[ 2], v[ 7], v[ 8], v[13]] = s:G(v[ 2], v[ 7], v[ 8], v[13], m, r, 6)
let [v[ 3], v[ 4], v[ 9], v[14]] = s:G(v[ 3], v[ 4], v[ 9], v[14], m, r, 7)
endfor
let a:S.h[0] = s:xor64(s:xor64(a:S.h[0], v[0]), v[8])
let a:S.h[1] = s:xor64(s:xor64(a:S.h[1], v[1]), v[9])
let a:S.h[2] = s:xor64(s:xor64(a:S.h[2], v[2]), v[10])
let a:S.h[3] = s:xor64(s:xor64(a:S.h[3], v[3]), v[11])
let a:S.h[4] = s:xor64(s:xor64(a:S.h[4], v[4]), v[12])
let a:S.h[5] = s:xor64(s:xor64(a:S.h[5], v[5]), v[13])
let a:S.h[6] = s:xor64(s:xor64(a:S.h[6], v[6]), v[14])
let a:S.h[7] = s:xor64(s:xor64(a:S.h[7], v[7]), v[15])
endfunction
function! s:cmp64(a, b)
let c = s:cmp32(a:a[1], a:b[1])
if c == 0
let c = s:cmp32(a:a[0], a:b[0])
endif
return c
endfunction
function! s:cmp32(a, b)
if (a:a >= 0 && a:b >= 0) || (a:a < 0 && a:b < 0)
return a:a < a:b ? -1 : a:a > a:b ? 1 : 0
else
return a:a < 0 ? 1 : -1
endif
endfunction
function! s:add64(a, b)
let lo = a:a[0] + a:b[0]
let c = (s:cmp32(lo, a:b[0]) < 0)
let hi = a:a[1] + a:b[1] + c
return [lo, hi]
endfunction
function! s:rotateleft(a, offset)
return s:or64(s:leftshift64(a:a, a:offset), s:rightshift64(a:a, 64 - a:offset))
endfunction
function! s:rotateright(a, offset)
return s:or64(s:rightshift64(a:a, a:offset), s:leftshift64(a:a, 64 - a:offset))
endfunction
function! s:invert64(x)
return [invert(a:x[0]), invert(a:x[1])]
endfunction
function! s:and64(x, y)
return [and(a:x[0], a:y[0]), and(a:x[1], a:y[1])]
endfunction
function! s:or64(x, y)
return [or(a:x[0], a:y[0]), or(a:x[1], a:y[1])]
endfunction
function! s:xor64(x, y)
return [xor(a:x[0], a:y[0]), xor(a:x[1], a:y[1])]
endfunction
let s:pow2 = [
\ 0x1, 0x2, 0x4, 0x8,
\ 0x10, 0x20, 0x40, 0x80,
\ 0x100, 0x200, 0x400, 0x800,
\ 0x1000, 0x2000, 0x4000, 0x8000,
\ 0x10000, 0x20000, 0x40000, 0x80000,
\ 0x100000, 0x200000, 0x400000, 0x800000,
\ 0x1000000, 0x2000000, 0x4000000, 0x8000000,
\ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
\ ]
function! s:leftshift(a, n)
return a:n == 0 ? a:a : a:n > 31 ? 0 : a:a * s:pow2[a:n]
endfunction
function! s:rightshift(a, n)
return a:n == 0 ? a:a : a:n > 31 ? 0 :
\ a:a < 0
\ ? (a:a - 0x80000000) / s:pow2[a:n] + 0x40000000 / s:pow2[a:n - 1]
\ : a:a / s:pow2[a:n]
endfunction
function! s:leftshift64(x, n)
let lo = s:leftshift(a:x[0], a:n)
if a:n < 32
let hi = or(s:leftshift(a:x[1], a:n), s:rightshift(a:x[0], 32 - a:n))
else
let hi = s:leftshift(a:x[0], a:n - 32)
endif
return [lo, hi]
endfunction
function! s:rightshift64(x, n)
let hi = s:rightshift(a:x[1], a:n)
if a:n < 32
let lo = or(s:rightshift(a:x[0], a:n), s:leftshift(a:x[1], 32 - a:n))
else
let lo = s:rightshift(a:x[1], a:n - 32)
endif
return [lo, hi]
endfunction
function! s:bytes_to_uint64(x)
let lo = a:x[3] * 0x1000000 + a:x[2] * 0x10000 + a:x[1] * 0x100 + a:x[0]
let hi = a:x[7] * 0x1000000 + a:x[6] * 0x10000 + a:x[5] * 0x100 + a:x[4]
return [lo, hi]
endfunction
function! s:uint64_to_bytes(x)
let x0 = and(a:x[0], 0xFF)
let x1 = and(s:rightshift(a:x[0], 8), 0xFF)
let x2 = and(s:rightshift(a:x[0], 16), 0xFF)
let x3 = and(s:rightshift(a:x[0], 24), 0xFF)
let x4 = and(a:x[1], 0xFF)
let x5 = and(s:rightshift(a:x[1], 8), 0xFF)
let x6 = and(s:rightshift(a:x[1], 16), 0xFF)
let x7 = and(s:rightshift(a:x[1], 24), 0xFF)
return [x0, x1, x2, x3, x4, x5, x6, x7]
endfunction
function! s:bytes(seq)
if type(a:seq)
return s:strtobytes(a:seq)
elseif type(a:seq) == type([])
return a:seq
else
throw 'type error'
endif
endfunction
function! s:hextobytes(hex)
return map(split(a:hex, '..\zs'), 'str2nr(v:val, 16)')
endfunction
function! s:bytestohex(bytes)
return join(map(copy(a:bytes), 'printf("%02x", v:val)'), '')
endfunction
function! s:strtobytes(str)
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
endfunction
@ynkdir
Copy link
Copy Markdown
Author

ynkdir commented Jan 7, 2013

呼ばれた気がしたので

@ynkdir
Copy link
Copy Markdown
Author

ynkdir commented Jan 7, 2013

saltとかtree hashingとかよくわからない

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment