Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created January 7, 2013 08:37
Show Gist options
  • Save ynkdir/4473374 to your computer and use it in GitHub Desktop.
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
Author

ynkdir commented Jan 7, 2013

呼ばれた気がしたので

@ynkdir
Copy link
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