· 6 years ago · Mar 23, 2020, 09:16 PM
1--[=[------------------------------------------------------------------------------------------------------------------------
2-- HashLib by Egor Skriptunoff, boatbomber, and howmanysmall
3
4Documentation here: https://devforum.roblox.com/t/open-source-hashlib/416732/1
5
6--------------------------------------------------------------------------------------------------------------------------
7
8Module was originally written by Egor Skriptunoff and distributed under an MIT license.
9It can be found here: https://github.com/Egor-Skriptunoff/pure_lua_SHA/blob/master/sha2.lua
10
11That version was around 3000 lines long, and supported Lua versions 5.1, 5.2, 5.3, and 5.4, and LuaJIT.
12Although that is super cool, Roblox only uses Lua 5.1, so that was extreme overkill.
13
14I, boatbomber, worked to port it to Roblox in a way that doesn't overcomplicate it with support of unreachable
15cases. Then, howmanysmall did some final optimizations that really squeeze out all the performance possible.
16It's gotten stupid fast, thanks to her!
17
18After quite a bit of work and benchmarking, this is what we were left with.
19Enjoy!
20
21--------------------------------------------------------------------------------------------------------------------------
22
23DESCRIPTION:
24 This module contains functions to calculate SHA digest:
25 MD5, SHA-1,
26 SHA-224, SHA-256, SHA-512/224, SHA-512/256, SHA-384, SHA-512,
27 SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256,
28 HMAC
29 Additionally, it has a few extra utility functions:
30 hex_to_bin
31 base64_to_bin
32 bin_to_base64
33 Written in pure Lua.
34USAGE:
35 Input data should be a string
36 Result (SHA digest) is returned in hexadecimal representation as a string of lowercase hex digits.
37 Simplest usage example:
38 local HashLib = require(script.HashLib)
39 local your_hash = HashLib.sha256("your string")
40API:
41 HashLib.md5
42 HashLib.sha1
43 SHA2 hash functions:
44 HashLib.sha224
45 HashLib.sha256
46 HashLib.sha512_224
47 HashLib.sha512_256
48 HashLib.sha384
49 HashLib.sha512
50 SHA3 hash functions:
51 HashLib.sha3_224
52 HashLib.sha3_256
53 HashLib.sha3_384
54 HashLib.sha3_512
55 HashLib.shake128
56 HashLib.shake256
57 Misc utilities:
58 HashLib.hmac (Applicable to any hash function from this module except SHAKE*)
59 HashLib.hex_to_bin
60 HashLib.base64_to_bin
61 HashLib.bin_to_base64
62
63--]=]---------------------------------------------------------------------------
64local base64Lib = "local l={}local h={}for a=65,90 do table.insert(l,a)end for a=97,122 do table.insert(l,a)end for a=48,57 do table.insert(l,a)end table.insert(l,43)table.insert(l,47)for b,a in ipairs(l)do h[a]=b end local a={}local i=bit32.rshift local j=bit32.lshift local k=bit32.band function a.Encode(b)local g={}local h=0 for a=1,#b,3 do local a,f,e=string.byte(b,a,a+2)local c=i(a,2)local a=j(k(a,3),4)+i(f or 0,4)local d=j(k(f or 0,15),2)+i(e or 0,6)local b=k(e or 0,63)h=h+1 g[h]=l[c+1]h=h+1 g[h]=l[a+1]h=h+1 g[h]=f and l[d+1]or 61 h=h+1 g[h]=e and l[b+1]or 61 end local b={}local c=0 local d for a=1,h,4096 do c=c+1 d=a+4096-1 b[c]=string.char(table.unpack(g,a,d>h and h or d))end return table.concat(b)end function a.Decode(a)local g={}local l=0 for b=1,#a,4 do local b,a,d,e=string.byte(a,b,b+3)local b=h[b]-1 local c=h[a]-1 local f=(h[d]or 1)-1 local a=(h[e]or 1)-1 local b=j(b,2)+i(c,4)local c=j(k(c,15),4)+i(f,2)local a=j(k(f,3),6)+a l=l+1 g[l]=b if d~=61 then l=l+1 g[l]=c end if e~=61 then l=l+1 g[l]=a end end local a={}local c=0 local d for b=1,l,4096 do c=c+1 d=b+4096-1 a[c]=string.char(table.unpack(g,b,d>l and l or d))end return table.concat(a)end return a"
65local Base64 = loadstring(base64Lib)()
66
67--------------------------------------------------------------------------------
68-- LOCALIZATION FOR VM OPTIMIZATIONS
69--------------------------------------------------------------------------------
70
71local ipairs = ipairs
72
73--------------------------------------------------------------------------------
74-- 32-BIT BITWISE FUNCTIONS
75--------------------------------------------------------------------------------
76-- Only low 32 bits of function arguments matter, high bits are ignored
77-- The result of all functions (except HEX) is an integer inside "correct range":
78-- for "bit" library: (-TWO_POW_31)..(TWO_POW_31-1)
79-- for "bit32" library: 0..(TWO_POW_32-1)
80local bit32_band = bit32.band -- 2 arguments
81local bit32_bor = bit32.bor -- 2 arguments
82local bit32_bxor = bit32.bxor -- 2..5 arguments
83local bit32_lshift = bit32.lshift -- second argument is integer 0..31
84local bit32_rshift = bit32.rshift -- second argument is integer 0..31
85local bit32_lrotate = bit32.lrotate -- second argument is integer 0..31
86local bit32_rrotate = bit32.rrotate -- second argument is integer 0..31
87
88--------------------------------------------------------------------------------
89-- CREATING OPTIMIZED INNER LOOP
90--------------------------------------------------------------------------------
91-- Arrays of SHA2 "magic numbers" (in "INT64" and "FFI" branches "*_lo" arrays contain 64-bit values)
92local sha2_K_lo, sha2_K_hi, sha2_H_lo, sha2_H_hi, sha3_RC_lo, sha3_RC_hi = {}, {}, {}, {}, {}, {}
93local sha2_H_ext256 = {
94 [224] = {};
95 [256] = sha2_H_hi;
96}
97
98local sha2_H_ext512_lo, sha2_H_ext512_hi = {
99 [384] = {};
100 [512] = sha2_H_lo;
101}, {
102 [384] = {};
103 [512] = sha2_H_hi;
104}
105
106local md5_K, md5_sha1_H = {}, {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}
107local md5_next_shift = {0, 0, 0, 0, 0, 0, 0, 0, 28, 25, 26, 27, 0, 0, 10, 9, 11, 12, 0, 15, 16, 17, 18, 0, 20, 22, 23, 21}
108local HEX64, XOR64A5, lanes_index_base -- defined only for branches that internally use 64-bit integers: "INT64" and "FFI"
109local common_W = {} -- temporary table shared between all calculations (to avoid creating new temporary table every time)
110local K_lo_modulo, hi_factor, hi_factor_keccak = 4294967296, 0, 0
111
112local TWO_POW_NEG_56 = 2 ^ -56
113local TWO_POW_NEG_17 = 2 ^ -17
114
115local TWO_POW_2 = 2 ^ 2
116local TWO_POW_3 = 2 ^ 3
117local TWO_POW_4 = 2 ^ 4
118local TWO_POW_5 = 2 ^ 5
119local TWO_POW_6 = 2 ^ 6
120local TWO_POW_7 = 2 ^ 7
121local TWO_POW_8 = 2 ^ 8
122local TWO_POW_9 = 2 ^ 9
123local TWO_POW_10 = 2 ^ 10
124local TWO_POW_11 = 2 ^ 11
125local TWO_POW_12 = 2 ^ 12
126local TWO_POW_13 = 2 ^ 13
127local TWO_POW_14 = 2 ^ 14
128local TWO_POW_15 = 2 ^ 15
129local TWO_POW_16 = 2 ^ 16
130local TWO_POW_17 = 2 ^ 17
131local TWO_POW_18 = 2 ^ 18
132local TWO_POW_19 = 2 ^ 19
133local TWO_POW_20 = 2 ^ 20
134local TWO_POW_21 = 2 ^ 21
135local TWO_POW_22 = 2 ^ 22
136local TWO_POW_23 = 2 ^ 23
137local TWO_POW_24 = 2 ^ 24
138local TWO_POW_25 = 2 ^ 25
139local TWO_POW_26 = 2 ^ 26
140local TWO_POW_27 = 2 ^ 27
141local TWO_POW_28 = 2 ^ 28
142local TWO_POW_29 = 2 ^ 29
143local TWO_POW_30 = 2 ^ 30
144local TWO_POW_31 = 2 ^ 31
145local TWO_POW_32 = 2 ^ 32
146local TWO_POW_40 = 2 ^ 40
147
148local TWO56_POW_7 = 256 ^ 7
149
150-- Implementation for Lua 5.1/5.2 (with or without bitwise library available)
151local function sha256_feed_64(H, str, offs, size)
152 -- offs >= 0, size >= 0, size is multiple of 64
153 local W, K = common_W, sha2_K_hi
154 local h1, h2, h3, h4, h5, h6, h7, h8 = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
155 for pos = offs, offs + size - 1, 64 do
156 for j = 1, 16 do
157 pos = pos + 4
158 local a, b, c, d = string.byte(str, pos - 3, pos)
159 W[j] = ((a * 256 + b) * 256 + c) * 256 + d
160 end
161
162 for j = 17, 64 do
163 local a, b = W[j - 15], W[j - 2]
164 W[j] = bit32_bxor(bit32_rrotate(a, 7), bit32_lrotate(a, 14), bit32_rshift(a, 3)) + bit32_bxor(bit32_lrotate(b, 15), bit32_lrotate(b, 13), bit32_rshift(b, 10)) + W[j - 7] + W[j - 16]
165 end
166
167 local a, b, c, d, e, f, g, h = h1, h2, h3, h4, h5, h6, h7, h8
168 for j = 1, 64 do
169 local z = bit32_bxor(bit32_rrotate(e, 6), bit32_rrotate(e, 11), bit32_lrotate(e, 7)) + bit32_band(e, f) + bit32_band(-1 - e, g) + h + K[j] + W[j]
170 h = g
171 g = f
172 f = e
173 e = z + d
174 d = c
175 c = b
176 b = a
177 a = z + bit32_band(d, c) + bit32_band(a, bit32_bxor(d, c)) + bit32_bxor(bit32_rrotate(a, 2), bit32_rrotate(a, 13), bit32_lrotate(a, 10))
178 end
179
180 h1, h2, h3, h4 = (a + h1) % 4294967296, (b + h2) % 4294967296, (c + h3) % 4294967296, (d + h4) % 4294967296
181 h5, h6, h7, h8 = (e + h5) % 4294967296, (f + h6) % 4294967296, (g + h7) % 4294967296, (h + h8) % 4294967296
182 end
183
184 H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8
185end
186
187local function sha512_feed_128(H_lo, H_hi, str, offs, size)
188 -- offs >= 0, size >= 0, size is multiple of 128
189 -- W1_hi, W1_lo, W2_hi, W2_lo, ... Wk_hi = W[2*k-1], Wk_lo = W[2*k]
190 local W, K_lo, K_hi = common_W, sha2_K_lo, sha2_K_hi
191 local h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo = H_lo[1], H_lo[2], H_lo[3], H_lo[4], H_lo[5], H_lo[6], H_lo[7], H_lo[8]
192 local h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi = H_hi[1], H_hi[2], H_hi[3], H_hi[4], H_hi[5], H_hi[6], H_hi[7], H_hi[8]
193 for pos = offs, offs + size - 1, 128 do
194 for j = 1, 16 * 2 do
195 pos = pos + 4
196 local a, b, c, d = string.byte(str, pos - 3, pos)
197 W[j] = ((a * 256 + b) * 256 + c) * 256 + d
198 end
199
200 for jj = 34, 160, 2 do
201 local a_lo, a_hi, b_lo, b_hi = W[jj - 30], W[jj - 31], W[jj - 4], W[jj - 5]
202 local tmp1 = bit32_bxor(bit32_rshift(a_lo, 1) + bit32_lshift(a_hi, 31), bit32_rshift(a_lo, 8) + bit32_lshift(a_hi, 24), bit32_rshift(a_lo, 7) + bit32_lshift(a_hi, 25)) % 4294967296 +
203 bit32_bxor(bit32_rshift(b_lo, 19) + bit32_lshift(b_hi, 13), bit32_lshift(b_lo, 3) + bit32_rshift(b_hi, 29), bit32_rshift(b_lo, 6) + bit32_lshift(b_hi, 26)) % 4294967296 +
204 W[jj - 14] + W[jj - 32]
205
206 local tmp2 = tmp1 % 4294967296
207 W[jj - 1] = bit32_bxor(bit32_rshift(a_hi, 1) + bit32_lshift(a_lo, 31), bit32_rshift(a_hi, 8) + bit32_lshift(a_lo, 24), bit32_rshift(a_hi, 7)) +
208 bit32_bxor(bit32_rshift(b_hi, 19) + bit32_lshift(b_lo, 13), bit32_lshift(b_hi, 3) + bit32_rshift(b_lo, 29), bit32_rshift(b_hi, 6)) +
209 W[jj - 15] + W[jj - 33] + (tmp1 - tmp2) / 4294967296
210
211 W[jj] = tmp2
212 end
213
214 local a_lo, b_lo, c_lo, d_lo, e_lo, f_lo, g_lo, h_lo = h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo
215 local a_hi, b_hi, c_hi, d_hi, e_hi, f_hi, g_hi, h_hi = h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi
216 for j = 1, 80 do
217 local jj = 2 * j
218 local tmp1 = bit32_bxor(bit32_rshift(e_lo, 14) + bit32_lshift(e_hi, 18), bit32_rshift(e_lo, 18) + bit32_lshift(e_hi, 14), bit32_lshift(e_lo, 23) + bit32_rshift(e_hi, 9)) % 4294967296 +
219 (bit32_band(e_lo, f_lo) + bit32_band(-1 - e_lo, g_lo)) % 4294967296 +
220 h_lo + K_lo[j] + W[jj]
221
222 local z_lo = tmp1 % 4294967296
223 local z_hi = bit32_bxor(bit32_rshift(e_hi, 14) + bit32_lshift(e_lo, 18), bit32_rshift(e_hi, 18) + bit32_lshift(e_lo, 14), bit32_lshift(e_hi, 23) + bit32_rshift(e_lo, 9)) +
224 bit32_band(e_hi, f_hi) + bit32_band(-1 - e_hi, g_hi) +
225 h_hi + K_hi[j] + W[jj - 1] +
226 (tmp1 - z_lo) / 4294967296
227
228 h_lo = g_lo
229 h_hi = g_hi
230 g_lo = f_lo
231 g_hi = f_hi
232 f_lo = e_lo
233 f_hi = e_hi
234 tmp1 = z_lo + d_lo
235 e_lo = tmp1 % 4294967296
236 e_hi = z_hi + d_hi + (tmp1 - e_lo) / 4294967296
237 d_lo = c_lo
238 d_hi = c_hi
239 c_lo = b_lo
240 c_hi = b_hi
241 b_lo = a_lo
242 b_hi = a_hi
243 tmp1 = z_lo + (bit32_band(d_lo, c_lo) + bit32_band(b_lo, bit32_bxor(d_lo, c_lo))) % 4294967296 + bit32_bxor(bit32_rshift(b_lo, 28) + bit32_lshift(b_hi, 4), bit32_lshift(b_lo, 30) + bit32_rshift(b_hi, 2), bit32_lshift(b_lo, 25) + bit32_rshift(b_hi, 7)) % 4294967296
244 a_lo = tmp1 % 4294967296
245 a_hi = z_hi + (bit32_band(d_hi, c_hi) + bit32_band(b_hi, bit32_bxor(d_hi, c_hi))) + bit32_bxor(bit32_rshift(b_hi, 28) + bit32_lshift(b_lo, 4), bit32_lshift(b_hi, 30) + bit32_rshift(b_lo, 2), bit32_lshift(b_hi, 25) + bit32_rshift(b_lo, 7)) + (tmp1 - a_lo) / 4294967296
246 end
247
248 a_lo = h1_lo + a_lo
249 h1_lo = a_lo % 4294967296
250 h1_hi = (h1_hi + a_hi + (a_lo - h1_lo) / 4294967296) % 4294967296
251 a_lo = h2_lo + b_lo
252 h2_lo = a_lo % 4294967296
253 h2_hi = (h2_hi + b_hi + (a_lo - h2_lo) / 4294967296) % 4294967296
254 a_lo = h3_lo + c_lo
255 h3_lo = a_lo % 4294967296
256 h3_hi = (h3_hi + c_hi + (a_lo - h3_lo) / 4294967296) % 4294967296
257 a_lo = h4_lo + d_lo
258 h4_lo = a_lo % 4294967296
259 h4_hi = (h4_hi + d_hi + (a_lo - h4_lo) / 4294967296) % 4294967296
260 a_lo = h5_lo + e_lo
261 h5_lo = a_lo % 4294967296
262 h5_hi = (h5_hi + e_hi + (a_lo - h5_lo) / 4294967296) % 4294967296
263 a_lo = h6_lo + f_lo
264 h6_lo = a_lo % 4294967296
265 h6_hi = (h6_hi + f_hi + (a_lo - h6_lo) / 4294967296) % 4294967296
266 a_lo = h7_lo + g_lo
267 h7_lo = a_lo % 4294967296
268 h7_hi = (h7_hi + g_hi + (a_lo - h7_lo) / 4294967296) % 4294967296
269 a_lo = h8_lo + h_lo
270 h8_lo = a_lo % 4294967296
271 h8_hi = (h8_hi + h_hi + (a_lo - h8_lo) / 4294967296) % 4294967296
272 end
273
274 H_lo[1], H_lo[2], H_lo[3], H_lo[4], H_lo[5], H_lo[6], H_lo[7], H_lo[8] = h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo
275 H_hi[1], H_hi[2], H_hi[3], H_hi[4], H_hi[5], H_hi[6], H_hi[7], H_hi[8] = h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi
276end
277
278local function md5_feed_64(H, str, offs, size)
279 -- offs >= 0, size >= 0, size is multiple of 64
280 local W, K, md5_next_shift = common_W, md5_K, md5_next_shift
281 local h1, h2, h3, h4 = H[1], H[2], H[3], H[4]
282 for pos = offs, offs + size - 1, 64 do
283 for j = 1, 16 do
284 pos = pos + 4
285 local a, b, c, d = string.byte(str, pos - 3, pos)
286 W[j] = ((d * 256 + c) * 256 + b) * 256 + a
287 end
288
289 local a, b, c, d = h1, h2, h3, h4
290 local s = 25
291 for j = 1, 16 do
292 local F = bit32_rrotate(bit32_band(b, c) + bit32_band(-1 - b, d) + a + K[j] + W[j], s) + b
293 s = md5_next_shift[s]
294 a = d
295 d = c
296 c = b
297 b = F
298 end
299
300 s = 27
301 for j = 17, 32 do
302 local F = bit32_rrotate(bit32_band(d, b) + bit32_band(-1 - d, c) + a + K[j] + W[(5 * j - 4) % 16 + 1], s) + b
303 s = md5_next_shift[s]
304 a = d
305 d = c
306 c = b
307 b = F
308 end
309
310 s = 28
311 for j = 33, 48 do
312 local F = bit32_rrotate(bit32_bxor(bit32_bxor(b, c), d) + a + K[j] + W[(3 * j + 2) % 16 + 1], s) + b
313 s = md5_next_shift[s]
314 a = d
315 d = c
316 c = b
317 b = F
318 end
319
320 s = 26
321 for j = 49, 64 do
322 local F = bit32_rrotate(bit32_bxor(c, bit32_bor(b, -1 - d)) + a + K[j] + W[(j * 7 - 7) % 16 + 1], s) + b
323 s = md5_next_shift[s]
324 a = d
325 d = c
326 c = b
327 b = F
328 end
329
330 h1 = (a + h1) % 4294967296
331 h2 = (b + h2) % 4294967296
332 h3 = (c + h3) % 4294967296
333 h4 = (d + h4) % 4294967296
334 end
335
336 H[1], H[2], H[3], H[4] = h1, h2, h3, h4
337end
338
339local function sha1_feed_64(H, str, offs, size)
340 -- offs >= 0, size >= 0, size is multiple of 64
341 local W = common_W
342 local h1, h2, h3, h4, h5 = H[1], H[2], H[3], H[4], H[5]
343 for pos = offs, offs + size - 1, 64 do
344 for j = 1, 16 do
345 pos = pos + 4
346 local a, b, c, d = string.byte(str, pos - 3, pos)
347 W[j] = ((a * 256 + b) * 256 + c) * 256 + d
348 end
349
350 for j = 17, 80 do
351 W[j] = bit32_lrotate(bit32_bxor(W[j - 3], W[j - 8], W[j - 14], W[j - 16]), 1)
352 end
353
354 local a, b, c, d, e = h1, h2, h3, h4, h5
355 for j = 1, 20 do
356 local z = bit32_lrotate(a, 5) + bit32_band(b, c) + bit32_band(-1 - b, d) + 0x5A827999 + W[j] + e -- constant = math.floor(TWO_POW_30 * sqrt(2))
357 e = d
358 d = c
359 c = bit32_rrotate(b, 2)
360 b = a
361 a = z
362 end
363
364 for j = 21, 40 do
365 local z = bit32_lrotate(a, 5) + bit32_bxor(b, c, d) + 0x6ED9EBA1 + W[j] + e -- TWO_POW_30 * sqrt(3)
366 e = d
367 d = c
368 c = bit32_rrotate(b, 2)
369 b = a
370 a = z
371 end
372
373 for j = 41, 60 do
374 local z = bit32_lrotate(a, 5) + bit32_band(d, c) + bit32_band(b, bit32_bxor(d, c)) + 0x8F1BBCDC + W[j] + e -- TWO_POW_30 * sqrt(5)
375 e = d
376 d = c
377 c = bit32_rrotate(b, 2)
378 b = a
379 a = z
380 end
381
382 for j = 61, 80 do
383 local z = bit32_lrotate(a, 5) + bit32_bxor(b, c, d) + 0xCA62C1D6 + W[j] + e -- TWO_POW_30 * sqrt(10)
384 e = d
385 d = c
386 c = bit32_rrotate(b, 2)
387 b = a
388 a = z
389 end
390
391 h1 = (a + h1) % 4294967296
392 h2 = (b + h2) % 4294967296
393 h3 = (c + h3) % 4294967296
394 h4 = (d + h4) % 4294967296
395 h5 = (e + h5) % 4294967296
396 end
397
398 H[1], H[2], H[3], H[4], H[5] = h1, h2, h3, h4, h5
399end
400
401local function keccak_feed(lanes_lo, lanes_hi, str, offs, size, block_size_in_bytes)
402 -- This is an example of a Lua function having 79 local variables :-)
403 -- offs >= 0, size >= 0, size is multiple of block_size_in_bytes, block_size_in_bytes is positive multiple of 8
404 local RC_lo, RC_hi = sha3_RC_lo, sha3_RC_hi
405 local qwords_qty = block_size_in_bytes / 8
406 for pos = offs, offs + size - 1, block_size_in_bytes do
407 for j = 1, qwords_qty do
408 local a, b, c, d = string.byte(str, pos + 1, pos + 4)
409 lanes_lo[j] = bit32_bxor(lanes_lo[j], ((d * 256 + c) * 256 + b) * 256 + a)
410 pos = pos + 8
411 a, b, c, d = string.byte(str, pos - 3, pos)
412 lanes_hi[j] = bit32_bxor(lanes_hi[j], ((d * 256 + c) * 256 + b) * 256 + a)
413 end
414
415 local L01_lo, L01_hi, L02_lo, L02_hi, L03_lo, L03_hi, L04_lo, L04_hi, L05_lo, L05_hi, L06_lo, L06_hi, L07_lo, L07_hi, L08_lo, L08_hi, L09_lo, L09_hi, L10_lo, L10_hi, L11_lo, L11_hi, L12_lo, L12_hi, L13_lo, L13_hi, L14_lo, L14_hi, L15_lo, L15_hi, L16_lo, L16_hi, L17_lo, L17_hi, L18_lo, L18_hi, L19_lo, L19_hi, L20_lo, L20_hi, L21_lo, L21_hi, L22_lo, L22_hi, L23_lo, L23_hi, L24_lo, L24_hi, L25_lo, L25_hi = lanes_lo[1], lanes_hi[1], lanes_lo[2], lanes_hi[2], lanes_lo[3], lanes_hi[3], lanes_lo[4], lanes_hi[4], lanes_lo[5], lanes_hi[5], lanes_lo[6], lanes_hi[6], lanes_lo[7], lanes_hi[7], lanes_lo[8], lanes_hi[8], lanes_lo[9], lanes_hi[9], lanes_lo[10], lanes_hi[10], lanes_lo[11], lanes_hi[11], lanes_lo[12], lanes_hi[12], lanes_lo[13], lanes_hi[13], lanes_lo[14], lanes_hi[14], lanes_lo[15], lanes_hi[15], lanes_lo[16], lanes_hi[16], lanes_lo[17], lanes_hi[17], lanes_lo[18], lanes_hi[18], lanes_lo[19], lanes_hi[19], lanes_lo[20], lanes_hi[20], lanes_lo[21], lanes_hi[21], lanes_lo[22], lanes_hi[22], lanes_lo[23], lanes_hi[23], lanes_lo[24], lanes_hi[24], lanes_lo[25], lanes_hi[25]
416
417 for round_idx = 1, 24 do
418 local C1_lo = bit32_bxor(L01_lo, L06_lo, L11_lo, L16_lo, L21_lo)
419 local C1_hi = bit32_bxor(L01_hi, L06_hi, L11_hi, L16_hi, L21_hi)
420 local C2_lo = bit32_bxor(L02_lo, L07_lo, L12_lo, L17_lo, L22_lo)
421 local C2_hi = bit32_bxor(L02_hi, L07_hi, L12_hi, L17_hi, L22_hi)
422 local C3_lo = bit32_bxor(L03_lo, L08_lo, L13_lo, L18_lo, L23_lo)
423 local C3_hi = bit32_bxor(L03_hi, L08_hi, L13_hi, L18_hi, L23_hi)
424 local C4_lo = bit32_bxor(L04_lo, L09_lo, L14_lo, L19_lo, L24_lo)
425 local C4_hi = bit32_bxor(L04_hi, L09_hi, L14_hi, L19_hi, L24_hi)
426 local C5_lo = bit32_bxor(L05_lo, L10_lo, L15_lo, L20_lo, L25_lo)
427 local C5_hi = bit32_bxor(L05_hi, L10_hi, L15_hi, L20_hi, L25_hi)
428
429 local D_lo = bit32_bxor(C1_lo, C3_lo * 2 + (C3_hi % TWO_POW_32 - C3_hi % TWO_POW_31) / TWO_POW_31)
430 local D_hi = bit32_bxor(C1_hi, C3_hi * 2 + (C3_lo % TWO_POW_32 - C3_lo % TWO_POW_31) / TWO_POW_31)
431
432 local T0_lo = bit32_bxor(D_lo, L02_lo)
433 local T0_hi = bit32_bxor(D_hi, L02_hi)
434 local T1_lo = bit32_bxor(D_lo, L07_lo)
435 local T1_hi = bit32_bxor(D_hi, L07_hi)
436 local T2_lo = bit32_bxor(D_lo, L12_lo)
437 local T2_hi = bit32_bxor(D_hi, L12_hi)
438 local T3_lo = bit32_bxor(D_lo, L17_lo)
439 local T3_hi = bit32_bxor(D_hi, L17_hi)
440 local T4_lo = bit32_bxor(D_lo, L22_lo)
441 local T4_hi = bit32_bxor(D_hi, L22_hi)
442
443 L02_lo = (T1_lo % TWO_POW_32 - T1_lo % TWO_POW_20) / TWO_POW_20 + T1_hi * TWO_POW_12
444 L02_hi = (T1_hi % TWO_POW_32 - T1_hi % TWO_POW_20) / TWO_POW_20 + T1_lo * TWO_POW_12
445 L07_lo = (T3_lo % TWO_POW_32 - T3_lo % TWO_POW_19) / TWO_POW_19 + T3_hi * TWO_POW_13
446 L07_hi = (T3_hi % TWO_POW_32 - T3_hi % TWO_POW_19) / TWO_POW_19 + T3_lo * TWO_POW_13
447 L12_lo = T0_lo * 2 + (T0_hi % TWO_POW_32 - T0_hi % TWO_POW_31) / TWO_POW_31
448 L12_hi = T0_hi * 2 + (T0_lo % TWO_POW_32 - T0_lo % TWO_POW_31) / TWO_POW_31
449 L17_lo = T2_lo * TWO_POW_10 + (T2_hi % TWO_POW_32 - T2_hi % TWO_POW_22) / TWO_POW_22
450 L17_hi = T2_hi * TWO_POW_10 + (T2_lo % TWO_POW_32 - T2_lo % TWO_POW_22) / TWO_POW_22
451 L22_lo = T4_lo * TWO_POW_2 + (T4_hi % TWO_POW_32 - T4_hi % TWO_POW_30) / TWO_POW_30
452 L22_hi = T4_hi * TWO_POW_2 + (T4_lo % TWO_POW_32 - T4_lo % TWO_POW_30) / TWO_POW_30
453
454 D_lo = bit32_bxor(C2_lo, C4_lo * 2 + (C4_hi % TWO_POW_32 - C4_hi % TWO_POW_31) / TWO_POW_31)
455 D_hi = bit32_bxor(C2_hi, C4_hi * 2 + (C4_lo % TWO_POW_32 - C4_lo % TWO_POW_31) / TWO_POW_31)
456
457 T0_lo = bit32_bxor(D_lo, L03_lo)
458 T0_hi = bit32_bxor(D_hi, L03_hi)
459 T1_lo = bit32_bxor(D_lo, L08_lo)
460 T1_hi = bit32_bxor(D_hi, L08_hi)
461 T2_lo = bit32_bxor(D_lo, L13_lo)
462 T2_hi = bit32_bxor(D_hi, L13_hi)
463 T3_lo = bit32_bxor(D_lo, L18_lo)
464 T3_hi = bit32_bxor(D_hi, L18_hi)
465 T4_lo = bit32_bxor(D_lo, L23_lo)
466 T4_hi = bit32_bxor(D_hi, L23_hi)
467
468 L03_lo = (T2_lo % TWO_POW_32 - T2_lo % TWO_POW_21) / TWO_POW_21 + T2_hi * TWO_POW_11
469 L03_hi = (T2_hi % TWO_POW_32 - T2_hi % TWO_POW_21) / TWO_POW_21 + T2_lo * TWO_POW_11
470 L08_lo = (T4_lo % TWO_POW_32 - T4_lo % TWO_POW_3) / TWO_POW_3 + T4_hi * TWO_POW_29 % TWO_POW_32
471 L08_hi = (T4_hi % TWO_POW_32 - T4_hi % TWO_POW_3) / TWO_POW_3 + T4_lo * TWO_POW_29 % TWO_POW_32
472 L13_lo = T1_lo * TWO_POW_6 + (T1_hi % TWO_POW_32 - T1_hi % TWO_POW_26) / TWO_POW_26
473 L13_hi = T1_hi * TWO_POW_6 + (T1_lo % TWO_POW_32 - T1_lo % TWO_POW_26) / TWO_POW_26
474 L18_lo = T3_lo * TWO_POW_15 + (T3_hi % TWO_POW_32 - T3_hi % TWO_POW_17) / TWO_POW_17
475 L18_hi = T3_hi * TWO_POW_15 + (T3_lo % TWO_POW_32 - T3_lo % TWO_POW_17) / TWO_POW_17
476 L23_lo = (T0_lo % TWO_POW_32 - T0_lo % TWO_POW_2) / TWO_POW_2 + T0_hi * TWO_POW_30 % TWO_POW_32
477 L23_hi = (T0_hi % TWO_POW_32 - T0_hi % TWO_POW_2) / TWO_POW_2 + T0_lo * TWO_POW_30 % TWO_POW_32
478
479 D_lo = bit32_bxor(C3_lo, C5_lo * 2 + (C5_hi % TWO_POW_32 - C5_hi % TWO_POW_31) / TWO_POW_31)
480 D_hi = bit32_bxor(C3_hi, C5_hi * 2 + (C5_lo % TWO_POW_32 - C5_lo % TWO_POW_31) / TWO_POW_31)
481
482 T0_lo = bit32_bxor(D_lo, L04_lo)
483 T0_hi = bit32_bxor(D_hi, L04_hi)
484 T1_lo = bit32_bxor(D_lo, L09_lo)
485 T1_hi = bit32_bxor(D_hi, L09_hi)
486 T2_lo = bit32_bxor(D_lo, L14_lo)
487 T2_hi = bit32_bxor(D_hi, L14_hi)
488 T3_lo = bit32_bxor(D_lo, L19_lo)
489 T3_hi = bit32_bxor(D_hi, L19_hi)
490 T4_lo = bit32_bxor(D_lo, L24_lo)
491 T4_hi = bit32_bxor(D_hi, L24_hi)
492
493 L04_lo = T3_lo * TWO_POW_21 % TWO_POW_32 + (T3_hi % TWO_POW_32 - T3_hi % TWO_POW_11) / TWO_POW_11
494 L04_hi = T3_hi * TWO_POW_21 % TWO_POW_32 + (T3_lo % TWO_POW_32 - T3_lo % TWO_POW_11) / TWO_POW_11
495 L09_lo = T0_lo * TWO_POW_28 % TWO_POW_32 + (T0_hi % TWO_POW_32 - T0_hi % TWO_POW_4) / TWO_POW_4
496 L09_hi = T0_hi * TWO_POW_28 % TWO_POW_32 + (T0_lo % TWO_POW_32 - T0_lo % TWO_POW_4) / TWO_POW_4
497 L14_lo = T2_lo * TWO_POW_25 % TWO_POW_32 + (T2_hi % TWO_POW_32 - T2_hi % TWO_POW_7) / TWO_POW_7
498 L14_hi = T2_hi * TWO_POW_25 % TWO_POW_32 + (T2_lo % TWO_POW_32 - T2_lo % TWO_POW_7) / TWO_POW_7
499 L19_lo = (T4_lo % TWO_POW_32 - T4_lo % TWO_POW_8) / TWO_POW_8 + T4_hi * TWO_POW_24 % TWO_POW_32
500 L19_hi = (T4_hi % TWO_POW_32 - T4_hi % TWO_POW_8) / TWO_POW_8 + T4_lo * TWO_POW_24 % TWO_POW_32
501 L24_lo = (T1_lo % TWO_POW_32 - T1_lo % TWO_POW_9) / TWO_POW_9 + T1_hi * TWO_POW_23 % TWO_POW_32
502 L24_hi = (T1_hi % TWO_POW_32 - T1_hi % TWO_POW_9) / TWO_POW_9 + T1_lo * TWO_POW_23 % TWO_POW_32
503
504 D_lo = bit32_bxor(C4_lo, C1_lo * 2 + (C1_hi % TWO_POW_32 - C1_hi % TWO_POW_31) / TWO_POW_31)
505 D_hi = bit32_bxor(C4_hi, C1_hi * 2 + (C1_lo % TWO_POW_32 - C1_lo % TWO_POW_31) / TWO_POW_31)
506
507 T0_lo = bit32_bxor(D_lo, L05_lo)
508 T0_hi = bit32_bxor(D_hi, L05_hi)
509 T1_lo = bit32_bxor(D_lo, L10_lo)
510 T1_hi = bit32_bxor(D_hi, L10_hi)
511 T2_lo = bit32_bxor(D_lo, L15_lo)
512 T2_hi = bit32_bxor(D_hi, L15_hi)
513 T3_lo = bit32_bxor(D_lo, L20_lo)
514 T3_hi = bit32_bxor(D_hi, L20_hi)
515 T4_lo = bit32_bxor(D_lo, L25_lo)
516 T4_hi = bit32_bxor(D_hi, L25_hi)
517
518 L05_lo = T4_lo * TWO_POW_14 + (T4_hi % TWO_POW_32 - T4_hi % TWO_POW_18) / TWO_POW_18
519 L05_hi = T4_hi * TWO_POW_14 + (T4_lo % TWO_POW_32 - T4_lo % TWO_POW_18) / TWO_POW_18
520 L10_lo = T1_lo * TWO_POW_20 % TWO_POW_32 + (T1_hi % TWO_POW_32 - T1_hi % TWO_POW_12) / TWO_POW_12
521 L10_hi = T1_hi * TWO_POW_20 % TWO_POW_32 + (T1_lo % TWO_POW_32 - T1_lo % TWO_POW_12) / TWO_POW_12
522 L15_lo = T3_lo * TWO_POW_8 + (T3_hi % TWO_POW_32 - T3_hi % TWO_POW_24) / TWO_POW_24
523 L15_hi = T3_hi * TWO_POW_8 + (T3_lo % TWO_POW_32 - T3_lo % TWO_POW_24) / TWO_POW_24
524 L20_lo = T0_lo * TWO_POW_27 % TWO_POW_32 + (T0_hi % TWO_POW_32 - T0_hi % TWO_POW_5) / TWO_POW_5
525 L20_hi = T0_hi * TWO_POW_27 % TWO_POW_32 + (T0_lo % TWO_POW_32 - T0_lo % TWO_POW_5) / TWO_POW_5
526 L25_lo = (T2_lo % TWO_POW_32 - T2_lo % TWO_POW_25) / TWO_POW_25 + T2_hi * TWO_POW_7
527 L25_hi = (T2_hi % TWO_POW_32 - T2_hi % TWO_POW_25) / TWO_POW_25 + T2_lo * TWO_POW_7
528
529 D_lo = bit32_bxor(C5_lo, C2_lo * 2 + (C2_hi % TWO_POW_32 - C2_hi % TWO_POW_31) / TWO_POW_31)
530 D_hi = bit32_bxor(C5_hi, C2_hi * 2 + (C2_lo % TWO_POW_32 - C2_lo % TWO_POW_31) / TWO_POW_31)
531
532 T1_lo = bit32_bxor(D_lo, L06_lo)
533 T1_hi = bit32_bxor(D_hi, L06_hi)
534 T2_lo = bit32_bxor(D_lo, L11_lo)
535 T2_hi = bit32_bxor(D_hi, L11_hi)
536 T3_lo = bit32_bxor(D_lo, L16_lo)
537 T3_hi = bit32_bxor(D_hi, L16_hi)
538 T4_lo = bit32_bxor(D_lo, L21_lo)
539 T4_hi = bit32_bxor(D_hi, L21_hi)
540
541 L06_lo = T2_lo * TWO_POW_3 + (T2_hi % TWO_POW_32 - T2_hi % TWO_POW_29) / TWO_POW_29
542 L06_hi = T2_hi * TWO_POW_3 + (T2_lo % TWO_POW_32 - T2_lo % TWO_POW_29) / TWO_POW_29
543 L11_lo = T4_lo * TWO_POW_18 + (T4_hi % TWO_POW_32 - T4_hi % TWO_POW_14) / TWO_POW_14
544 L11_hi = T4_hi * TWO_POW_18 + (T4_lo % TWO_POW_32 - T4_lo % TWO_POW_14) / TWO_POW_14
545 L16_lo = (T1_lo % TWO_POW_32 - T1_lo % TWO_POW_28) / TWO_POW_28 + T1_hi * TWO_POW_4
546 L16_hi = (T1_hi % TWO_POW_32 - T1_hi % TWO_POW_28) / TWO_POW_28 + T1_lo * TWO_POW_4
547 L21_lo = (T3_lo % TWO_POW_32 - T3_lo % TWO_POW_23) / TWO_POW_23 + T3_hi * TWO_POW_9
548 L21_hi = (T3_hi % TWO_POW_32 - T3_hi % TWO_POW_23) / TWO_POW_23 + T3_lo * TWO_POW_9
549
550 L01_lo = bit32_bxor(D_lo, L01_lo)
551 L01_hi = bit32_bxor(D_hi, L01_hi)
552 L01_lo, L02_lo, L03_lo, L04_lo, L05_lo = bit32_bxor(L01_lo, bit32_band(-1 - L02_lo, L03_lo)), bit32_bxor(L02_lo, bit32_band(-1 - L03_lo, L04_lo)), bit32_bxor(L03_lo, bit32_band(-1 - L04_lo, L05_lo)), bit32_bxor(L04_lo, bit32_band(-1 - L05_lo, L01_lo)), bit32_bxor(L05_lo, bit32_band(-1 - L01_lo, L02_lo))
553 L01_hi, L02_hi, L03_hi, L04_hi, L05_hi = bit32_bxor(L01_hi, bit32_band(-1 - L02_hi, L03_hi)), bit32_bxor(L02_hi, bit32_band(-1 - L03_hi, L04_hi)), bit32_bxor(L03_hi, bit32_band(-1 - L04_hi, L05_hi)), bit32_bxor(L04_hi, bit32_band(-1 - L05_hi, L01_hi)), bit32_bxor(L05_hi, bit32_band(-1 - L01_hi, L02_hi))
554 L06_lo, L07_lo, L08_lo, L09_lo, L10_lo = bit32_bxor(L09_lo, bit32_band(-1 - L10_lo, L06_lo)), bit32_bxor(L10_lo, bit32_band(-1 - L06_lo, L07_lo)), bit32_bxor(L06_lo, bit32_band(-1 - L07_lo, L08_lo)), bit32_bxor(L07_lo, bit32_band(-1 - L08_lo, L09_lo)), bit32_bxor(L08_lo, bit32_band(-1 - L09_lo, L10_lo))
555 L06_hi, L07_hi, L08_hi, L09_hi, L10_hi = bit32_bxor(L09_hi, bit32_band(-1 - L10_hi, L06_hi)), bit32_bxor(L10_hi, bit32_band(-1 - L06_hi, L07_hi)), bit32_bxor(L06_hi, bit32_band(-1 - L07_hi, L08_hi)), bit32_bxor(L07_hi, bit32_band(-1 - L08_hi, L09_hi)), bit32_bxor(L08_hi, bit32_band(-1 - L09_hi, L10_hi))
556 L11_lo, L12_lo, L13_lo, L14_lo, L15_lo = bit32_bxor(L12_lo, bit32_band(-1 - L13_lo, L14_lo)), bit32_bxor(L13_lo, bit32_band(-1 - L14_lo, L15_lo)), bit32_bxor(L14_lo, bit32_band(-1 - L15_lo, L11_lo)), bit32_bxor(L15_lo, bit32_band(-1 - L11_lo, L12_lo)), bit32_bxor(L11_lo, bit32_band(-1 - L12_lo, L13_lo))
557 L11_hi, L12_hi, L13_hi, L14_hi, L15_hi = bit32_bxor(L12_hi, bit32_band(-1 - L13_hi, L14_hi)), bit32_bxor(L13_hi, bit32_band(-1 - L14_hi, L15_hi)), bit32_bxor(L14_hi, bit32_band(-1 - L15_hi, L11_hi)), bit32_bxor(L15_hi, bit32_band(-1 - L11_hi, L12_hi)), bit32_bxor(L11_hi, bit32_band(-1 - L12_hi, L13_hi))
558 L16_lo, L17_lo, L18_lo, L19_lo, L20_lo = bit32_bxor(L20_lo, bit32_band(-1 - L16_lo, L17_lo)), bit32_bxor(L16_lo, bit32_band(-1 - L17_lo, L18_lo)), bit32_bxor(L17_lo, bit32_band(-1 - L18_lo, L19_lo)), bit32_bxor(L18_lo, bit32_band(-1 - L19_lo, L20_lo)), bit32_bxor(L19_lo, bit32_band(-1 - L20_lo, L16_lo))
559 L16_hi, L17_hi, L18_hi, L19_hi, L20_hi = bit32_bxor(L20_hi, bit32_band(-1 - L16_hi, L17_hi)), bit32_bxor(L16_hi, bit32_band(-1 - L17_hi, L18_hi)), bit32_bxor(L17_hi, bit32_band(-1 - L18_hi, L19_hi)), bit32_bxor(L18_hi, bit32_band(-1 - L19_hi, L20_hi)), bit32_bxor(L19_hi, bit32_band(-1 - L20_hi, L16_hi))
560 L21_lo, L22_lo, L23_lo, L24_lo, L25_lo = bit32_bxor(L23_lo, bit32_band(-1 - L24_lo, L25_lo)), bit32_bxor(L24_lo, bit32_band(-1 - L25_lo, L21_lo)), bit32_bxor(L25_lo, bit32_band(-1 - L21_lo, L22_lo)), bit32_bxor(L21_lo, bit32_band(-1 - L22_lo, L23_lo)), bit32_bxor(L22_lo, bit32_band(-1 - L23_lo, L24_lo))
561 L21_hi, L22_hi, L23_hi, L24_hi, L25_hi = bit32_bxor(L23_hi, bit32_band(-1 - L24_hi, L25_hi)), bit32_bxor(L24_hi, bit32_band(-1 - L25_hi, L21_hi)), bit32_bxor(L25_hi, bit32_band(-1 - L21_hi, L22_hi)), bit32_bxor(L21_hi, bit32_band(-1 - L22_hi, L23_hi)), bit32_bxor(L22_hi, bit32_band(-1 - L23_hi, L24_hi))
562 L01_lo = bit32_bxor(L01_lo, RC_lo[round_idx])
563 L01_hi = L01_hi + RC_hi[round_idx] -- RC_hi[] is either 0 or 0x80000000, so we could use fast addition instead of slow XOR
564 end
565
566 lanes_lo[1] = L01_lo
567 lanes_hi[1] = L01_hi
568 lanes_lo[2] = L02_lo
569 lanes_hi[2] = L02_hi
570 lanes_lo[3] = L03_lo
571 lanes_hi[3] = L03_hi
572 lanes_lo[4] = L04_lo
573 lanes_hi[4] = L04_hi
574 lanes_lo[5] = L05_lo
575 lanes_hi[5] = L05_hi
576 lanes_lo[6] = L06_lo
577 lanes_hi[6] = L06_hi
578 lanes_lo[7] = L07_lo
579 lanes_hi[7] = L07_hi
580 lanes_lo[8] = L08_lo
581 lanes_hi[8] = L08_hi
582 lanes_lo[9] = L09_lo
583 lanes_hi[9] = L09_hi
584 lanes_lo[10] = L10_lo
585 lanes_hi[10] = L10_hi
586 lanes_lo[11] = L11_lo
587 lanes_hi[11] = L11_hi
588 lanes_lo[12] = L12_lo
589 lanes_hi[12] = L12_hi
590 lanes_lo[13] = L13_lo
591 lanes_hi[13] = L13_hi
592 lanes_lo[14] = L14_lo
593 lanes_hi[14] = L14_hi
594 lanes_lo[15] = L15_lo
595 lanes_hi[15] = L15_hi
596 lanes_lo[16] = L16_lo
597 lanes_hi[16] = L16_hi
598 lanes_lo[17] = L17_lo
599 lanes_hi[17] = L17_hi
600 lanes_lo[18] = L18_lo
601 lanes_hi[18] = L18_hi
602 lanes_lo[19] = L19_lo
603 lanes_hi[19] = L19_hi
604 lanes_lo[20] = L20_lo
605 lanes_hi[20] = L20_hi
606 lanes_lo[21] = L21_lo
607 lanes_hi[21] = L21_hi
608 lanes_lo[22] = L22_lo
609 lanes_hi[22] = L22_hi
610 lanes_lo[23] = L23_lo
611 lanes_hi[23] = L23_hi
612 lanes_lo[24] = L24_lo
613 lanes_hi[24] = L24_hi
614 lanes_lo[25] = L25_lo
615 lanes_hi[25] = L25_hi
616 end
617end
618
619--------------------------------------------------------------------------------
620-- MAGIC NUMBERS CALCULATOR
621--------------------------------------------------------------------------------
622-- Q:
623-- Is 53-bit "double" math enough to calculate square roots and cube roots of primes with 64 correct bits after decimal point?
624-- A:
625-- Yes, 53-bit "double" arithmetic is enough.
626-- We could obtain first 40 bits by direct calculation of p^(1/3) and next 40 bits by one step of Newton's method.
627do
628 local function mul(src1, src2, factor, result_length)
629 -- src1, src2 - long integers (arrays of digits in base TWO_POW_24)
630 -- factor - small integer
631 -- returns long integer result (src1 * src2 * factor) and its floating point approximation
632 local result, carry, value, weight = table.create(result_length), 0, 0, 1
633 for j = 1, result_length do
634 for k = math.max(1, j + 1 - #src2), math.min(j, #src1) do
635 carry = carry + factor * src1[k] * src2[j + 1 - k] -- "int32" is not enough for multiplication result, that's why "factor" must be of type "double"
636 end
637
638 local digit = carry % TWO_POW_24
639 result[j] = math.floor(digit)
640 carry = (carry - digit) / TWO_POW_24
641 value = value + digit * weight
642 weight = weight * TWO_POW_24
643 end
644
645 return result, value
646 end
647
648 local idx, step, p, one, sqrt_hi, sqrt_lo = 0, {4, 1, 2, -2, 2}, 4, {1}, sha2_H_hi, sha2_H_lo
649 repeat
650 p = p + step[p % 6]
651 local d = 1
652 repeat
653 d = d + step[d % 6]
654 if d * d > p then
655 -- next prime number is found
656 local root = p ^ (1 / 3)
657 local R = root * TWO_POW_40
658 R = mul(table.create(1, math.floor(R)), one, 1, 2)
659 local _, delta = mul(R, mul(R, R, 1, 4), -1, 4)
660 local hi = R[2] % 65536 * 65536 + math.floor(R[1] / 256)
661 local lo = R[1] % 256 * 16777216 + math.floor(delta * (TWO_POW_NEG_56 / 3) * root / p)
662
663 if idx < 16 then
664 root = math.sqrt(p)
665 R = root * TWO_POW_40
666 R = mul(table.create(1, math.floor(R)), one, 1, 2)
667 _, delta = mul(R, R, -1, 2)
668 local hi = R[2] % 65536 * 65536 + math.floor(R[1] / 256)
669 local lo = R[1] % 256 * 16777216 + math.floor(delta * TWO_POW_NEG_17 / root)
670 local idx = idx % 8 + 1
671 sha2_H_ext256[224][idx] = lo
672 sqrt_hi[idx], sqrt_lo[idx] = hi, lo + hi * hi_factor
673 if idx > 7 then
674 sqrt_hi, sqrt_lo = sha2_H_ext512_hi[384], sha2_H_ext512_lo[384]
675 end
676 end
677
678 idx = idx + 1
679 sha2_K_hi[idx], sha2_K_lo[idx] = hi, lo % K_lo_modulo + hi * hi_factor
680 break
681 end
682 until p % d == 0
683 until idx > 79
684end
685
686-- Calculating IVs for SHA512/224 and SHA512/256
687for width = 224, 256, 32 do
688 local H_lo, H_hi = {}, nil
689 if XOR64A5 then
690 for j = 1, 8 do
691 H_lo[j] = XOR64A5(sha2_H_lo[j])
692 end
693 else
694 H_hi = {}
695 for j = 1, 8 do
696 H_lo[j] = bit32_bxor(sha2_H_lo[j], 0xA5A5A5A5) % 4294967296
697 H_hi[j] = bit32_bxor(sha2_H_hi[j], 0xA5A5A5A5) % 4294967296
698 end
699 end
700
701 sha512_feed_128(H_lo, H_hi, "SHA-512/" .. tostring(width) .. "\128" .. string.rep("\0", 115) .. "\88", 0, 128)
702 sha2_H_ext512_lo[width] = H_lo
703 sha2_H_ext512_hi[width] = H_hi
704end
705
706-- Constants for MD5
707do
708 for idx = 1, 64 do
709 -- we can't use formula math.floor(abs(sin(idx))*TWO_POW_32) because its result may be beyond integer range on Lua built with 32-bit integers
710 local hi, lo = math.modf(math.abs(math.sin(idx)) * TWO_POW_16)
711 md5_K[idx] = hi * 65536 + math.floor(lo * TWO_POW_16)
712 end
713end
714
715-- Constants for SHA3
716do
717 local sh_reg = 29
718 local function next_bit()
719 local r = sh_reg % 2
720 sh_reg = bit32_bxor((sh_reg - r) / 2, 142 * r)
721 return r
722 end
723
724 for idx = 1, 24 do
725 local lo, m = 0, nil
726 for _ = 1, 6 do
727 m = m and m * m * 2 or 1
728 lo = lo + next_bit() * m
729 end
730
731 local hi = next_bit() * m
732 sha3_RC_hi[idx], sha3_RC_lo[idx] = hi, lo + hi * hi_factor_keccak
733 end
734end
735
736--------------------------------------------------------------------------------
737-- MAIN FUNCTIONS
738--------------------------------------------------------------------------------
739local function sha256ext(width, message)
740 -- Create an instance (private objects for current calculation)
741 local Array256 = sha2_H_ext256[width] -- # == 8
742 local length, tail = 0, ""
743 local H = table.create(8)
744 H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = Array256[1], Array256[2], Array256[3], Array256[4], Array256[5], Array256[6], Array256[7], Array256[8]
745
746 local function partial(message_part)
747 if message_part then
748 local partLength = #message_part
749 if tail then
750 length = length + partLength
751 local offs = 0
752 local tailLength = #tail
753 if tail ~= "" and tailLength + partLength >= 64 then
754 offs = 64 - tailLength
755 sha256_feed_64(H, tail .. string.sub(message_part, 1, offs), 0, 64)
756 tail = ""
757 end
758
759 local size = partLength - offs
760 local size_tail = size % 64
761 sha256_feed_64(H, message_part, offs, size - size_tail)
762 tail = tail .. string.sub(message_part, partLength + 1 - size_tail)
763 return partial
764 else
765 error("Adding more chunks is not allowed after receiving the result", 2)
766 end
767 else
768 if tail then
769 local final_blocks = table.create(10) --{tail, "\128", string.rep("\0", (-9 - length) % 64 + 1)}
770 final_blocks[1] = tail
771 final_blocks[2] = "\128"
772 final_blocks[3] = string.rep("\0", (-9 - length) % 64 + 1)
773
774 tail = nil
775 -- Assuming user data length is shorter than (TWO_POW_53)-9 bytes
776 -- Anyway, it looks very unrealistic that someone would spend more than a year of calculations to process TWO_POW_53 bytes of data by using this Lua script :-)
777 -- TWO_POW_53 bytes = TWO_POW_56 bits, so "bit-counter" fits in 7 bytes
778 length = length * (8 / TWO56_POW_7) -- convert "byte-counter" to "bit-counter" and move decimal point to the left
779 for j = 4, 10 do
780 length = length % 1 * 256
781 final_blocks[j] = string.char(math.floor(length))
782 end
783
784 final_blocks = table.concat(final_blocks)
785 sha256_feed_64(H, final_blocks, 0, #final_blocks)
786 local max_reg = width / 32
787 for j = 1, max_reg do
788 H[j] = string.format("%08x", H[j] % 4294967296)
789 end
790
791 H = table.concat(H, "", 1, max_reg)
792 end
793
794 return H
795 end
796 end
797
798 if message then
799 -- Actually perform calculations and return the SHA256 digest of a message
800 return partial(message)()
801 else
802 -- Return function for chunk-by-chunk loading
803 -- User should feed every chunk of input data as single argument to this function and finally get SHA256 digest by invoking this function without an argument
804 return partial
805 end
806end
807
808local function sha512ext(width, message)
809
810 -- Create an instance (private objects for current calculation)
811 local length, tail, H_lo, H_hi = 0, "", table.pack(table.unpack(sha2_H_ext512_lo[width])), not HEX64 and table.pack(table.unpack(sha2_H_ext512_hi[width]))
812
813 local function partial(message_part)
814 if message_part then
815 local partLength = #message_part
816 if tail then
817 length = length + partLength
818 local offs = 0
819 if tail ~= "" and #tail + partLength >= 128 then
820 offs = 128 - #tail
821 sha512_feed_128(H_lo, H_hi, tail .. string.sub(message_part, 1, offs), 0, 128)
822 tail = ""
823 end
824
825 local size = partLength - offs
826 local size_tail = size % 128
827 sha512_feed_128(H_lo, H_hi, message_part, offs, size - size_tail)
828 tail = tail .. string.sub(message_part, partLength + 1 - size_tail)
829 return partial
830 else
831 error("Adding more chunks is not allowed after receiving the result", 2)
832 end
833 else
834 if tail then
835 local final_blocks = table.create(3) --{tail, "\128", string.rep("\0", (-17-length) % 128 + 9)}
836 final_blocks[1] = tail
837 final_blocks[2] = "\128"
838 final_blocks[3] = string.rep("\0", (-17 - length) % 128 + 9)
839
840 tail = nil
841 -- Assuming user data length is shorter than (TWO_POW_53)-17 bytes
842 -- TWO_POW_53 bytes = TWO_POW_56 bits, so "bit-counter" fits in 7 bytes
843 length = length * (8 / TWO56_POW_7) -- convert "byte-counter" to "bit-counter" and move floating point to the left
844 for j = 4, 10 do
845 length = length % 1 * 256
846 final_blocks[j] = string.char(math.floor(length))
847 end
848
849 final_blocks = table.concat(final_blocks)
850 sha512_feed_128(H_lo, H_hi, final_blocks, 0, #final_blocks)
851 local max_reg = math.ceil(width / 64)
852
853 if HEX64 then
854 for j = 1, max_reg do
855 H_lo[j] = HEX64(H_lo[j])
856 end
857 else
858 for j = 1, max_reg do
859 H_lo[j] = string.format("%08x", H_hi[j] % 4294967296) .. string.format("%08x", H_lo[j] % 4294967296)
860 end
861
862 H_hi = nil
863 end
864
865 H_lo = string.sub(table.concat(H_lo, "", 1, max_reg), 1, width / 4)
866 end
867
868 return H_lo
869 end
870 end
871
872 if message then
873 -- Actually perform calculations and return the SHA512 digest of a message
874 return partial(message)()
875 else
876 -- Return function for chunk-by-chunk loading
877 -- User should feed every chunk of input data as single argument to this function and finally get SHA512 digest by invoking this function without an argument
878 return partial
879 end
880end
881
882local function md5(message)
883
884 -- Create an instance (private objects for current calculation)
885 local H, length, tail = table.create(4), 0, ""
886 H[1], H[2], H[3], H[4] = md5_sha1_H[1], md5_sha1_H[2], md5_sha1_H[3], md5_sha1_H[4]
887
888 local function partial(message_part)
889 if message_part then
890 local partLength = #message_part
891 if tail then
892 length = length + partLength
893 local offs = 0
894 if tail ~= "" and #tail + partLength >= 64 then
895 offs = 64 - #tail
896 md5_feed_64(H, tail .. string.sub(message_part, 1, offs), 0, 64)
897 tail = ""
898 end
899
900 local size = partLength - offs
901 local size_tail = size % 64
902 md5_feed_64(H, message_part, offs, size - size_tail)
903 tail = tail .. string.sub(message_part, partLength + 1 - size_tail)
904 return partial
905 else
906 error("Adding more chunks is not allowed after receiving the result", 2)
907 end
908 else
909 if tail then
910 local final_blocks = table.create(3) --{tail, "\128", string.rep("\0", (-9 - length) % 64)}
911 final_blocks[1] = tail
912 final_blocks[2] = "\128"
913 final_blocks[3] = string.rep("\0", (-9 - length) % 64)
914 tail = nil
915 length = length * 8 -- convert "byte-counter" to "bit-counter"
916 for j = 4, 11 do
917 local low_byte = length % 256
918 final_blocks[j] = string.char(low_byte)
919 length = (length - low_byte) / 256
920 end
921
922 final_blocks = table.concat(final_blocks)
923 md5_feed_64(H, final_blocks, 0, #final_blocks)
924 for j = 1, 4 do
925 H[j] = string.format("%08x", H[j] % 4294967296)
926 end
927
928 H = string.gsub(table.concat(H), "(..)(..)(..)(..)", "%4%3%2%1")
929 end
930
931 return H
932 end
933 end
934
935 if message then
936 -- Actually perform calculations and return the MD5 digest of a message
937 return partial(message)()
938 else
939 -- Return function for chunk-by-chunk loading
940 -- User should feed every chunk of input data as single argument to this function and finally get MD5 digest by invoking this function without an argument
941 return partial
942 end
943end
944
945local function sha1(message)
946 -- Create an instance (private objects for current calculation)
947 local H, length, tail = table.pack(table.unpack(md5_sha1_H)), 0, ""
948
949 local function partial(message_part)
950 if message_part then
951 local partLength = #message_part
952 if tail then
953 length = length + partLength
954 local offs = 0
955 if tail ~= "" and #tail + partLength >= 64 then
956 offs = 64 - #tail
957 sha1_feed_64(H, tail .. string.sub(message_part, 1, offs), 0, 64)
958 tail = ""
959 end
960
961 local size = partLength - offs
962 local size_tail = size % 64
963 sha1_feed_64(H, message_part, offs, size - size_tail)
964 tail = tail .. string.sub(message_part, partLength + 1 - size_tail)
965 return partial
966 else
967 error("Adding more chunks is not allowed after receiving the result", 2)
968 end
969 else
970 if tail then
971 local final_blocks = table.create(10) --{tail, "\128", string.rep("\0", (-9 - length) % 64 + 1)}
972 final_blocks[1] = tail
973 final_blocks[2] = "\128"
974 final_blocks[3] = string.rep("\0", (-9 - length) % 64 + 1)
975 tail = nil
976
977 -- Assuming user data length is shorter than (TWO_POW_53)-9 bytes
978 -- TWO_POW_53 bytes = TWO_POW_56 bits, so "bit-counter" fits in 7 bytes
979 length = length * (8 / TWO56_POW_7) -- convert "byte-counter" to "bit-counter" and move decimal point to the left
980 for j = 4, 10 do
981 length = length % 1 * 256
982 final_blocks[j] = string.char(math.floor(length))
983 end
984
985 final_blocks = table.concat(final_blocks)
986 sha1_feed_64(H, final_blocks, 0, #final_blocks)
987 for j = 1, 5 do
988 H[j] = string.format("%08x", H[j] % 4294967296)
989 end
990
991 H = table.concat(H)
992 end
993
994 return H
995 end
996 end
997
998 if message then
999 -- Actually perform calculations and return the SHA-1 digest of a message
1000 return partial(message)()
1001 else
1002 -- Return function for chunk-by-chunk loading
1003 -- User should feed every chunk of input data as single argument to this function and finally get SHA-1 digest by invoking this function without an argument
1004 return partial
1005 end
1006end
1007
1008local function keccak(block_size_in_bytes, digest_size_in_bytes, is_SHAKE, message)
1009 -- "block_size_in_bytes" is multiple of 8
1010 if type(digest_size_in_bytes) ~= "number" then
1011 -- arguments in SHAKE are swapped:
1012 -- NIST FIPS 202 defines SHAKE(message,num_bits)
1013 -- this module defines SHAKE(num_bytes,message)
1014 -- it's easy to forget about this swap, hence the check
1015 error("Argument 'digest_size_in_bytes' must be a number", 2)
1016 end
1017
1018 -- Create an instance (private objects for current calculation)
1019 local tail, lanes_lo, lanes_hi = "", table.create(25, 0), hi_factor_keccak == 0 and table.create(25, 0)
1020 local result
1021
1022 --~ pad the input N using the pad function, yielding a padded bit string P with a length divisible by r (such that n = len(P)/r is integer),
1023 --~ break P into n consecutive r-bit pieces P0, ..., Pn-1 (last is zero-padded)
1024 --~ initialize the state S to a string of b 0 bits.
1025 --~ absorb the input into the state: For each block Pi,
1026 --~ extend Pi at the end by a string of c 0 bits, yielding one of length b,
1027 --~ XOR that with S and
1028 --~ apply the block permutation f to the result, yielding a new state S
1029 --~ initialize Z to be the empty string
1030 --~ while the length of Z is less than d:
1031 --~ append the first r bits of S to Z
1032 --~ if Z is still less than d bits long, apply f to S, yielding a new state S.
1033 --~ truncate Z to d bits
1034 local function partial(message_part)
1035 if message_part then
1036 local partLength = #message_part
1037 if tail then
1038 local offs = 0
1039 if tail ~= "" and #tail + partLength >= block_size_in_bytes then
1040 offs = block_size_in_bytes - #tail
1041 keccak_feed(lanes_lo, lanes_hi, tail .. string.sub(message_part, 1, offs), 0, block_size_in_bytes, block_size_in_bytes)
1042 tail = ""
1043 end
1044
1045 local size = partLength - offs
1046 local size_tail = size % block_size_in_bytes
1047 keccak_feed(lanes_lo, lanes_hi, message_part, offs, size - size_tail, block_size_in_bytes)
1048 tail = tail .. string.sub(message_part, partLength + 1 - size_tail)
1049 return partial
1050 else
1051 error("Adding more chunks is not allowed after receiving the result", 2)
1052 end
1053 else
1054 if tail then
1055 -- append the following bits to the message: for usual SHA3: 011(0*)1, for SHAKE: 11111(0*)1
1056 local gap_start = is_SHAKE and 31 or 6
1057 tail = tail .. (#tail + 1 == block_size_in_bytes and string.char(gap_start + 128) or string.char(gap_start) .. string.rep("\0", (-2 - #tail) % block_size_in_bytes) .. "\128")
1058 keccak_feed(lanes_lo, lanes_hi, tail, 0, #tail, block_size_in_bytes)
1059 tail = nil
1060
1061 local lanes_used = 0
1062 local total_lanes = math.floor(block_size_in_bytes / 8)
1063 local qwords = {}
1064
1065 local function get_next_qwords_of_digest(qwords_qty)
1066 -- returns not more than 'qwords_qty' qwords ('qwords_qty' might be non-integer)
1067 -- doesn't go across keccak-buffer boundary
1068 -- block_size_in_bytes is a multiple of 8, so, keccak-buffer contains integer number of qwords
1069 if lanes_used >= total_lanes then
1070 keccak_feed(lanes_lo, lanes_hi, "\0\0\0\0\0\0\0\0", 0, 8, 8)
1071 lanes_used = 0
1072 end
1073
1074 qwords_qty = math.floor(math.min(qwords_qty, total_lanes - lanes_used))
1075 if hi_factor_keccak ~= 0 then
1076 for j = 1, qwords_qty do
1077 qwords[j] = HEX64(lanes_lo[lanes_used + j - 1 + lanes_index_base])
1078 end
1079 else
1080 for j = 1, qwords_qty do
1081 qwords[j] = string.format("%08x", lanes_hi[lanes_used + j] % 4294967296) .. string.format("%08x", lanes_lo[lanes_used + j] % 4294967296)
1082 end
1083 end
1084
1085 lanes_used = lanes_used + qwords_qty
1086 return string.gsub(table.concat(qwords, "", 1, qwords_qty), "(..)(..)(..)(..)(..)(..)(..)(..)", "%8%7%6%5%4%3%2%1"), qwords_qty * 8
1087 end
1088
1089 local parts = {} -- digest parts
1090 local last_part, last_part_size = "", 0
1091
1092 local function get_next_part_of_digest(bytes_needed)
1093 -- returns 'bytes_needed' bytes, for arbitrary integer 'bytes_needed'
1094 bytes_needed = bytes_needed or 1
1095 if bytes_needed <= last_part_size then
1096 last_part_size = last_part_size - bytes_needed
1097 local part_size_in_nibbles = bytes_needed * 2
1098 local result = string.sub(last_part, 1, part_size_in_nibbles)
1099 last_part = string.sub(last_part, part_size_in_nibbles + 1)
1100 return result
1101 end
1102
1103 local parts_qty = 0
1104 if last_part_size > 0 then
1105 parts_qty = 1
1106 parts[parts_qty] = last_part
1107 bytes_needed = bytes_needed - last_part_size
1108 end
1109
1110 -- repeats until the length is enough
1111 while bytes_needed >= 8 do
1112 local next_part, next_part_size = get_next_qwords_of_digest(bytes_needed / 8)
1113 parts_qty = parts_qty + 1
1114 parts[parts_qty] = next_part
1115 bytes_needed = bytes_needed - next_part_size
1116 end
1117
1118 if bytes_needed > 0 then
1119 last_part, last_part_size = get_next_qwords_of_digest(1)
1120 parts_qty = parts_qty + 1
1121 parts[parts_qty] = get_next_part_of_digest(bytes_needed)
1122 else
1123 last_part, last_part_size = "", 0
1124 end
1125
1126 return table.concat(parts, "", 1, parts_qty)
1127 end
1128
1129 if digest_size_in_bytes < 0 then
1130 result = get_next_part_of_digest
1131 else
1132 result = get_next_part_of_digest(digest_size_in_bytes)
1133 end
1134
1135 end
1136
1137 return result
1138 end
1139 end
1140
1141 if message then
1142 -- Actually perform calculations and return the SHA3 digest of a message
1143 return partial(message)()
1144 else
1145 -- Return function for chunk-by-chunk loading
1146 -- User should feed every chunk of input data as single argument to this function and finally get SHA3 digest by invoking this function without an argument
1147 return partial
1148 end
1149end
1150
1151local function HexToBinFunction(hh)
1152 return string.char(tonumber(hh, 16))
1153end
1154
1155local function hex2bin(hex_string)
1156 return (string.gsub(hex_string, "%x%x", HexToBinFunction))
1157end
1158
1159local base64_symbols = {
1160 ["+"] = 62, ["-"] = 62, [62] = "+";
1161 ["/"] = 63, ["_"] = 63, [63] = "/";
1162 ["="] = -1, ["."] = -1, [-1] = "=";
1163}
1164
1165local symbol_index = 0
1166for j, pair in ipairs{"AZ", "az", "09"} do
1167 for ascii = string.byte(pair), string.byte(pair, 2) do
1168 local ch = string.char(ascii)
1169 base64_symbols[ch] = symbol_index
1170 base64_symbols[symbol_index] = ch
1171 symbol_index = symbol_index + 1
1172 end
1173end
1174
1175local function bin2base64(binary_string)
1176 local stringLength = #binary_string
1177 local result = table.create(math.ceil(stringLength / 3))
1178 local length = 0
1179
1180 for pos = 1, #binary_string, 3 do
1181 local c1, c2, c3, c4 = string.byte(string.sub(binary_string, pos, pos + 2) .. '\0', 1, -1)
1182 length = length + 1
1183 result[length] =
1184 base64_symbols[math.floor(c1 / 4)] ..
1185 base64_symbols[c1 % 4 * 16 + math.floor(c2 / 16)] ..
1186 base64_symbols[c3 and c2 % 16 * 4 + math.floor(c3 / 64) or -1] ..
1187 base64_symbols[c4 and c3 % 64 or -1]
1188 end
1189
1190 return table.concat(result)
1191end
1192
1193local function base642bin(base64_string)
1194 local result, chars_qty = {}, 3
1195 for pos, ch in string.gmatch(string.gsub(base64_string, "%s+", ""), "()(.)") do
1196 local code = base64_symbols[ch]
1197 if code < 0 then
1198 chars_qty = chars_qty - 1
1199 code = 0
1200 end
1201
1202 local idx = pos % 4
1203 if idx > 0 then
1204 result[-idx] = code
1205 else
1206 local c1 = result[-1] * 4 + math.floor(result[-2] / 16)
1207 local c2 = (result[-2] % 16) * 16 + math.floor(result[-3] / 4)
1208 local c3 = (result[-3] % 4) * 64 + code
1209 result[#result + 1] = string.sub(string.char(c1, c2, c3), 1, chars_qty)
1210 end
1211 end
1212
1213 return table.concat(result)
1214end
1215
1216local block_size_for_HMAC -- this table will be initialized at the end of the module
1217--local function pad_and_xor(str, result_length, byte_for_xor)
1218-- return string.gsub(str, ".", function(c)
1219-- return string.char(bit32_bxor(string.byte(c), byte_for_xor))
1220-- end) .. string.rep(string.char(byte_for_xor), result_length - #str)
1221--end
1222
1223-- For the sake of speed of converting hexes to strings, there's a map of the conversions here
1224local BinaryStringMap = {}
1225for Index = 0, 255 do
1226 BinaryStringMap[string.format("%02x", Index)] = string.char(Index)
1227end
1228
1229-- Update 02.14.20 - added AsBinary for easy GameAnalytics replacement.
1230local function hmac(hash_func, key, message, AsBinary)
1231 -- Create an instance (private objects for current calculation)
1232 local block_size = block_size_for_HMAC[hash_func]
1233 if not block_size then
1234 error("Unknown hash function", 2)
1235 end
1236
1237 local KeyLength = #key
1238 if KeyLength > block_size then
1239 key = string.gsub(hash_func(key), "%x%x", HexToBinFunction)
1240 KeyLength = #key
1241 end
1242
1243 local append = hash_func()(string.gsub(key, ".", function(c)
1244 return string.char(bit32_bxor(string.byte(c), 0x36))
1245 end) .. string.rep("6", block_size - KeyLength)) -- 6 = string.char(0x36)
1246
1247 local result
1248
1249 local function partial(message_part)
1250 if not message_part then
1251 result = result or hash_func(
1252 string.gsub(key, ".", function(c)
1253 return string.char(bit32_bxor(string.byte(c), 0x5c))
1254 end) .. string.rep("\\", block_size - KeyLength) -- \ = string.char(0x5c)
1255 .. (string.gsub(append(), "%x%x", HexToBinFunction))
1256 )
1257
1258 return result
1259 elseif result then
1260 error("Adding more chunks is not allowed after receiving the result", 2)
1261 else
1262 append(message_part)
1263 return partial
1264 end
1265 end
1266
1267 if message then
1268 -- Actually perform calculations and return the HMAC of a message
1269 local FinalMessage = partial(message)()
1270 return AsBinary and (string.gsub(FinalMessage, "%x%x", BinaryStringMap)) or FinalMessage
1271 else
1272 -- Return function for chunk-by-chunk loading of a message
1273 -- User should feed every chunk of the message as single argument to this function and finally get HMAC by invoking this function without an argument
1274 return partial
1275 end
1276end
1277
1278local sha = {
1279 md5 = md5,
1280 sha1 = sha1,
1281 -- SHA2 hash functions:
1282 sha224 = function(message)
1283 return sha256ext(224, message)
1284 end;
1285
1286 sha256 = function(message)
1287 return sha256ext(256, message)
1288 end;
1289
1290 sha512_224 = function(message)
1291 return sha512ext(224, message)
1292 end;
1293
1294 sha512_256 = function(message)
1295 return sha512ext(256, message)
1296 end;
1297
1298 sha384 = function(message)
1299 return sha512ext(384, message)
1300 end;
1301
1302 sha512 = function(message)
1303 return sha512ext(512, message)
1304 end;
1305
1306 -- SHA3 hash functions:
1307 sha3_224 = function(message)
1308 return keccak((1600 - 2 * 224) / 8, 224 / 8, false, message)
1309 end;
1310
1311 sha3_256 = function(message)
1312 return keccak((1600 - 2 * 256) / 8, 256 / 8, false, message)
1313 end;
1314
1315 sha3_384 = function(message)
1316 return keccak((1600 - 2 * 384) / 8, 384 / 8, false, message)
1317 end;
1318
1319 sha3_512 = function(message)
1320 return keccak((1600 - 2 * 512) / 8, 512 / 8, false, message)
1321 end;
1322
1323 shake128 = function(message, digest_size_in_bytes)
1324 return keccak((1600 - 2 * 128) / 8, digest_size_in_bytes, true, message)
1325 end;
1326
1327 shake256 = function(message, digest_size_in_bytes)
1328 return keccak((1600 - 2 * 256) / 8, digest_size_in_bytes, true, message)
1329 end;
1330
1331 -- misc utilities:
1332 hmac = hmac; -- HMAC(hash_func, key, message) is applicable to any hash function from this module except SHAKE*
1333 hex_to_bin = hex2bin; -- converts hexadecimal representation to binary string
1334 base64_to_bin = base642bin; -- converts base64 representation to binary string
1335 bin_to_base64 = bin2base64; -- converts binary string to base64 representation
1336 base64_encode = Base64.Encode;
1337 base64_decode = Base64.Decode;
1338}
1339
1340block_size_for_HMAC = {
1341 [sha.md5] = 64;
1342 [sha.sha1] = 64;
1343 [sha.sha224] = 64;
1344 [sha.sha256] = 64;
1345 [sha.sha512_224] = 128;
1346 [sha.sha512_256] = 128;
1347 [sha.sha384] = 128;
1348 [sha.sha512] = 128;
1349 [sha.sha3_224] = (1600 - 2 * 224) / 8;
1350 [sha.sha3_256] = (1600 - 2 * 256) / 8;
1351 [sha.sha3_384] = (1600 - 2 * 384) / 8;
1352 [sha.sha3_512] = (1600 - 2 * 512) / 8;
1353}
1354
1355return sha