Created
January 7, 2013 08:37
-
-
Save ynkdir/4473374 to your computer and use it in GitHub Desktop.
blake2.vim
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
呼ばれた気がしたので