Skip to content

Commit 184a157

Browse files
authored
Merge pull request #696 from tsuyoshicho/feature/hashupdate
Proposal: update and simply refine Hash(MD5,SHA1) module; using Data.List.Byte functions
2 parents 32f20a1 + 3574028 commit 184a157

File tree

4 files changed

+75
-96
lines changed

4 files changed

+75
-96
lines changed

autoload/vital/__vital__/Hash/MD5.vim

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
let s:save_cpo = &cpo
44
set cpo&vim
55

6+
function! s:_vital_created(module) abort
7+
let a:module.name = 'MD5'
8+
let a:module.hash_length = 128
9+
endfunction
10+
611
function! s:_vital_loaded(V) abort
712
let s:V = a:V
8-
let s:bitwise = s:V.import('Bitwise')
13+
let s:Bitwise = s:V.import('Bitwise')
14+
let s:ByteArray = s:V.import('Data.List.Byte')
915
endfunction
1016

1117
function! s:_vital_depends() abort
12-
return ['Bitwise']
18+
return ['Bitwise', 'Data.List.Byte']
1319
endfunction
1420

1521
let s:shift = [
@@ -39,16 +45,16 @@ let s:table = [
3945
\ ]
4046

4147
function! s:sum(data) abort
42-
let bytes = s:_str2bytes(a:data)
48+
let bytes = s:ByteArray.from_string(a:data)
4349
return s:sum_raw(bytes)
4450
endfunction
4551

4652
function! s:sum_raw(bytes) abort
47-
return s:_bytes2binstr(s:digest_raw(a:bytes))
53+
return s:ByteArray.to_hexstring(s:digest_raw(a:bytes))
4854
endfunction
4955

5056
function! s:digest(data) abort
51-
let bytes = s:_str2bytes(a:data)
57+
let bytes = s:ByteArray.from_string(a:data)
5258
return s:digest_raw(bytes)
5359
endfunction
5460

@@ -67,16 +73,16 @@ function! s:digest_raw(bytes) abort
6773

6874

6975
if has('num64')
70-
call extend(l:padded, s:_int2bytes(64, l:orig_len))
76+
call extend(l:padded, s:ByteArray.endian_convert(s:ByteArray.from_int(l:orig_len, 64)))
7177
else
72-
call extend(l:padded, s:_int2bytes(32, l:orig_len))
78+
call extend(l:padded, s:ByteArray.endian_convert(s:ByteArray.from_int(l:orig_len, 32)))
7379
call extend(l:padded, [0, 0, 0, 0])
7480
endif
7581

7682
for l:chunk_i in range(0, len(l:padded)-1, 64)
7783
let l:chunk = l:padded[l:chunk_i : l:chunk_i + 63]
7884

79-
let l:M = map(range(16), 's:_bytes2int32(l:chunk[(v:val*4):(v:val*4)+3])')
85+
let l:M = map(range(16), {i,v -> s:ByteArray.to_int(s:ByteArray.endian_convert(l:chunk[(i*4) : (i*4)+3]))})
8086
let l:A = l:a0
8187
let l:B = l:b0
8288
let l:C = l:c0
@@ -86,24 +92,24 @@ function! s:digest_raw(bytes) abort
8692
let l:F = 0
8793
let l:g = 0
8894
if 0 <= l:i && l:i <= 15
89-
let l:F = s:bitwise.or(s:bitwise.and(l:B, l:C), s:bitwise.and(s:bitwise.invert(l:B), l:D))
95+
let l:F = s:Bitwise.or(s:Bitwise.and(l:B, l:C), s:Bitwise.and(s:Bitwise.invert(l:B), l:D))
9096
let l:g = l:i
9197
elseif 16 <= l:i && l:i <= 31
92-
let l:F = s:bitwise.or(s:bitwise.and(l:B, l:D), s:bitwise.and(s:bitwise.invert(l:D), l:C))
98+
let l:F = s:Bitwise.or(s:Bitwise.and(l:B, l:D), s:Bitwise.and(s:Bitwise.invert(l:D), l:C))
9399
let l:g = fmod((5 * l:i) + 1, 16)
94100
elseif 32 <= l:i && l:i <= 47
95-
let l:F = s:bitwise.xor(l:B, s:bitwise.xor(l:C, l:D))
101+
let l:F = s:Bitwise.xor(l:B, s:Bitwise.xor(l:C, l:D))
96102
let l:g = fmod((3 * l:i) + 5, 16)
97103
elseif 48 <= l:i && l:i <= 63
98-
let l:F = s:bitwise.xor(l:C, s:bitwise.or(l:B, s:bitwise.invert(l:D)))
104+
let l:F = s:Bitwise.xor(l:C, s:Bitwise.or(l:B, s:Bitwise.invert(l:D)))
99105
let l:g = fmod(7 * l:i, 16)
100106
endif
101107

102108
let l:F = l:F + l:A + s:table[l:i] + M[float2nr(l:g)]
103109
let l:A = l:D
104110
let l:D = l:C
105111
let l:C = l:B
106-
let l:B = l:B + s:_leftrotate(l:F, s:shift[l:i])
112+
let l:B = l:B + s:Bitwise.rotate32l(l:F, s:shift[l:i])
107113

108114
endfor
109115
let l:a0 = l:a0 + l:A
@@ -113,38 +119,14 @@ function! s:digest_raw(bytes) abort
113119
endfor
114120

115121
let l:bytes = []
116-
call extend(l:bytes, s:_int2bytes(32, l:a0))
117-
call extend(l:bytes, s:_int2bytes(32, l:b0))
118-
call extend(l:bytes, s:_int2bytes(32, l:c0))
119-
call extend(l:bytes, s:_int2bytes(32, l:d0))
122+
call extend(l:bytes, s:ByteArray.endian_convert(s:ByteArray.from_int(l:a0, 32)))
123+
call extend(l:bytes, s:ByteArray.endian_convert(s:ByteArray.from_int(l:b0, 32)))
124+
call extend(l:bytes, s:ByteArray.endian_convert(s:ByteArray.from_int(l:c0, 32)))
125+
call extend(l:bytes, s:ByteArray.endian_convert(s:ByteArray.from_int(l:d0, 32)))
120126

121127
return l:bytes
122128
endfunction
123129

124-
function! s:_leftrotate(x, c) abort
125-
let l:x = s:bitwise.and(a:x, 0xFFFFFFFF)
126-
return s:bitwise.and(s:bitwise.or(s:bitwise.lshift(l:x, a:c), s:bitwise.rshift(l:x, (32-a:c))), 0xFFFFFFFF)
127-
endfunction
128-
129-
function! s:_bytes2binstr(bytes) abort
130-
return join(map(copy(a:bytes), 'printf(''%02x'', v:val)'), '')
131-
endfunction
132-
133-
function! s:_str2bytes(str) abort
134-
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
135-
endfunction
136-
137-
function! s:_int2bytes(bits, int) abort
138-
return map(range(a:bits / 8), 's:bitwise.and(s:bitwise.rshift(a:int, v:val * 8), 0xff)')
139-
endfunction
140-
141-
function! s:_bytes2int32(bytes) abort
142-
return s:bitwise.or(s:bitwise.lshift(a:bytes[3], 24),
143-
\ s:bitwise.or(s:bitwise.lshift(a:bytes[2], 16),
144-
\ s:bitwise.or(s:bitwise.lshift(a:bytes[1], 8),
145-
\ a:bytes[0])))
146-
endfunction
147-
148130
let &cpo = s:save_cpo
149131
unlet s:save_cpo
150132

autoload/vital/__vital__/Hash/SHA1.vim

Lines changed: 38 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,32 @@
88
let s:save_cpo = &cpo
99
set cpo&vim
1010

11+
function! s:_vital_created(module) abort
12+
let a:module.name = 'SHA1'
13+
let a:module.hash_length = s:sha1hashsize * 8 " 160
14+
endfunction
15+
1116
function! s:_vital_loaded(V) abort
1217
let s:V = a:V
13-
let s:bitwise = s:V.import('Bitwise')
18+
let s:Bitwise = s:V.import('Bitwise')
19+
let s:ByteArray = s:V.import('Data.List.Byte')
1420
endfunction
1521

1622
function! s:_vital_depends() abort
17-
return ['Bitwise']
23+
return ['Bitwise', 'Data.List.Byte']
1824
endfunction
1925

2026
function! s:sum(data) abort
21-
let bytes = s:_str2bytes(a:data)
27+
let bytes = s:ByteArray.from_string(a:data)
2228
return s:sum_raw(bytes)
2329
endfunction
2430

2531
function! s:sum_raw(bytes) abort
26-
return s:_bytes2binstr(s:digest_raw(a:bytes))
32+
return s:ByteArray.to_hexstring(s:digest_raw(a:bytes))
2733
endfunction
2834

2935
function! s:digest(data) abort
30-
let bytes = s:_str2bytes(a:data)
36+
let bytes = s:ByteArray.from_string(a:data)
3137
return s:digest_raw(bytes)
3238
endfunction
3339

@@ -77,7 +83,7 @@ let s:sha1context = {
7783
\}
7884

7985
function! s:_sha1circular_shift(bits, word) abort
80-
return s:bitwise.or(s:bitwise.lshift32(a:word, a:bits), s:bitwise.rshift32(a:word, 32 - a:bits))
86+
return s:Bitwise.rotate32l(a:word, a:bits)
8187
endfunction
8288

8389
function! s:sha1context.init() dict abort
@@ -112,10 +118,10 @@ function! s:sha1context.result(digest) dict abort
112118
endif
113119

114120
for i in range(s:sha1hashsize)
115-
let a:digest[i] = s:_uint8(
116-
\ s:bitwise.rshift32(
117-
\ self.intermediatehash[s:bitwise.rshift32(i, 2)],
118-
\ 8 * (3 - s:bitwise.and(i, 0x03))
121+
let a:digest[i] = s:Bitwise.uint8(
122+
\ s:Bitwise.rshift32(
123+
\ self.intermediatehash[s:Bitwise.rshift32(i, 2)],
124+
\ 8 * (3 - s:Bitwise.and(i, 0x03))
119125
\ )
120126
\ )
121127
endfor
@@ -144,7 +150,7 @@ function! s:sha1context.input(bytes) dict abort
144150
if self.Corrupted
145151
break
146152
endif
147-
call self.messageblock.push(s:_uint8(x))
153+
call self.messageblock.push(s:Bitwise.uint8(x))
148154

149155
if self.messageblock.index == s:sha1blocksize
150156
call self.process()
@@ -171,14 +177,14 @@ function! s:sha1context.process() dict abort
171177
" Initialize the first 16 words in the array W
172178
"
173179
for t in range(16)
174-
let W[t] = s:bitwise.lshift32(self.messageblock.data[t * 4], 24)
175-
let W[t] = s:bitwise.or(W[t], s:bitwise.lshift32(self.messageblock.data[t * 4 + 1], 16))
176-
let W[t] = s:bitwise.or(W[t], s:bitwise.lshift32(self.messageblock.data[t * 4 + 2], 8))
177-
let W[t] = s:bitwise.or(W[t], self.messageblock.data[t * 4 + 3])
180+
let W[t] = s:Bitwise.lshift32(self.messageblock.data[t * 4], 24)
181+
let W[t] = s:Bitwise.or(W[t], s:Bitwise.lshift32(self.messageblock.data[t * 4 + 1], 16))
182+
let W[t] = s:Bitwise.or(W[t], s:Bitwise.lshift32(self.messageblock.data[t * 4 + 2], 8))
183+
let W[t] = s:Bitwise.or(W[t], self.messageblock.data[t * 4 + 3])
178184
endfor
179185

180186
for t in range(16, 79)
181-
let W[t] = s:_sha1circular_shift(1, s:bitwise.xor(s:bitwise.xor(s:bitwise.xor(W[t-3], W[t-8]), W[t-14]), W[t-16]))
187+
let W[t] = s:_sha1circular_shift(1, s:Bitwise.xor(s:Bitwise.xor(s:Bitwise.xor(W[t-3], W[t-8]), W[t-14]), W[t-16]))
182188
endfor
183189

184190
let A = self.intermediatehash[0]
@@ -189,7 +195,7 @@ function! s:sha1context.process() dict abort
189195

190196
for t in range(20)
191197
let temp = s:_sha1circular_shift(5,A) +
192-
\ s:bitwise.or(s:bitwise.and(B, C), s:bitwise.and(s:bitwise.invert(B), D)) +
198+
\ s:Bitwise.or(s:Bitwise.and(B, C), s:Bitwise.and(s:Bitwise.invert(B), D)) +
193199
\ E + W[t] + K[0]
194200
let E = D
195201
let D = C
@@ -199,7 +205,7 @@ function! s:sha1context.process() dict abort
199205
endfor
200206

201207
for t in range(20, 39)
202-
let temp = s:_sha1circular_shift(5,A) + s:bitwise.xor(s:bitwise.xor(B, C), D) + E + W[t] + K[1]
208+
let temp = s:_sha1circular_shift(5,A) + s:Bitwise.xor(s:Bitwise.xor(B, C), D) + E + W[t] + K[1]
203209
let E = D
204210
let D = C
205211
let C = s:_sha1circular_shift(30,B)
@@ -209,7 +215,7 @@ function! s:sha1context.process() dict abort
209215

210216
for t in range(40, 59)
211217
let temp = s:_sha1circular_shift(5,A) +
212-
\ s:bitwise.or(s:bitwise.or(s:bitwise.and(B, C), s:bitwise.and(B, D)), s:bitwise.and(C, D)) +
218+
\ s:Bitwise.or(s:Bitwise.or(s:Bitwise.and(B, C), s:Bitwise.and(B, D)), s:Bitwise.and(C, D)) +
213219
\ E + W[t] + K[2]
214220
let E = D
215221
let D = C
@@ -220,7 +226,7 @@ function! s:sha1context.process() dict abort
220226

221227
for t in range(60, 79)
222228
let temp = s:_sha1circular_shift(5,A) +
223-
\ s:bitwise.xor(s:bitwise.xor(B, C), D) + E + W[t] + K[3]
229+
\ s:Bitwise.xor(s:Bitwise.xor(B, C), D) + E + W[t] + K[3]
224230
let E = D
225231
let D = C
226232
let C = s:_sha1circular_shift(30,B)
@@ -266,14 +272,14 @@ function! s:sha1context.padding() dict abort
266272
" Store the message length as the last 8 octets
267273
"
268274
" as data[-8]..data[-1]
269-
let self.messageblock.data[56] = s:_uint8(s:bitwise.rshift32(self.length.high, 24))
270-
let self.messageblock.data[57] = s:_uint8(s:bitwise.rshift32(self.length.high, 16))
271-
let self.messageblock.data[58] = s:_uint8(s:bitwise.rshift32(self.length.high, 8))
272-
let self.messageblock.data[59] = s:_uint8( self.length.high )
273-
let self.messageblock.data[60] = s:_uint8(s:bitwise.rshift32(self.length.low , 24))
274-
let self.messageblock.data[61] = s:_uint8(s:bitwise.rshift32(self.length.low , 16))
275-
let self.messageblock.data[62] = s:_uint8(s:bitwise.rshift32(self.length.low , 8))
276-
let self.messageblock.data[63] = s:_uint8( self.length.low )
275+
let self.messageblock.data[56] = s:Bitwise.uint8(s:Bitwise.rshift32(self.length.high, 24))
276+
let self.messageblock.data[57] = s:Bitwise.uint8(s:Bitwise.rshift32(self.length.high, 16))
277+
let self.messageblock.data[58] = s:Bitwise.uint8(s:Bitwise.rshift32(self.length.high, 8))
278+
let self.messageblock.data[59] = s:Bitwise.uint8( self.length.high )
279+
let self.messageblock.data[60] = s:Bitwise.uint8(s:Bitwise.rshift32(self.length.low , 24))
280+
let self.messageblock.data[61] = s:Bitwise.uint8(s:Bitwise.rshift32(self.length.low , 16))
281+
let self.messageblock.data[62] = s:Bitwise.uint8(s:Bitwise.rshift32(self.length.low , 8))
282+
let self.messageblock.data[63] = s:Bitwise.uint8( self.length.low )
277283

278284
call self.process()
279285
endfunction
@@ -305,38 +311,19 @@ function! s:sha1context.length.sizeset(data) dict abort
305311
" 3.b high shift = 0x0000000l >> (32 - 3)
306312
" endif
307313
" 32/64bit work use shift
308-
let self.high = s:_uint32(s:bitwise.rshift(len(a:data), 32 - 3))
309-
let self.low = s:_uint32(s:bitwise.lshift(len(a:data), 3))
314+
let self.high = s:Bitwise.uint32(s:Bitwise.rshift(len(a:data), 32 - 3))
315+
let self.low = s:Bitwise.uint32(s:Bitwise.lshift(len(a:data), 3))
310316

311317
" SHA1 2^64 - 1 overflow check
312-
" 0xh0000000 is not 0, then overflow it(byte data are Vim List;it can contain 2^64 - 1 item)
313-
if (has('num64') && (0 != s:_uint32(s:bitwise.rshift(len(a:data), 32 + (32 - 3)))))
318+
" 0xh0000000 is not 0, then overflow it(byte data are Vim List;it can contains 2^64 - 1 item)
319+
if (has('num64') && (0 != s:Bitwise.uint32(s:Bitwise.rshift(len(a:data), 32 + (32 - 3)))))
314320
let self.high = 0
315321
let self.low = 0
316322
return s:input_long
317323
endif
318324
return s:success
319325
endfunction
320326

321-
"---------------------------------------------------------------------
322-
" misc
323-
324-
function! s:_uint8(n) abort
325-
return s:bitwise.and(a:n, 0xFF)
326-
endfunction
327-
328-
function! s:_uint32(n) abort
329-
return s:bitwise.and(a:n, 0xFFFFFFFF)
330-
endfunction
331-
332-
function! s:_str2bytes(str) abort
333-
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
334-
endfunction
335-
336-
function! s:_bytes2binstr(bytes) abort
337-
return join(map(copy(a:bytes), 'printf(''%02x'', v:val)'), '')
338-
endfunction
339-
340327
let &cpo = s:save_cpo
341328
unlet s:save_cpo
342329

test/Hash/MD5.vim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ function! s:suite.after()
99
unlet! s:MD5
1010
endfunction
1111

12+
function! s:suite.prop() abort
13+
call s:assert.is_string(s:MD5.name)
14+
call s:assert.is_number(s:MD5.hash_length)
15+
endfunction
16+
1217
function! s:suite.encode() abort
1318
call s:assert.equal(s:MD5.sum(''), 'd41d8cd98f00b204e9800998ecf8427e')
1419
call s:assert.equal(s:MD5.sum('a'), '0cc175b9c0f1b6a831c399e269772661')

test/Hash/SHA1.vim

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ function! s:suite.after()
99
unlet! s:SHA1
1010
endfunction
1111

12+
function! s:suite.prop() abort
13+
call s:assert.is_string(s:SHA1.name)
14+
call s:assert.is_number(s:SHA1.hash_length)
15+
endfunction
16+
1217
function! s:suite.encode() abort
1318
call s:assert.equal(s:SHA1.sum(''), 'da39a3ee5e6b4b0d3255bfef95601890afd80709')
1419
call s:assert.equal(s:SHA1.sum('a'), '86f7e437faa5a7fce15d1ddcb9eaeaea377667b8')
@@ -36,10 +41,10 @@ function! s:suite.encode() abort
3641
\ ]
3742
" original result
3843
" let s:resultarray = [
39-
" \ 'a9993e364706816aba3e25717850c26c9cd0d89d",
40-
" \ '84983e441c3bd26ebaae4aa1f95129e5e54670f1",
41-
" \ '34aa973cd4c4daa4f61eeb2bdbad27316534016f",
42-
" \ 'dea356a2cddd90c7a7ecedc5ebb563934f460452"
44+
" \ 'a9993e364706816aba3e25717850c26c9cd0d89d',
45+
" \ '84983e441c3bd26ebaae4aa1f95129e5e54670f1',
46+
" \ '34aa973cd4c4daa4f61eeb2bdbad27316534016f',
47+
" \ 'dea356a2cddd90c7a7ecedc5ebb563934f460452'
4348
" \ ]
4449

4550
" other SHA1 test site generate result

0 commit comments

Comments
 (0)