Created
January 7, 2013 08:37
-
-
Save ynkdir/4473374 to your computer and use it in GitHub Desktop.
blake2.vim
This file contains 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
呼ばれた気がしたので