diff --git a/README.MD b/README.MD index 05c93e7..87edb20 100644 --- a/README.MD +++ b/README.MD @@ -1,9 +1,9 @@ ## HAProxy DDoS protection system A fork and further development of a proof of concept from https://github.com/mora9715/haproxy_ddos_protector, a HAProxy configuration and lua scripts allowing a challenge-response page where users solve a captcha and/or proof-of-work. -Intended to stop bots, spam, ddos, etc. +Intended to stop bots, spam, ddos, -Will soon™ be accompanied by a control panel allowing to manage clusters of servers with this installed. Allowing you to add/remove/edit domains, protection rules, blocked ips, backend server IPs, etc during runtime. +Integrates with https://gitgud.io/fatchan/haproxy-panel-next to add/remove/edit domains, protection rules, blocked ips, backend server IPs, etc during runtime. Improvements in this fork: @@ -28,6 +28,8 @@ Add some env vars to docker-compose file: - HCAPTCHA_SITEKEY - your hcaptcha site key - HCAPTCHA_SECRET - your hcaptcha secret key +- RECAPTCHA_SITEKEY - your recaptcha site key +- RECAPTCHA_SECRET - your recaptcha secret key - CAPTCHA_COOKIE_SECRET - random string, a salt for captcha cookies - POW_COOKIE_SECRET - different random string, a salt for pow cookies - RAY_ID - string to identify the HAProxy node by @@ -55,7 +57,7 @@ Before installing the tool, ensure that HAProxy is built with Lua support and ve - Copy [haproxy.cfg](haproxy/haproxy.cfg) to /etc/haproxy - Edit the `lua-load` directive to be the absolute path to [register.lua](src/scripts/register.lua) - - Edit the paths of sha1.js and worker.js in the `http-request return` directive to the absolut path to the respective files in the haproxy/js folder + - Edit the paths of challenge.js and worker.js in the `http-request return` directive to the absolut path to the respective files in the haproxy/js folder - Copy [dataplaneapi.hcl](haproxy/dataplaneapi.hcl) to /etc/haproxy - Copy or link [scripts](src/scripts) to /etc/haproxy/scripts - Copy or link [libs](src/libs) to /etc/haproxy/libs (or a path where Lua looks for modules). diff --git a/docker-compose.yml b/docker-compose.yml index 45c6fee..84feedd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,29 +5,31 @@ services: # context: ./ # dockerfile: tor/Dockerfile haproxy: - network_mode: "host" + ports: + - 80:80 build: context: ./ dockerfile: haproxy/Dockerfile - ports: - - 80:80 #http - - 2000:2000 #port 2000 haproxy socket for external management volumes: - ./haproxy/haproxy.cfg:/etc/haproxy/haproxy.cfg - ./haproxy/ddos.map:/etc/haproxy/ddos.map - ./haproxy/hosts.map:/etc/haproxy/hosts.map - ./haproxy/backends.map:/etc/haproxy/backends.map - ./haproxy/blocked.map:/etc/haproxy/blocked.map + - ./haproxy/whitelist.map:/etc/haproxy/whitelist.map + - ./haproxy/maintenance.map:/etc/haproxy/maintenance.map - ./haproxy/dataplaneapi.hcl:/etc/haproxy/dataplaneapi.hcl - ./haproxy/trace.txt:/etc/haproxy/trace.txt - ./src/scripts/:/etc/haproxy/scripts/ - ./src/libs/:/etc/haproxy/libs/ - ./haproxy/js/:/var/www/js/ + - ./haproxy/html/maintenance.html:/var/www/html/maintenance.html environment: - - HCAPTCHA_SECRET= - - HCAPTCHA_SITEKEY= + - RECAPTCHA_SECRET=6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe + - RECAPTCHA_SITEKEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI - CAPTCHA_COOKIE_SECRET=changeme - POW_COOKIE_SECRET=changeme + - HMAC_COOKIE_SECRET=changeme - RAY_ID=docker - BUCKET_DURATION=43200 - BACKEND_NAME=servers diff --git a/haproxy/backends.map b/haproxy/backends.map index e69de29..4479d20 100644 --- a/haproxy/backends.map +++ b/haproxy/backends.map @@ -0,0 +1 @@ +localhost websrv1 diff --git a/haproxy/ddos.map b/haproxy/ddos.map index e69de29..49766ca 100644 --- a/haproxy/ddos.map +++ b/haproxy/ddos.map @@ -0,0 +1,2 @@ +localhost 1 +localhost/captcha 2 diff --git a/haproxy/haproxy.cfg b/haproxy/haproxy.cfg index 992a791..e1f928b 100644 --- a/haproxy/haproxy.cfg +++ b/haproxy/haproxy.cfg @@ -7,6 +7,7 @@ global group haproxy daemon maxconn 10000 + httpclient.ssl.verify none #for haproxy panel stats socket 127.0.0.1:1999 level operator @@ -94,8 +95,8 @@ frontend www-http-https acl is_kikeflare hdr(host) -i kikeflare.com www.kikeflare.com # drop requests with invalid host header - acl is_existing_vhost hdr(host),lower,map_str(/etc/haproxy/hosts.map) -m found - http-request silent-drop unless is_existing_vhost + #acl is_existing_vhost hdr(host),lower,map_str(/etc/haproxy/hosts.map) -m found + #http-request silent-drop unless is_existing_vhost # acl for blocked IPs/subnets acl blocked_ip_or_subnet src,map_ip(/etc/haproxy/blocked.map) -m found @@ -112,10 +113,10 @@ frontend www-http-https acl ddos_mode_enabled base,map(/etc/haproxy/ddos.map) -m bool # serve challenge page scripts directly from haproxy - acl is_sha1_js path /js/sha1.js + acl is_challenge_js path /js/challenge.js acl is_worker_js path /js/worker.js acl is_footerlogo_png path /img/footerlogo.png - http-request return file /var/www/js/sha1.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_sha1_js + http-request return file /var/www/js/challenge.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_challenge_js http-request return file /var/www/js/worker.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_worker_js http-request return file /var/www/img/footerlogo.png status 200 content-type "image/png" hdr "cache-control" "public, max-age=300" if is_footerlogo_png @@ -236,3 +237,7 @@ backend maxconn-20-backend backend hcaptcha mode http server hcaptcha hcaptcha.com:443 + +backend recaptcha + mode http + server recaptcha www.google.com:443 diff --git a/haproxy/js/challenge.js b/haproxy/js/challenge.js new file mode 100644 index 0000000..4ebe130 --- /dev/null +++ b/haproxy/js/challenge.js @@ -0,0 +1,53 @@ +function finishPow(combined, answer) { + const submitButton = document.querySelector('input[type=submit]') + if (submitButton) { + //button is shown only if captcha is enabled + submitButton.disabled = false; + submitButton.value = 'Submit'; + } else { + window.location=location.search.slice(1)+location.hash || "/"; + } +} + +const combined = document.querySelector('[data-pow]').dataset.pow; +const [_userkey, challenge, _signature] = combined.split("#"); +const start = Date.now(); +if (window.Worker && crypto.subtle) { + const threads = Math.min(4,Math.ceil(window.navigator.hardwareConcurrency/2)); + let finished = false; + const messageHandler = (e) => { + if (finished) { return; } + finished = true; + workers.forEach(w => w.terminate()); + const [workerId, answer] = e.data; + console.log('Worker', workerId, 'returned answer', answer, 'in', Date.now()-start+'ms'); + document.cookie='z_ddos_pow='+combined+'#'+answer+';expires=Thu, 31-Dec-37 23:55:55 GMT; path=/; SameSite=Strict; '+(location.protocol==='https:'?'Secure=true; ':''); + const dummyTime = 5000 - (Date.now()-start); + window.setTimeout(() => finishPow(combined, answer), dummyTime); + } + const workers = []; + for (let i = 0; i < threads; i++) { + const shaWorker = new Worker('/js/worker.js'); + shaWorker.onmessage = messageHandler; + workers.push(shaWorker); + } + workers.forEach((w, i) => w.postMessage([challenge, i, threads])); +} else { + console.warn('No webworker or crypto.subtle support, using legacy method in main/UI thread!'); + function sha256(ascii){function rightRotate(value,amount){return(value>>>amount)|(value<<(32-amount))};var mathPow=Math.pow;var maxWord=mathPow(2,32);var lengthProperty='length';var i,j;var result='';var words=[];var asciiBitLength=ascii[lengthProperty]*8;var hash=sha256.h=sha256.h||[];var k=sha256.k=sha256.k||[];var primeCounter=k[lengthProperty];var isComposite={};for(var candidate=2;primeCounter<64;candidate+=1){if(!isComposite[candidate]){for(i=0;i<313;i+=candidate){isComposite[i]=candidate}hash[primeCounter]=(mathPow(candidate,.5)*maxWord)|0;k[primeCounter++]=(mathPow(candidate,1/3)*maxWord)|0}}ascii+='\x80';while(ascii[lengthProperty]%64-56){ascii+='\x00';}for(i=0;i>8){return;}words[i>>2]|=j<<((3-i)%4)*8}words[words[lengthProperty]]=((asciiBitLength/maxWord)|0);words[words[lengthProperty]]=(asciiBitLength);for(j=0;j>>3))+w[i-7]+(rightRotate(w2,17)^rightRotate(w2,19)^(w2>>>10)))|0);var temp2=(rightRotate(a,2)^rightRotate(a,13)^rightRotate(a,22))+((a&hash[1])^(a&hash[2])^(hash[1]&hash[2]));hash=[(temp1+temp2)|0].concat(hash);hash[4]=(hash[4]+temp1)|0}for(i=0;i<8;i+=1){hash[i]=(hash[i]+oldHash[i])|0}}for(i=0;i<8;i+=1){for(j=3;j+1;j-=1){var b=(hash[i]>>(j*8))&255;result+=((b<16)?0:'')+b.toString(16)}}return result} + let challengeIndex = parseInt(challenge[0], 16); + let i = 0 + , result; + while(true) { + result = sha256(challenge+i); + if(result[challengeIndex] === 0x00 + && result[challengeIndex+1] === 0x41){ + console.log('Worker thread found solution:', i); + postMessage([id, i]); + break; + } + i++; + } + const dummyTime = 5000 - (Date.now()-start); + window.setTimeout(() => finishPow(combined, result), dummyTime); +} diff --git a/haproxy/js/worker.js b/haproxy/js/worker.js index 89a7f14..084368f 100644 --- a/haproxy/js/worker.js +++ b/haproxy/js/worker.js @@ -5,19 +5,14 @@ async function hash(data, method) { } onmessage = async function(e) { - const [challenge, difficulty, id, threads] = e.data; - console.log('Worker thread', id,'got challenge', challenge, 'with difficulty', difficulty); + const [challenge, id, threads] = e.data; + console.log('Worker thread', id,'got challenge', challenge); let i = id; let challengeIndex = parseInt(challenge[0], 16); while(true) { - let result = await hash(challenge+i, 'sha-1'); - let middle = true; - for(let imiddle = 1; imiddle <= difficulty; imiddle++) { - middle = (middle && (result[challengeIndex+imiddle] === 0x00)); - } - if(result[challengeIndex] === 0xb0 - && middle === true - && result[challengeIndex+difficulty+1] === 0x0b){ + let result = await hash(challenge+i, 'sha-256'); + if(result[challengeIndex] === 0x00 + && result[challengeIndex+1] === 0x41){ console.log('Worker thread found solution:', i); postMessage([id, i]); break; diff --git a/src/libs/randbytes.lua b/src/libs/randbytes.lua new file mode 100644 index 0000000..af00355 --- /dev/null +++ b/src/libs/randbytes.lua @@ -0,0 +1,105 @@ +-- randbytes.lua +-- Colin 'Oka' Hall-Coates +-- MIT, 2015 +-- https://github.com/okabsd/randbytes +local defaults = setmetatable ({ + bytes = 4, + mask = 256, + file = 'urandom', + filetable = {'urandom', 'random'} +}, { __newindex = function () return false end }) + +local files = { + urandom = false, + random = false +} + +local utils = {} + +function utils:gettable (...) + local t, r = {...}, defaults.filetable + if #t > 0 then r = t end + return r +end + +function utils:open (...) + for _, f in next, self:gettable (...) do + for k, _ in next, files do + if k == f then + files[f] = assert (io.open ('/dev/'..f, 'rb')) + end + end + end +end + +function utils:close (...) + for _, f in next, self:gettable (...) do + for k, _ in next, files do + if files[f] and k == f then + files[f] = not assert (files[f]:close ()) + end + end + end +end + +function utils:reader (f, b) + if f then + return f:read (b or defaults.bytes) + end +end + +local randbytes = { + generate = function (f, ...) + if f then + local n, m = 0, select (2, ...) or defaults.mask + local s = utils:reader (f, select (1, ...)) + + for i = 1, s:len () do + n = m * n + s:byte (i) + end + + return n + end + end +} + +function randbytes:open (...) + utils:open (...) + return self +end + +function randbytes:close (...) + utils:close (...) + return self +end + +function randbytes:uread (...) + return utils:reader (files.urandom, ...) +end + +function randbytes:read (...) + return utils:reader (files.random, ...) +end + +function randbytes:urandom (...) + return self.generate (files.urandom, ...) +end + +function randbytes:random (...) + return self.generate (files.random, ...) +end + +function randbytes:setdefault (k, v) + defaults[k] = v or defaults[k] + return defaults[k] +end + +utils:open () + +return setmetatable (randbytes, { + __call = function (t, ...) + return utils:reader (files[defaults.file], ...) + end, + __metatable = false, + __newindex = function () return false end +}) diff --git a/src/libs/sha.lua b/src/libs/sha.lua index bbd2867..201f52e 100644 --- a/src/libs/sha.lua +++ b/src/libs/sha.lua @@ -1,17 +1,19 @@ -------------------------------------------------------------------------------------------------------------------------- -- sha2.lua -------------------------------------------------------------------------------------------------------------------------- --- VERSION: 9 (2020-05-10) +-- VERSION: 12 (2022-02-23) -- AUTHOR: Egor Skriptunoff -- LICENSE: MIT (the same license as Lua itself) --- +-- URL: https://github.com/Egor-Skriptunoff/pure_lua_SHA -- -- DESCRIPTION: -- This module contains functions to calculate SHA digest: -- MD5, SHA-1, -- SHA-224, SHA-256, SHA-512/224, SHA-512/256, SHA-384, SHA-512, -- SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256, --- HMAC +-- HMAC, +-- BLAKE2b, BLAKE2s, BLAKE2bp, BLAKE2sp, BLAKE2Xb, BLAKE2Xs, +-- BLAKE3, BLAKE3_KDF -- Written in pure Lua. -- Compatible with: -- Lua 5.1, Lua 5.2, Lua 5.3, Lua 5.4, Fengari, LuaJIT 2.0/2.1 (any CPU endianness). @@ -39,8 +41,11 @@ -- CHANGELOG: -- version date description -- ------- ---------- ----------- +-- 12 2022-02-23 Now works in Luau (but NOT optimized for speed) +-- 11 2022-01-09 BLAKE3 added +-- 10 2022-01-02 BLAKE2 functions added -- 9 2020-05-10 Now works in OpenWrt's Lua (dialect of Lua 5.1 with "double" + "invisible int32") --- 8 2019-09-03 SHA3 functions added +-- 8 2019-09-03 SHA-3 functions added -- 7 2019-03-17 Added functions to convert to/from base64 -- 6 2018-11-12 HMAC added -- 5 2018-11-10 SHA-1 added @@ -50,10 +55,11 @@ -- 1 2018-10-06 First release (only SHA-2 functions) ----------------------------------------------------------------------------- + local print_debug_messages = false -- set to true to view some messages about your system's abilities and implementation branch chosen for your system -local unpack, table_concat, byte, char, string_rep, sub, gsub, gmatch, string_format, floor, ceil, math_min, math_max, tonumber, type = - table.unpack or unpack, table.concat, string.byte, string.char, string.rep, string.sub, string.gsub, string.gmatch, string.format, math.floor, math.ceil, math.min, math.max, tonumber, type +local unpack, table_concat, byte, char, string_rep, sub, gsub, gmatch, string_format, floor, ceil, math_min, math_max, tonumber, type, math_huge = + table.unpack or unpack, table.concat, string.byte, string.char, string.rep, string.sub, string.gsub, string.gmatch, string.format, math.floor, math.ceil, math.min, math.max, tonumber, type, math.huge -------------------------------------------------------------------------------- @@ -111,7 +117,7 @@ assert(Lua_has_int64 or Lua_has_int32 or not Lua_has_integers, "Lua integers mus -- Using "int128" instead of "int64" is not OK: "int128" would require different branch of implementation for optimized SHA512. -- Check for LuaJIT and 32-bit bitwise libraries -local is_LuaJIT = ({false, [1] = true})[1] and (type(jit) ~= "table" or jit.version_num >= 20000) -- LuaJIT 1.x.x is treated as vanilla Lua 5.1 +local is_LuaJIT = ({false, [1] = true})[1] and _VERSION ~= "Luau" and (type(jit) ~= "table" or jit.version_num >= 20000) -- LuaJIT 1.x.x and Luau are treated as vanilla Lua 5.1/5.2 local is_LuaJIT_21 -- LuaJIT 2.1+ local LuaJIT_arch local ffi -- LuaJIT FFI library (as a table) @@ -165,7 +171,7 @@ if is_LuaJIT and ffi then method = "Using 'ffi' library of LuaJIT" branch = "FFI" elseif is_LuaJIT then - method = "Using special code for FFI-less LuaJIT" + method = "Using special code for sandboxed LuaJIT (no FFI)" branch = "LJ" elseif Lua_has_int64 then method = "Using native int64 bitwise operators" @@ -224,7 +230,6 @@ elseif branch == "EMUL" then end function SHR(x, n) - -- return (x % 2^32 - x % 2^n) / 2^n x = x % 2^32 / 2^n return x - x % 1 end @@ -316,8 +321,8 @@ HEX = HEX return string_format("%08x", (x + 2^31) % 2^32 - 2^31) end -local function XOR32A5(x) - return XOR(x, 0xA5A5A5A5) % 4294967296 +local function XORA5(x, y) + return XOR(x, y or 0xA5A5A5A5) % 4294967296 end local function create_array_of_lanes() @@ -330,17 +335,36 @@ end -------------------------------------------------------------------------------- -- Inner loop functions -local sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed +local sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed, blake2s_feed_64, blake2b_feed_128, blake3_feed_64 --- Arrays of SHA2 "magic numbers" (in "INT64" and "FFI" branches "*_lo" arrays contain 64-bit values) +-- Arrays of SHA-2 "magic numbers" (in "INT64" and "FFI" branches "*_lo" arrays contain 64-bit values) local sha2_K_lo, sha2_K_hi, sha2_H_lo, sha2_H_hi, sha3_RC_lo, sha3_RC_hi = {}, {}, {}, {}, {}, {} local sha2_H_ext256 = {[224] = {}, [256] = sha2_H_hi} local sha2_H_ext512_lo, sha2_H_ext512_hi = {[384] = {}, [512] = sha2_H_lo}, {[384] = {}, [512] = sha2_H_hi} local md5_K, md5_sha1_H = {}, {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0} local 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} -local HEX64, XOR64A5, lanes_index_base -- defined only for branches that internally use 64-bit integers: "INT64" and "FFI" +local HEX64, lanes_index_base -- defined only for branches that internally use 64-bit integers: "INT64" and "FFI" local common_W = {} -- temporary table shared between all calculations (to avoid creating new temporary table every time) +local common_W_blake2b, common_W_blake2s, v_for_blake2s_feed_64 = common_W, common_W, {} local K_lo_modulo, hi_factor, hi_factor_keccak = 4294967296, 0, 0 +local sigma = { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, + { 15, 11, 5, 9, 10, 16, 14, 7, 2, 13, 1, 3, 12, 8, 6, 4 }, + { 12, 9, 13, 1, 6, 3, 16, 14, 11, 15, 4, 7, 8, 2, 10, 5 }, + { 8, 10, 4, 2, 14, 13, 12, 15, 3, 7, 6, 11, 5, 1, 16, 9 }, + { 10, 1, 6, 8, 3, 5, 11, 16, 15, 2, 12, 13, 7, 9, 4, 14 }, + { 3, 13, 7, 11, 1, 12, 9, 4, 5, 14, 8, 6, 16, 15, 2, 10 }, + { 13, 6, 2, 16, 15, 14, 5, 11, 1, 8, 7, 4, 10, 3, 9, 12 }, + { 14, 12, 8, 15, 13, 2, 4, 10, 6, 1, 16, 5, 9, 7, 3, 11 }, + { 7, 16, 15, 10, 12, 4, 1, 9, 13, 3, 14, 8, 2, 5, 11, 6 }, + { 11, 3, 9, 5, 8, 7, 2, 6, 16, 12, 10, 15, 4, 13, 14, 1 }, +}; sigma[11], sigma[12] = sigma[1], sigma[2] +local perm_blake3 = { + 1, 3, 4, 11, 13, 10, 12, 6, + 1, 3, 4, 11, 13, 10, + 2, 7, 5, 8, 14, 15, 16, 9, + 2, 7, 5, 8, 14, 15, +} local function build_keccak_format(elem) local keccak_format = {} @@ -353,11 +377,17 @@ end if branch == "FFI" then + local common_W_FFI_int32 = ffi.new("int32_t[?]", 80) -- 64 is enough for SHA256, but 80 is needed for SHA-1 + common_W_blake2s = common_W_FFI_int32 + v_for_blake2s_feed_64 = ffi.new("int32_t[?]", 16) + perm_blake3 = ffi.new("uint8_t[?]", #perm_blake3 + 1, 0, unpack(perm_blake3)) + for j = 1, 10 do + sigma[j] = ffi.new("uint8_t[?]", #sigma[j] + 1, 0, unpack(sigma[j])) + end; sigma[11], sigma[12] = sigma[1], sigma[2] + -- SHA256 implementation for "LuaJIT with FFI" branch - local common_W_FFI_int32 = ffi.new"int32_t[80]" -- 64 is enough for SHA256, but 80 is needed for SHA-1 - function sha256_feed_64(H, str, offs, size) -- offs >= 0, size >= 0, size is multiple of 64 local W, K = common_W_FFI_int32, sha2_K_hi @@ -403,11 +433,12 @@ if branch == "FFI" then end end - local common_W_FFI_int64 = ffi.new"int64_t[80]" + + local common_W_FFI_int64 = ffi.new("int64_t[?]", 80) + common_W_blake2b = common_W_FFI_int64 local int64 = ffi.typeof"int64_t" local int32 = ffi.typeof"int32_t" local uint32 = ffi.typeof"uint32_t" - hi_factor = int64(2^32) if is_LuaJIT_21 then -- LuaJIT 2.1 supports bitwise 64-bit operations @@ -417,15 +448,83 @@ if branch == "FFI" then HEX64 = HEX - -- SHA3 implementation for "LuaJIT 2.1 + FFI" branch + -- BLAKE2b implementation for "LuaJIT 2.1 + FFI" branch - local lanes_arr64 = ffi.typeof"int64_t[30]" -- 25 + 5 for temporary usage + do + local v = ffi.new("int64_t[?]", 16) + local W = common_W_blake2b + + local function G(a, b, c, d, k1, k2) + local va, vb, vc, vd = v[a], v[b], v[c], v[d] + va = W[k1] + (va + vb) + vd = ROR64(XOR64(vd, va), 32) + vc = vc + vd + vb = ROR64(XOR64(vb, vc), 24) + va = W[k2] + (va + vb) + vd = ROR64(XOR64(vd, va), 16) + vc = vc + vd + vb = ROL64(XOR64(vb, vc), 1) + v[a], v[b], v[c], v[d] = va, vb, vc, vd + end + + function blake2b_feed_128(H, _, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 128 + 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] + for pos = offs, offs + size - 1, 128 do + if str then + for j = 1, 16 do + pos = pos + 8 + local a, b, c, d, e, f, g, h = byte(str, pos - 7, pos) + W[j] = XOR64(OR(SHL(h, 24), SHL(g, 16), SHL(f, 8), e) * int64(2^32), uint32(int32(OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a)))) + end + end + v[0x0], v[0x1], v[0x2], v[0x3], v[0x4], v[0x5], v[0x6], v[0x7] = h1, h2, h3, h4, h5, h6, h7, h8 + v[0x8], v[0x9], v[0xA], v[0xB], v[0xD], v[0xE], v[0xF] = sha2_H_lo[1], sha2_H_lo[2], sha2_H_lo[3], sha2_H_lo[4], sha2_H_lo[6], sha2_H_lo[7], sha2_H_lo[8] + bytes_compressed = bytes_compressed + (last_block_size or 128) + v[0xC] = XOR64(sha2_H_lo[5], bytes_compressed) -- t0 = low_8_bytes(bytes_compressed) + -- t1 = high_8_bytes(bytes_compressed) = 0, message length is always below 2^53 bytes + if last_block_size then -- flag f0 + v[0xE] = NOT64(v[0xE]) + end + if is_last_node then -- flag f1 + v[0xF] = NOT64(v[0xF]) + end + for j = 1, 12 do + local row = sigma[j] + G(0, 4, 8, 12, row[ 1], row[ 2]) + G(1, 5, 9, 13, row[ 3], row[ 4]) + G(2, 6, 10, 14, row[ 5], row[ 6]) + G(3, 7, 11, 15, row[ 7], row[ 8]) + G(0, 5, 10, 15, row[ 9], row[10]) + G(1, 6, 11, 12, row[11], row[12]) + G(2, 7, 8, 13, row[13], row[14]) + G(3, 4, 9, 14, row[15], row[16]) + end + h1 = XOR64(h1, v[0x0], v[0x8]) + h2 = XOR64(h2, v[0x1], v[0x9]) + h3 = XOR64(h3, v[0x2], v[0xA]) + h4 = XOR64(h4, v[0x3], v[0xB]) + h5 = XOR64(h5, v[0x4], v[0xC]) + h6 = XOR64(h6, v[0x5], v[0xD]) + h7 = XOR64(h7, v[0x6], v[0xE]) + h8 = XOR64(h8, v[0x7], v[0xF]) + end + H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 + return bytes_compressed + end + + end + + + -- SHA-3 implementation for "LuaJIT 2.1 + FFI" branch + + local arr64_t = ffi.typeof"int64_t[?]" -- lanes array is indexed from 0 lanes_index_base = 0 hi_factor_keccak = int64(2^32) function create_array_of_lanes() - return lanes_arr64() + return arr64_t(30) -- 25 + 5 for temporary usage end function keccak_feed(lanes, _, str, offs, size, block_size_in_bytes) @@ -467,14 +566,15 @@ if branch == "FFI" then end - -- SHA512 implementation for "LuaJIT 2.1 + FFI" branch - local A5_long = 0xA5A5A5A5 * int64(2^32 + 1) -- It's impossible to use constant 0xA5A5A5A5A5A5A5A5LL because it will raise syntax error on other Lua versions - function XOR64A5(long) - return XOR64(long, A5_long) + function XORA5(long, long2) + return XOR64(long, long2 or A5_long) end + + -- SHA512 implementation for "LuaJIT 2.1 + FFI" branch + function sha512_feed_128(H, _, str, offs, size) -- offs >= 0, size >= 0, size is multiple of 128 local W, K = common_W_FFI_int64, sha2_K_lo @@ -528,18 +628,8 @@ if branch == "FFI" then else -- LuaJIT 2.0 doesn't support 64-bit bitwise operations - - -- SHA512 implementation for "LuaJIT 2.0 + FFI" branch - - local union64 = ffi.typeof"union{int64_t i64; struct{int32_t lo, hi;} i32;}" - do -- make sure the struct is endianness-compatible - local u = union64(1) - if u.i32.lo < u.i32.hi then - union64 = ffi.typeof"union{int64_t i64; struct{int32_t hi, lo;} i32;}" - end - end - local unions64 = ffi.typeof("$[?]", union64) - local U = unions64(3) -- this array of unions is used for fast splitting int64 into int32_high and int32_low + local U = ffi.new("union{int64_t i64; struct{int32_t "..(ffi.abi("le") and "lo, hi" or "hi, lo")..";} i32;}[3]") + -- this array of unions is used for fast splitting int64 into int32_high and int32_low -- "xorrific" 64-bit functions :-) -- int64 input is splitted into two int32 parts, some bitwise 32-bit operations are performed, finally the result is converted to int64 @@ -549,8 +639,8 @@ if branch == "FFI" then -- return XOR64(ROR64(a, 1), ROR64(a, 8), SHR64(a, 7)) U[0].i64 = a local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi - local t_lo = XOR(OR(SHR(a_lo, 1), SHL(a_hi, 31)), OR(SHR(a_lo, 8), SHL(a_hi, 24)), OR(SHR(a_lo, 7), SHL(a_hi, 25))) - local t_hi = XOR(OR(SHR(a_hi, 1), SHL(a_lo, 31)), OR(SHR(a_hi, 8), SHL(a_lo, 24)), SHR(a_hi, 7)) + local t_lo = XOR(SHR(a_lo, 1), SHL(a_hi, 31), SHR(a_lo, 8), SHL(a_hi, 24), SHR(a_lo, 7), SHL(a_hi, 25)) + local t_hi = XOR(SHR(a_hi, 1), SHL(a_lo, 31), SHR(a_hi, 8), SHL(a_lo, 24), SHR(a_hi, 7)) return t_hi * int64(2^32) + uint32(int32(t_lo)) end @@ -558,8 +648,8 @@ if branch == "FFI" then -- return XOR64(ROR64(b, 19), ROL64(b, 3), SHR64(b, 6)) U[0].i64 = b local b_lo, b_hi = U[0].i32.lo, U[0].i32.hi - local u_lo = XOR(OR(SHR(b_lo, 19), SHL(b_hi, 13)), OR(SHL(b_lo, 3), SHR(b_hi, 29)), OR(SHR(b_lo, 6), SHL(b_hi, 26))) - local u_hi = XOR(OR(SHR(b_hi, 19), SHL(b_lo, 13)), OR(SHL(b_hi, 3), SHR(b_lo, 29)), SHR(b_hi, 6)) + local u_lo = XOR(SHR(b_lo, 19), SHL(b_hi, 13), SHL(b_lo, 3), SHR(b_hi, 29), SHR(b_lo, 6), SHL(b_hi, 26)) + local u_hi = XOR(SHR(b_hi, 19), SHL(b_lo, 13), SHL(b_hi, 3), SHR(b_lo, 29), SHR(b_hi, 6)) return u_hi * int64(2^32) + uint32(int32(u_lo)) end @@ -567,8 +657,8 @@ if branch == "FFI" then -- return XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) U[0].i64 = e local e_lo, e_hi = U[0].i32.lo, U[0].i32.hi - local u_lo = XOR(OR(SHR(e_lo, 14), SHL(e_hi, 18)), OR(SHR(e_lo, 18), SHL(e_hi, 14)), OR(SHL(e_lo, 23), SHR(e_hi, 9))) - local u_hi = XOR(OR(SHR(e_hi, 14), SHL(e_lo, 18)), OR(SHR(e_hi, 18), SHL(e_lo, 14)), OR(SHL(e_hi, 23), SHR(e_lo, 9))) + local u_lo = XOR(SHR(e_lo, 14), SHL(e_hi, 18), SHR(e_lo, 18), SHL(e_hi, 14), SHL(e_lo, 23), SHR(e_hi, 9)) + local u_hi = XOR(SHR(e_hi, 14), SHL(e_lo, 18), SHR(e_hi, 18), SHL(e_lo, 14), SHL(e_hi, 23), SHR(e_lo, 9)) return u_hi * int64(2^32) + uint32(int32(u_lo)) end @@ -576,8 +666,8 @@ if branch == "FFI" then -- return XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) U[0].i64 = a local b_lo, b_hi = U[0].i32.lo, U[0].i32.hi - local u_lo = XOR(OR(SHR(b_lo, 28), SHL(b_hi, 4)), OR(SHL(b_lo, 30), SHR(b_hi, 2)), OR(SHL(b_lo, 25), SHR(b_hi, 7))) - local u_hi = XOR(OR(SHR(b_hi, 28), SHL(b_lo, 4)), OR(SHL(b_hi, 30), SHR(b_lo, 2)), OR(SHL(b_hi, 25), SHR(b_lo, 7))) + local u_lo = XOR(SHR(b_lo, 28), SHL(b_hi, 4), SHL(b_lo, 30), SHR(b_hi, 2), SHL(b_lo, 25), SHR(b_hi, 7)) + local u_hi = XOR(SHR(b_hi, 28), SHL(b_lo, 4), SHL(b_hi, 30), SHR(b_lo, 2), SHL(b_hi, 25), SHR(b_lo, 7)) return u_hi * int64(2^32) + uint32(int32(u_lo)) end @@ -607,12 +697,73 @@ if branch == "FFI" then return result_hi * int64(2^32) + uint32(int32(result_lo)) end - function XOR64A5(long) - -- return XOR64(long, 0xA5A5A5A5A5A5A5A5) + local function XORROR64_7(a, b, m) + -- return ROR64(XOR64(a, b), m), m = 1..31 + U[0].i64 = a + U[1].i64 = b + local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi + local b_lo, b_hi = U[1].i32.lo, U[1].i32.hi + local c_lo, c_hi = XOR(a_lo, b_lo), XOR(a_hi, b_hi) + local t_lo = XOR(SHR(c_lo, m), SHL(c_hi, -m)) + local t_hi = XOR(SHR(c_hi, m), SHL(c_lo, -m)) + return t_hi * int64(2^32) + uint32(int32(t_lo)) + end + + local function XORROR64_8(a, b) + -- return ROL64(XOR64(a, b), 1) + U[0].i64 = a + U[1].i64 = b + local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi + local b_lo, b_hi = U[1].i32.lo, U[1].i32.hi + local c_lo, c_hi = XOR(a_lo, b_lo), XOR(a_hi, b_hi) + local t_lo = XOR(SHL(c_lo, 1), SHR(c_hi, 31)) + local t_hi = XOR(SHL(c_hi, 1), SHR(c_lo, 31)) + return t_hi * int64(2^32) + uint32(int32(t_lo)) + end + + local function XORROR64_9(a, b) + -- return ROR64(XOR64(a, b), 32) + U[0].i64 = a + U[1].i64 = b + local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi + local b_lo, b_hi = U[1].i32.lo, U[1].i32.hi + local t_hi, t_lo = XOR(a_lo, b_lo), XOR(a_hi, b_hi) + return t_hi * int64(2^32) + uint32(int32(t_lo)) + end + + local function XOR64(a, b) + -- return XOR64(a, b) + U[0].i64 = a + U[1].i64 = b + local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi + local b_lo, b_hi = U[1].i32.lo, U[1].i32.hi + local t_lo, t_hi = XOR(a_lo, b_lo), XOR(a_hi, b_hi) + return t_hi * int64(2^32) + uint32(int32(t_lo)) + end + + local function XORROR64_11(a, b, c) + -- return XOR64(a, b, c) + U[0].i64 = a + U[1].i64 = b + U[2].i64 = c + local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi + local b_lo, b_hi = U[1].i32.lo, U[1].i32.hi + local c_lo, c_hi = U[2].i32.lo, U[2].i32.hi + local t_lo, t_hi = XOR(a_lo, b_lo, c_lo), XOR(a_hi, b_hi, c_hi) + return t_hi * int64(2^32) + uint32(int32(t_lo)) + end + + function XORA5(long, long2) + -- return XOR64(long, long2 or 0xA5A5A5A5A5A5A5A5) U[0].i64 = long local lo32, hi32 = U[0].i32.lo, U[0].i32.hi - lo32 = XOR(lo32, 0xA5A5A5A5) - hi32 = XOR(hi32, 0xA5A5A5A5) + local long2_lo, long2_hi = 0xA5A5A5A5, 0xA5A5A5A5 + if long2 then + U[1].i64 = long2 + long2_lo, long2_hi = U[1].i32.lo, U[1].i32.hi + end + lo32 = XOR(lo32, long2_lo) + hi32 = XOR(hi32, long2_hi) return hi32 * int64(2^32) + uint32(int32(lo32)) end @@ -621,6 +772,9 @@ if branch == "FFI" then return HEX(U[0].i32.hi)..HEX(U[0].i32.lo) end + + -- SHA512 implementation for "LuaJIT 2.0 + FFI" branch + function sha512_feed_128(H, _, str, offs, size) -- offs >= 0, size >= 0, size is multiple of 128 local W, K = common_W_FFI_int64, sha2_K_lo @@ -671,6 +825,74 @@ if branch == "FFI" then end end + + -- BLAKE2b implementation for "LuaJIT 2.0 + FFI" branch + + do + local v = ffi.new("int64_t[?]", 16) + local W = common_W_blake2b + + local function G(a, b, c, d, k1, k2) + local va, vb, vc, vd = v[a], v[b], v[c], v[d] + va = W[k1] + (va + vb) + vd = XORROR64_9(vd, va) + vc = vc + vd + vb = XORROR64_7(vb, vc, 24) + va = W[k2] + (va + vb) + vd = XORROR64_7(vd, va, 16) + vc = vc + vd + vb = XORROR64_8(vb, vc) + v[a], v[b], v[c], v[d] = va, vb, vc, vd + end + + function blake2b_feed_128(H, _, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 128 + 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] + for pos = offs, offs + size - 1, 128 do + if str then + for j = 1, 16 do + pos = pos + 8 + local a, b, c, d, e, f, g, h = byte(str, pos - 7, pos) + W[j] = XOR64(OR(SHL(h, 24), SHL(g, 16), SHL(f, 8), e) * int64(2^32), uint32(int32(OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a)))) + end + end + v[0x0], v[0x1], v[0x2], v[0x3], v[0x4], v[0x5], v[0x6], v[0x7] = h1, h2, h3, h4, h5, h6, h7, h8 + v[0x8], v[0x9], v[0xA], v[0xB], v[0xD], v[0xE], v[0xF] = sha2_H_lo[1], sha2_H_lo[2], sha2_H_lo[3], sha2_H_lo[4], sha2_H_lo[6], sha2_H_lo[7], sha2_H_lo[8] + bytes_compressed = bytes_compressed + (last_block_size or 128) + v[0xC] = XOR64(sha2_H_lo[5], bytes_compressed) -- t0 = low_8_bytes(bytes_compressed) + -- t1 = high_8_bytes(bytes_compressed) = 0, message length is always below 2^53 bytes + if last_block_size then -- flag f0 + v[0xE] = -1 - v[0xE] + end + if is_last_node then -- flag f1 + v[0xF] = -1 - v[0xF] + end + for j = 1, 12 do + local row = sigma[j] + G(0, 4, 8, 12, row[ 1], row[ 2]) + G(1, 5, 9, 13, row[ 3], row[ 4]) + G(2, 6, 10, 14, row[ 5], row[ 6]) + G(3, 7, 11, 15, row[ 7], row[ 8]) + G(0, 5, 10, 15, row[ 9], row[10]) + G(1, 6, 11, 12, row[11], row[12]) + G(2, 7, 8, 13, row[13], row[14]) + G(3, 4, 9, 14, row[15], row[16]) + end + h1 = XORROR64_11(h1, v[0x0], v[0x8]) + h2 = XORROR64_11(h2, v[0x1], v[0x9]) + h3 = XORROR64_11(h3, v[0x2], v[0xA]) + h4 = XORROR64_11(h4, v[0x3], v[0xB]) + h5 = XORROR64_11(h5, v[0x4], v[0xC]) + h6 = XORROR64_11(h6, v[0x5], v[0xD]) + h7 = XORROR64_11(h7, v[0x6], v[0xE]) + h8 = XORROR64_11(h8, v[0x7], v[0xF]) + end + H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 + return bytes_compressed + end + + end + end @@ -768,19 +990,20 @@ if branch == "FFI" then end --- SHA3 implementation for "LuaJIT 2.0 + FFI" and "LuaJIT without FFI" branches - if branch == "FFI" and not is_LuaJIT_21 or branch == "LJ" then if branch == "FFI" then - local lanes_arr32 = ffi.typeof"int32_t[31]" -- 25 + 5 + 1 (due to 1-based indexing) + local arr32_t = ffi.typeof"int32_t[?]" function create_array_of_lanes() - return lanes_arr32() + return arr32_t(31) -- 25 + 5 + 1 (due to 1-based indexing) end end + + -- SHA-3 implementation for "LuaJIT 2.0 + FFI" and "LuaJIT without FFI" branches + function keccak_feed(lanes_lo, lanes_hi, str, offs, size, block_size_in_bytes) -- offs >= 0, size >= 0, size is multiple of block_size_in_bytes, block_size_in_bytes is positive multiple of 8 local RC_lo, RC_hi = sha3_RC_lo, sha3_RC_hi @@ -1105,6 +1328,229 @@ if branch == "LJ" then end end + + -- BLAKE2b implementation for "LuaJIT without FFI" branch + + do + local v_lo, v_hi = {}, {} + + local function G(a, b, c, d, k1, k2) + local W = common_W + local va_lo, vb_lo, vc_lo, vd_lo = v_lo[a], v_lo[b], v_lo[c], v_lo[d] + local va_hi, vb_hi, vc_hi, vd_hi = v_hi[a], v_hi[b], v_hi[c], v_hi[d] + local z = W[2*k1-1] + (va_lo % 2^32 + vb_lo % 2^32) + va_lo = NORM(z) + va_hi = NORM(W[2*k1] + (va_hi + vb_hi + floor(z / 2^32))) + vd_lo, vd_hi = XOR(vd_hi, va_hi), XOR(vd_lo, va_lo) + z = vc_lo % 2^32 + vd_lo % 2^32 + vc_lo = NORM(z) + vc_hi = NORM(vc_hi + vd_hi + floor(z / 2^32)) + vb_lo, vb_hi = XOR(vb_lo, vc_lo), XOR(vb_hi, vc_hi) + vb_lo, vb_hi = XOR(SHR(vb_lo, 24), SHL(vb_hi, 8)), XOR(SHR(vb_hi, 24), SHL(vb_lo, 8)) + z = W[2*k2-1] + (va_lo % 2^32 + vb_lo % 2^32) + va_lo = NORM(z) + va_hi = NORM(W[2*k2] + (va_hi + vb_hi + floor(z / 2^32))) + vd_lo, vd_hi = XOR(vd_lo, va_lo), XOR(vd_hi, va_hi) + vd_lo, vd_hi = XOR(SHR(vd_lo, 16), SHL(vd_hi, 16)), XOR(SHR(vd_hi, 16), SHL(vd_lo, 16)) + z = vc_lo % 2^32 + vd_lo % 2^32 + vc_lo = NORM(z) + vc_hi = NORM(vc_hi + vd_hi + floor(z / 2^32)) + vb_lo, vb_hi = XOR(vb_lo, vc_lo), XOR(vb_hi, vc_hi) + vb_lo, vb_hi = XOR(SHL(vb_lo, 1), SHR(vb_hi, 31)), XOR(SHL(vb_hi, 1), SHR(vb_lo, 31)) + v_lo[a], v_lo[b], v_lo[c], v_lo[d] = va_lo, vb_lo, vc_lo, vd_lo + v_hi[a], v_hi[b], v_hi[c], v_hi[d] = va_hi, vb_hi, vc_hi, vd_hi + end + + function blake2b_feed_128(H_lo, H_hi, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 128 + local W = common_W + 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] + 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] + for pos = offs, offs + size - 1, 128 do + if str then + for j = 1, 32 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = d * 2^24 + OR(SHL(c, 16), SHL(b, 8), a) + end + end + v_lo[0x0], v_lo[0x1], v_lo[0x2], v_lo[0x3], v_lo[0x4], v_lo[0x5], v_lo[0x6], v_lo[0x7] = h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo + v_lo[0x8], v_lo[0x9], v_lo[0xA], v_lo[0xB], v_lo[0xC], v_lo[0xD], v_lo[0xE], v_lo[0xF] = sha2_H_lo[1], sha2_H_lo[2], sha2_H_lo[3], sha2_H_lo[4], sha2_H_lo[5], sha2_H_lo[6], sha2_H_lo[7], sha2_H_lo[8] + v_hi[0x0], v_hi[0x1], v_hi[0x2], v_hi[0x3], v_hi[0x4], v_hi[0x5], v_hi[0x6], v_hi[0x7] = h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi + v_hi[0x8], v_hi[0x9], v_hi[0xA], v_hi[0xB], v_hi[0xC], v_hi[0xD], v_hi[0xE], v_hi[0xF] = sha2_H_hi[1], sha2_H_hi[2], sha2_H_hi[3], sha2_H_hi[4], sha2_H_hi[5], sha2_H_hi[6], sha2_H_hi[7], sha2_H_hi[8] + bytes_compressed = bytes_compressed + (last_block_size or 128) + local t0_lo = bytes_compressed % 2^32 + local t0_hi = floor(bytes_compressed / 2^32) + v_lo[0xC] = XOR(v_lo[0xC], t0_lo) -- t0 = low_8_bytes(bytes_compressed) + v_hi[0xC] = XOR(v_hi[0xC], t0_hi) + -- t1 = high_8_bytes(bytes_compressed) = 0, message length is always below 2^53 bytes + if last_block_size then -- flag f0 + v_lo[0xE] = NOT(v_lo[0xE]) + v_hi[0xE] = NOT(v_hi[0xE]) + end + if is_last_node then -- flag f1 + v_lo[0xF] = NOT(v_lo[0xF]) + v_hi[0xF] = NOT(v_hi[0xF]) + end + for j = 1, 12 do + local row = sigma[j] + G(0, 4, 8, 12, row[ 1], row[ 2]) + G(1, 5, 9, 13, row[ 3], row[ 4]) + G(2, 6, 10, 14, row[ 5], row[ 6]) + G(3, 7, 11, 15, row[ 7], row[ 8]) + G(0, 5, 10, 15, row[ 9], row[10]) + G(1, 6, 11, 12, row[11], row[12]) + G(2, 7, 8, 13, row[13], row[14]) + G(3, 4, 9, 14, row[15], row[16]) + end + h1_lo = XOR(h1_lo, v_lo[0x0], v_lo[0x8]) + h2_lo = XOR(h2_lo, v_lo[0x1], v_lo[0x9]) + h3_lo = XOR(h3_lo, v_lo[0x2], v_lo[0xA]) + h4_lo = XOR(h4_lo, v_lo[0x3], v_lo[0xB]) + h5_lo = XOR(h5_lo, v_lo[0x4], v_lo[0xC]) + h6_lo = XOR(h6_lo, v_lo[0x5], v_lo[0xD]) + h7_lo = XOR(h7_lo, v_lo[0x6], v_lo[0xE]) + h8_lo = XOR(h8_lo, v_lo[0x7], v_lo[0xF]) + h1_hi = XOR(h1_hi, v_hi[0x0], v_hi[0x8]) + h2_hi = XOR(h2_hi, v_hi[0x1], v_hi[0x9]) + h3_hi = XOR(h3_hi, v_hi[0x2], v_hi[0xA]) + h4_hi = XOR(h4_hi, v_hi[0x3], v_hi[0xB]) + h5_hi = XOR(h5_hi, v_hi[0x4], v_hi[0xC]) + h6_hi = XOR(h6_hi, v_hi[0x5], v_hi[0xD]) + h7_hi = XOR(h7_hi, v_hi[0x6], v_hi[0xE]) + h8_hi = XOR(h8_hi, v_hi[0x7], v_hi[0xF]) + end + 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 % 2^32, h2_lo % 2^32, h3_lo % 2^32, h4_lo % 2^32, h5_lo % 2^32, h6_lo % 2^32, h7_lo % 2^32, h8_lo % 2^32 + 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 % 2^32, h2_hi % 2^32, h3_hi % 2^32, h4_hi % 2^32, h5_hi % 2^32, h6_hi % 2^32, h7_hi % 2^32, h8_hi % 2^32 + return bytes_compressed + end + + end +end + + +if branch == "FFI" or branch == "LJ" then + + + -- BLAKE2s and BLAKE3 implementations for "LuaJIT with FFI" and "LuaJIT without FFI" branches + + do + local W = common_W_blake2s + local v = v_for_blake2s_feed_64 + + local function G(a, b, c, d, k1, k2) + local va, vb, vc, vd = v[a], v[b], v[c], v[d] + va = NORM(W[k1] + (va + vb)) + vd = ROR(XOR(vd, va), 16) + vc = NORM(vc + vd) + vb = ROR(XOR(vb, vc), 12) + va = NORM(W[k2] + (va + vb)) + vd = ROR(XOR(vd, va), 8) + vc = NORM(vc + vd) + vb = ROR(XOR(vb, vc), 7) + v[a], v[b], v[c], v[d] = va, vb, vc, vd + end + + function blake2s_feed_64(H, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 64 + local h1, h2, h3, h4, h5, h6, h7, h8 = NORM(H[1]), NORM(H[2]), NORM(H[3]), NORM(H[4]), NORM(H[5]), NORM(H[6]), NORM(H[7]), NORM(H[8]) + for pos = offs, offs + size - 1, 64 do + if str then + for j = 1, 16 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a) + end + end + v[0x0], v[0x1], v[0x2], v[0x3], v[0x4], v[0x5], v[0x6], v[0x7] = h1, h2, h3, h4, h5, h6, h7, h8 + v[0x8], v[0x9], v[0xA], v[0xB], v[0xE], v[0xF] = NORM(sha2_H_hi[1]), NORM(sha2_H_hi[2]), NORM(sha2_H_hi[3]), NORM(sha2_H_hi[4]), NORM(sha2_H_hi[7]), NORM(sha2_H_hi[8]) + bytes_compressed = bytes_compressed + (last_block_size or 64) + local t0 = bytes_compressed % 2^32 + local t1 = floor(bytes_compressed / 2^32) + v[0xC] = XOR(sha2_H_hi[5], t0) -- t0 = low_4_bytes(bytes_compressed) + v[0xD] = XOR(sha2_H_hi[6], t1) -- t1 = high_4_bytes(bytes_compressed + if last_block_size then -- flag f0 + v[0xE] = NOT(v[0xE]) + end + if is_last_node then -- flag f1 + v[0xF] = NOT(v[0xF]) + end + for j = 1, 10 do + local row = sigma[j] + G(0, 4, 8, 12, row[ 1], row[ 2]) + G(1, 5, 9, 13, row[ 3], row[ 4]) + G(2, 6, 10, 14, row[ 5], row[ 6]) + G(3, 7, 11, 15, row[ 7], row[ 8]) + G(0, 5, 10, 15, row[ 9], row[10]) + G(1, 6, 11, 12, row[11], row[12]) + G(2, 7, 8, 13, row[13], row[14]) + G(3, 4, 9, 14, row[15], row[16]) + end + h1 = XOR(h1, v[0x0], v[0x8]) + h2 = XOR(h2, v[0x1], v[0x9]) + h3 = XOR(h3, v[0x2], v[0xA]) + h4 = XOR(h4, v[0x3], v[0xB]) + h5 = XOR(h5, v[0x4], v[0xC]) + h6 = XOR(h6, v[0x5], v[0xD]) + h7 = XOR(h7, v[0x6], v[0xE]) + h8 = XOR(h8, v[0x7], v[0xF]) + end + H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 + return bytes_compressed + end + + function blake3_feed_64(str, offs, size, flags, chunk_index, H_in, H_out, wide_output, block_length) + -- offs >= 0, size >= 0, size is multiple of 64 + block_length = block_length or 64 + local h1, h2, h3, h4, h5, h6, h7, h8 = NORM(H_in[1]), NORM(H_in[2]), NORM(H_in[3]), NORM(H_in[4]), NORM(H_in[5]), NORM(H_in[6]), NORM(H_in[7]), NORM(H_in[8]) + H_out = H_out or H_in + for pos = offs, offs + size - 1, 64 do + if str then + for j = 1, 16 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a) + end + end + v[0x0], v[0x1], v[0x2], v[0x3], v[0x4], v[0x5], v[0x6], v[0x7] = h1, h2, h3, h4, h5, h6, h7, h8 + v[0x8], v[0x9], v[0xA], v[0xB] = NORM(sha2_H_hi[1]), NORM(sha2_H_hi[2]), NORM(sha2_H_hi[3]), NORM(sha2_H_hi[4]) + v[0xC] = NORM(chunk_index % 2^32) -- t0 = low_4_bytes(chunk_index) + v[0xD] = floor(chunk_index / 2^32) -- t1 = high_4_bytes(chunk_index) + v[0xE], v[0xF] = block_length, flags + for j = 1, 7 do + G(0, 4, 8, 12, perm_blake3[j], perm_blake3[j + 14]) + G(1, 5, 9, 13, perm_blake3[j + 1], perm_blake3[j + 2]) + G(2, 6, 10, 14, perm_blake3[j + 16], perm_blake3[j + 7]) + G(3, 7, 11, 15, perm_blake3[j + 15], perm_blake3[j + 17]) + G(0, 5, 10, 15, perm_blake3[j + 21], perm_blake3[j + 5]) + G(1, 6, 11, 12, perm_blake3[j + 3], perm_blake3[j + 6]) + G(2, 7, 8, 13, perm_blake3[j + 4], perm_blake3[j + 18]) + G(3, 4, 9, 14, perm_blake3[j + 19], perm_blake3[j + 20]) + end + if wide_output then + H_out[ 9] = XOR(h1, v[0x8]) + H_out[10] = XOR(h2, v[0x9]) + H_out[11] = XOR(h3, v[0xA]) + H_out[12] = XOR(h4, v[0xB]) + H_out[13] = XOR(h5, v[0xC]) + H_out[14] = XOR(h6, v[0xD]) + H_out[15] = XOR(h7, v[0xE]) + H_out[16] = XOR(h8, v[0xF]) + end + h1 = XOR(v[0x0], v[0x8]) + h2 = XOR(v[0x1], v[0x9]) + h3 = XOR(v[0x2], v[0xA]) + h4 = XOR(v[0x3], v[0xB]) + h5 = XOR(v[0x4], v[0xC]) + h6 = XOR(v[0x5], v[0xD]) + h7 = XOR(v[0x6], v[0xE]) + h8 = XOR(v[0x7], v[0xF]) + end + H_out[1], H_out[2], H_out[3], H_out[4], H_out[5], H_out[6], H_out[7], H_out[8] = h1, h2, h3, h4, h5, h6, h7, h8 + end + + end + end @@ -1117,24 +1563,22 @@ if branch == "INT64" then hi_factor_keccak = 4294967296 lanes_index_base = 1 - HEX64, XOR64A5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed = load[[ - local md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo = ... + HEX64, XORA5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed, blake2s_feed_64, blake2b_feed_128, blake3_feed_64 = load[=[-- branch "INT64" + local md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo, sigma, common_W, sha2_H_lo, sha2_H_hi, perm_blake3 = ... local string_format, string_unpack = string.format, string.unpack local function HEX64(x) return string_format("%016x", x) end - local function XOR64A5(x) - return x ~ 0xa5a5a5a5a5a5a5a5 + local function XORA5(x, y) + return x ~ (y or 0xa5a5a5a5a5a5a5a5) end local function XOR_BYTE(x, y) return x ~ y end - local common_W = {} - local function sha256_feed_64(H, str, offs, size) -- offs >= 0, size >= 0, size is multiple of 64 local W, K = common_W, sha2_K_hi @@ -1426,8 +1870,408 @@ if branch == "INT64" then end end - return HEX64, XOR64A5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed - ]](md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo) + local function blake2s_feed_64(H, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 64 + local W = common_W + 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] + for pos = offs + 1, offs + size, 64 do + if str then + W[1], W[2], W[3], W[4], W[5], W[6], W[7], W[8], W[9], W[10], W[11], W[12], W[13], W[14], W[15], W[16] = + string_unpack("> 32 -- t1 = high_4_bytes(bytes_compressed) + if last_block_size then -- flag f0 + vE = ~vE + end + if is_last_node then -- flag f1 + vF = ~vF + end + for j = 1, 10 do + local row = sigma[j] + v0 = v0 + v4 + W[row[1]] + vC = vC ~ v0 + vC = (vC & (1<<32)-1) >> 16 | vC << 16 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = (v4 & (1<<32)-1) >> 12 | v4 << 20 + v0 = v0 + v4 + W[row[2]] + vC = vC ~ v0 + vC = (vC & (1<<32)-1) >> 8 | vC << 24 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = (v4 & (1<<32)-1) >> 7 | v4 << 25 + v1 = v1 + v5 + W[row[3]] + vD = vD ~ v1 + vD = (vD & (1<<32)-1) >> 16 | vD << 16 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = (v5 & (1<<32)-1) >> 12 | v5 << 20 + v1 = v1 + v5 + W[row[4]] + vD = vD ~ v1 + vD = (vD & (1<<32)-1) >> 8 | vD << 24 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = (v5 & (1<<32)-1) >> 7 | v5 << 25 + v2 = v2 + v6 + W[row[5]] + vE = vE ~ v2 + vE = (vE & (1<<32)-1) >> 16 | vE << 16 + vA = vA + vE + v6 = v6 ~ vA + v6 = (v6 & (1<<32)-1) >> 12 | v6 << 20 + v2 = v2 + v6 + W[row[6]] + vE = vE ~ v2 + vE = (vE & (1<<32)-1) >> 8 | vE << 24 + vA = vA + vE + v6 = v6 ~ vA + v6 = (v6 & (1<<32)-1) >> 7 | v6 << 25 + v3 = v3 + v7 + W[row[7]] + vF = vF ~ v3 + vF = (vF & (1<<32)-1) >> 16 | vF << 16 + vB = vB + vF + v7 = v7 ~ vB + v7 = (v7 & (1<<32)-1) >> 12 | v7 << 20 + v3 = v3 + v7 + W[row[8]] + vF = vF ~ v3 + vF = (vF & (1<<32)-1) >> 8 | vF << 24 + vB = vB + vF + v7 = v7 ~ vB + v7 = (v7 & (1<<32)-1) >> 7 | v7 << 25 + v0 = v0 + v5 + W[row[9]] + vF = vF ~ v0 + vF = (vF & (1<<32)-1) >> 16 | vF << 16 + vA = vA + vF + v5 = v5 ~ vA + v5 = (v5 & (1<<32)-1) >> 12 | v5 << 20 + v0 = v0 + v5 + W[row[10]] + vF = vF ~ v0 + vF = (vF & (1<<32)-1) >> 8 | vF << 24 + vA = vA + vF + v5 = v5 ~ vA + v5 = (v5 & (1<<32)-1) >> 7 | v5 << 25 + v1 = v1 + v6 + W[row[11]] + vC = vC ~ v1 + vC = (vC & (1<<32)-1) >> 16 | vC << 16 + vB = vB + vC + v6 = v6 ~ vB + v6 = (v6 & (1<<32)-1) >> 12 | v6 << 20 + v1 = v1 + v6 + W[row[12]] + vC = vC ~ v1 + vC = (vC & (1<<32)-1) >> 8 | vC << 24 + vB = vB + vC + v6 = v6 ~ vB + v6 = (v6 & (1<<32)-1) >> 7 | v6 << 25 + v2 = v2 + v7 + W[row[13]] + vD = vD ~ v2 + vD = (vD & (1<<32)-1) >> 16 | vD << 16 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = (v7 & (1<<32)-1) >> 12 | v7 << 20 + v2 = v2 + v7 + W[row[14]] + vD = vD ~ v2 + vD = (vD & (1<<32)-1) >> 8 | vD << 24 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = (v7 & (1<<32)-1) >> 7 | v7 << 25 + v3 = v3 + v4 + W[row[15]] + vE = vE ~ v3 + vE = (vE & (1<<32)-1) >> 16 | vE << 16 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = (v4 & (1<<32)-1) >> 12 | v4 << 20 + v3 = v3 + v4 + W[row[16]] + vE = vE ~ v3 + vE = (vE & (1<<32)-1) >> 8 | vE << 24 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = (v4 & (1<<32)-1) >> 7 | v4 << 25 + end + h1 = h1 ~ v0 ~ v8 + h2 = h2 ~ v1 ~ v9 + h3 = h3 ~ v2 ~ vA + h4 = h4 ~ v3 ~ vB + h5 = h5 ~ v4 ~ vC + h6 = h6 ~ v5 ~ vD + h7 = h7 ~ v6 ~ vE + h8 = h8 ~ v7 ~ vF + end + H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 + return bytes_compressed + end + + local function blake2b_feed_128(H, _, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 128 + local W = common_W + 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] + for pos = offs + 1, offs + size, 128 do + if str then + W[1], W[2], W[3], W[4], W[5], W[6], W[7], W[8], W[9], W[10], W[11], W[12], W[13], W[14], W[15], W[16] = + string_unpack("> 32 | vC << 32 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = v4 >> 24 | v4 << 40 + v0 = v0 + v4 + W[row[2]] + vC = vC ~ v0 + vC = vC >> 16 | vC << 48 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = v4 >> 63 | v4 << 1 + v1 = v1 + v5 + W[row[3]] + vD = vD ~ v1 + vD = vD >> 32 | vD << 32 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = v5 >> 24 | v5 << 40 + v1 = v1 + v5 + W[row[4]] + vD = vD ~ v1 + vD = vD >> 16 | vD << 48 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = v5 >> 63 | v5 << 1 + v2 = v2 + v6 + W[row[5]] + vE = vE ~ v2 + vE = vE >> 32 | vE << 32 + vA = vA + vE + v6 = v6 ~ vA + v6 = v6 >> 24 | v6 << 40 + v2 = v2 + v6 + W[row[6]] + vE = vE ~ v2 + vE = vE >> 16 | vE << 48 + vA = vA + vE + v6 = v6 ~ vA + v6 = v6 >> 63 | v6 << 1 + v3 = v3 + v7 + W[row[7]] + vF = vF ~ v3 + vF = vF >> 32 | vF << 32 + vB = vB + vF + v7 = v7 ~ vB + v7 = v7 >> 24 | v7 << 40 + v3 = v3 + v7 + W[row[8]] + vF = vF ~ v3 + vF = vF >> 16 | vF << 48 + vB = vB + vF + v7 = v7 ~ vB + v7 = v7 >> 63 | v7 << 1 + v0 = v0 + v5 + W[row[9]] + vF = vF ~ v0 + vF = vF >> 32 | vF << 32 + vA = vA + vF + v5 = v5 ~ vA + v5 = v5 >> 24 | v5 << 40 + v0 = v0 + v5 + W[row[10]] + vF = vF ~ v0 + vF = vF >> 16 | vF << 48 + vA = vA + vF + v5 = v5 ~ vA + v5 = v5 >> 63 | v5 << 1 + v1 = v1 + v6 + W[row[11]] + vC = vC ~ v1 + vC = vC >> 32 | vC << 32 + vB = vB + vC + v6 = v6 ~ vB + v6 = v6 >> 24 | v6 << 40 + v1 = v1 + v6 + W[row[12]] + vC = vC ~ v1 + vC = vC >> 16 | vC << 48 + vB = vB + vC + v6 = v6 ~ vB + v6 = v6 >> 63 | v6 << 1 + v2 = v2 + v7 + W[row[13]] + vD = vD ~ v2 + vD = vD >> 32 | vD << 32 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = v7 >> 24 | v7 << 40 + v2 = v2 + v7 + W[row[14]] + vD = vD ~ v2 + vD = vD >> 16 | vD << 48 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = v7 >> 63 | v7 << 1 + v3 = v3 + v4 + W[row[15]] + vE = vE ~ v3 + vE = vE >> 32 | vE << 32 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = v4 >> 24 | v4 << 40 + v3 = v3 + v4 + W[row[16]] + vE = vE ~ v3 + vE = vE >> 16 | vE << 48 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = v4 >> 63 | v4 << 1 + end + h1 = h1 ~ v0 ~ v8 + h2 = h2 ~ v1 ~ v9 + h3 = h3 ~ v2 ~ vA + h4 = h4 ~ v3 ~ vB + h5 = h5 ~ v4 ~ vC + h6 = h6 ~ v5 ~ vD + h7 = h7 ~ v6 ~ vE + h8 = h8 ~ v7 ~ vF + end + H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 + return bytes_compressed + end + + local function blake3_feed_64(str, offs, size, flags, chunk_index, H_in, H_out, wide_output, block_length) + -- offs >= 0, size >= 0, size is multiple of 64 + block_length = block_length or 64 + local W = common_W + local h1, h2, h3, h4, h5, h6, h7, h8 = H_in[1], H_in[2], H_in[3], H_in[4], H_in[5], H_in[6], H_in[7], H_in[8] + H_out = H_out or H_in + for pos = offs + 1, offs + size, 64 do + if str then + W[1], W[2], W[3], W[4], W[5], W[6], W[7], W[8], W[9], W[10], W[11], W[12], W[13], W[14], W[15], W[16] = + string_unpack("> 16 | vC << 16 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = (v4 & (1<<32)-1) >> 12 | v4 << 20 + v0 = v0 + v4 + W[perm_blake3[j + 14]] + vC = vC ~ v0 + vC = (vC & (1<<32)-1) >> 8 | vC << 24 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = (v4 & (1<<32)-1) >> 7 | v4 << 25 + v1 = v1 + v5 + W[perm_blake3[j + 1]] + vD = vD ~ v1 + vD = (vD & (1<<32)-1) >> 16 | vD << 16 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = (v5 & (1<<32)-1) >> 12 | v5 << 20 + v1 = v1 + v5 + W[perm_blake3[j + 2]] + vD = vD ~ v1 + vD = (vD & (1<<32)-1) >> 8 | vD << 24 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = (v5 & (1<<32)-1) >> 7 | v5 << 25 + v2 = v2 + v6 + W[perm_blake3[j + 16]] + vE = vE ~ v2 + vE = (vE & (1<<32)-1) >> 16 | vE << 16 + vA = vA + vE + v6 = v6 ~ vA + v6 = (v6 & (1<<32)-1) >> 12 | v6 << 20 + v2 = v2 + v6 + W[perm_blake3[j + 7]] + vE = vE ~ v2 + vE = (vE & (1<<32)-1) >> 8 | vE << 24 + vA = vA + vE + v6 = v6 ~ vA + v6 = (v6 & (1<<32)-1) >> 7 | v6 << 25 + v3 = v3 + v7 + W[perm_blake3[j + 15]] + vF = vF ~ v3 + vF = (vF & (1<<32)-1) >> 16 | vF << 16 + vB = vB + vF + v7 = v7 ~ vB + v7 = (v7 & (1<<32)-1) >> 12 | v7 << 20 + v3 = v3 + v7 + W[perm_blake3[j + 17]] + vF = vF ~ v3 + vF = (vF & (1<<32)-1) >> 8 | vF << 24 + vB = vB + vF + v7 = v7 ~ vB + v7 = (v7 & (1<<32)-1) >> 7 | v7 << 25 + v0 = v0 + v5 + W[perm_blake3[j + 21]] + vF = vF ~ v0 + vF = (vF & (1<<32)-1) >> 16 | vF << 16 + vA = vA + vF + v5 = v5 ~ vA + v5 = (v5 & (1<<32)-1) >> 12 | v5 << 20 + v0 = v0 + v5 + W[perm_blake3[j + 5]] + vF = vF ~ v0 + vF = (vF & (1<<32)-1) >> 8 | vF << 24 + vA = vA + vF + v5 = v5 ~ vA + v5 = (v5 & (1<<32)-1) >> 7 | v5 << 25 + v1 = v1 + v6 + W[perm_blake3[j + 3]] + vC = vC ~ v1 + vC = (vC & (1<<32)-1) >> 16 | vC << 16 + vB = vB + vC + v6 = v6 ~ vB + v6 = (v6 & (1<<32)-1) >> 12 | v6 << 20 + v1 = v1 + v6 + W[perm_blake3[j + 6]] + vC = vC ~ v1 + vC = (vC & (1<<32)-1) >> 8 | vC << 24 + vB = vB + vC + v6 = v6 ~ vB + v6 = (v6 & (1<<32)-1) >> 7 | v6 << 25 + v2 = v2 + v7 + W[perm_blake3[j + 4]] + vD = vD ~ v2 + vD = (vD & (1<<32)-1) >> 16 | vD << 16 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = (v7 & (1<<32)-1) >> 12 | v7 << 20 + v2 = v2 + v7 + W[perm_blake3[j + 18]] + vD = vD ~ v2 + vD = (vD & (1<<32)-1) >> 8 | vD << 24 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = (v7 & (1<<32)-1) >> 7 | v7 << 25 + v3 = v3 + v4 + W[perm_blake3[j + 19]] + vE = vE ~ v3 + vE = (vE & (1<<32)-1) >> 16 | vE << 16 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = (v4 & (1<<32)-1) >> 12 | v4 << 20 + v3 = v3 + v4 + W[perm_blake3[j + 20]] + vE = vE ~ v3 + vE = (vE & (1<<32)-1) >> 8 | vE << 24 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = (v4 & (1<<32)-1) >> 7 | v4 << 25 + end + if wide_output then + H_out[ 9] = h1 ~ v8 + H_out[10] = h2 ~ v9 + H_out[11] = h3 ~ vA + H_out[12] = h4 ~ vB + H_out[13] = h5 ~ vC + H_out[14] = h6 ~ vD + H_out[15] = h7 ~ vE + H_out[16] = h8 ~ vF + end + h1 = v0 ~ v8 + h2 = v1 ~ v9 + h3 = v2 ~ vA + h4 = v3 ~ vB + h5 = v4 ~ vC + h6 = v5 ~ vD + h7 = v6 ~ vE + h8 = v7 ~ vF + end + H_out[1], H_out[2], H_out[3], H_out[4], H_out[5], H_out[6], H_out[7], H_out[8] = h1, h2, h3, h4, h5, h6, h7, h8 + end + + return HEX64, XORA5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed, blake2s_feed_64, blake2b_feed_128, blake3_feed_64 + ]=](md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo, sigma, common_W, sha2_H_lo, sha2_H_hi, perm_blake3) end @@ -1443,20 +2287,18 @@ if branch == "INT32" then return string_format("%08x", x) end - XOR32A5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed = load[[ - local md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo, sha3_RC_hi = ... + XORA5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed, blake2s_feed_64, blake2b_feed_128, blake3_feed_64 = load[=[-- branch "INT32" + local md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo, sha3_RC_hi, sigma, common_W, sha2_H_lo, sha2_H_hi, perm_blake3 = ... local string_unpack, floor = string.unpack, math.floor - local function XOR32A5(x) - return x ~ 0xA5A5A5A5 + local function XORA5(x, y) + return x ~ (y and (y + 2^31) % 2^32 - 2^31 or 0xA5A5A5A5) end local function XOR_BYTE(x, y) return x ~ y end - local common_W = {} - local function sha256_feed_64(H, str, offs, size) -- offs >= 0, size >= 0, size is multiple of 64 local W, K = common_W, sha2_K_hi @@ -1521,21 +2363,15 @@ if branch == "INT32" then local z_lo = (e_lo>>14 ~ e_hi<<18 ~ e_lo>>18 ~ e_hi<<14 ~ e_lo<<23 ~ e_hi>>9) % 2^32 + (g_lo ~ e_lo & (f_lo ~ g_lo)) % 2^32 + h_lo % 2^32 + K_lo[j] + W[jj] % 2^32 local z_hi = (e_hi>>14 ~ e_lo<<18 ~ e_hi>>18 ~ e_lo<<14 ~ e_hi<<23 ~ e_lo>>9) + (g_hi ~ e_hi & (f_hi ~ g_hi)) + h_hi + K_hi[j] + W[jj-1] + floor(z_lo / 2^32) z_lo = z_lo % 2^32 - h_lo = g_lo - h_hi = g_hi - g_lo = f_lo - g_hi = f_hi - f_lo = e_lo - f_hi = e_hi + h_lo = g_lo; h_hi = g_hi + g_lo = f_lo; g_hi = f_hi + f_lo = e_lo; f_hi = e_hi e_lo = z_lo + d_lo % 2^32 e_hi = z_hi + d_hi + floor(e_lo / 2^32) e_lo = 0|((e_lo + 2^31) % 2^32 - 2^31) - d_lo = c_lo - d_hi = c_hi - c_lo = b_lo - c_hi = b_hi - b_lo = a_lo - b_hi = a_hi + d_lo = c_lo; d_hi = c_hi + c_lo = b_lo; c_hi = b_hi + b_lo = a_lo; b_hi = a_hi z_lo = z_lo + (d_lo & c_lo ~ b_lo & (d_lo ~ c_lo)) % 2^32 + (b_lo>>28 ~ b_hi<<4 ~ b_lo<<30 ~ b_hi>>2 ~ b_lo<<25 ~ b_hi>>7) % 2^32 a_hi = z_hi + (d_hi & c_hi ~ b_hi & (d_hi ~ c_hi)) + (b_hi>>28 ~ b_lo<<4 ~ b_hi<<30 ~ b_lo>>2 ~ b_hi<<25 ~ b_lo>>7) + floor(z_lo / 2^32) a_lo = 0|((z_lo + 2^31) % 2^32 - 2^31) @@ -1827,64 +2663,535 @@ if branch == "INT32" then L01_lo = L01_lo ~ RC_lo[round_idx] L01_hi = L01_hi ~ RC_hi[round_idx] end - lanes_lo[1] = L01_lo - lanes_hi[1] = L01_hi - lanes_lo[2] = L02_lo - lanes_hi[2] = L02_hi - lanes_lo[3] = L03_lo - lanes_hi[3] = L03_hi - lanes_lo[4] = L04_lo - lanes_hi[4] = L04_hi - lanes_lo[5] = L05_lo - lanes_hi[5] = L05_hi - lanes_lo[6] = L06_lo - lanes_hi[6] = L06_hi - lanes_lo[7] = L07_lo - lanes_hi[7] = L07_hi - lanes_lo[8] = L08_lo - lanes_hi[8] = L08_hi - lanes_lo[9] = L09_lo - lanes_hi[9] = L09_hi - lanes_lo[10] = L10_lo - lanes_hi[10] = L10_hi - lanes_lo[11] = L11_lo - lanes_hi[11] = L11_hi - lanes_lo[12] = L12_lo - lanes_hi[12] = L12_hi - lanes_lo[13] = L13_lo - lanes_hi[13] = L13_hi - lanes_lo[14] = L14_lo - lanes_hi[14] = L14_hi - lanes_lo[15] = L15_lo - lanes_hi[15] = L15_hi - lanes_lo[16] = L16_lo - lanes_hi[16] = L16_hi - lanes_lo[17] = L17_lo - lanes_hi[17] = L17_hi - lanes_lo[18] = L18_lo - lanes_hi[18] = L18_hi - lanes_lo[19] = L19_lo - lanes_hi[19] = L19_hi - lanes_lo[20] = L20_lo - lanes_hi[20] = L20_hi - lanes_lo[21] = L21_lo - lanes_hi[21] = L21_hi - lanes_lo[22] = L22_lo - lanes_hi[22] = L22_hi - lanes_lo[23] = L23_lo - lanes_hi[23] = L23_hi - lanes_lo[24] = L24_lo - lanes_hi[24] = L24_hi - lanes_lo[25] = L25_lo - lanes_hi[25] = L25_hi + lanes_lo[1] = L01_lo; lanes_hi[1] = L01_hi + lanes_lo[2] = L02_lo; lanes_hi[2] = L02_hi + lanes_lo[3] = L03_lo; lanes_hi[3] = L03_hi + lanes_lo[4] = L04_lo; lanes_hi[4] = L04_hi + lanes_lo[5] = L05_lo; lanes_hi[5] = L05_hi + lanes_lo[6] = L06_lo; lanes_hi[6] = L06_hi + lanes_lo[7] = L07_lo; lanes_hi[7] = L07_hi + lanes_lo[8] = L08_lo; lanes_hi[8] = L08_hi + lanes_lo[9] = L09_lo; lanes_hi[9] = L09_hi + lanes_lo[10] = L10_lo; lanes_hi[10] = L10_hi + lanes_lo[11] = L11_lo; lanes_hi[11] = L11_hi + lanes_lo[12] = L12_lo; lanes_hi[12] = L12_hi + lanes_lo[13] = L13_lo; lanes_hi[13] = L13_hi + lanes_lo[14] = L14_lo; lanes_hi[14] = L14_hi + lanes_lo[15] = L15_lo; lanes_hi[15] = L15_hi + lanes_lo[16] = L16_lo; lanes_hi[16] = L16_hi + lanes_lo[17] = L17_lo; lanes_hi[17] = L17_hi + lanes_lo[18] = L18_lo; lanes_hi[18] = L18_hi + lanes_lo[19] = L19_lo; lanes_hi[19] = L19_hi + lanes_lo[20] = L20_lo; lanes_hi[20] = L20_hi + lanes_lo[21] = L21_lo; lanes_hi[21] = L21_hi + lanes_lo[22] = L22_lo; lanes_hi[22] = L22_hi + lanes_lo[23] = L23_lo; lanes_hi[23] = L23_hi + lanes_lo[24] = L24_lo; lanes_hi[24] = L24_hi + lanes_lo[25] = L25_lo; lanes_hi[25] = L25_hi end end - return XOR32A5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed - ]](md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo, sha3_RC_hi) + local function blake2s_feed_64(H, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 64 + local W = common_W + 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] + for pos = offs + 1, offs + size, 64 do + if str then + W[1], W[2], W[3], W[4], W[5], W[6], W[7], W[8], W[9], W[10], W[11], W[12], W[13], W[14], W[15], W[16] = + string_unpack("> 16 | vC << 16 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = v4 >> 12 | v4 << 20 + v0 = v0 + v4 + W[row[2]] + vC = vC ~ v0 + vC = vC >> 8 | vC << 24 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = v4 >> 7 | v4 << 25 + v1 = v1 + v5 + W[row[3]] + vD = vD ~ v1 + vD = vD >> 16 | vD << 16 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = v5 >> 12 | v5 << 20 + v1 = v1 + v5 + W[row[4]] + vD = vD ~ v1 + vD = vD >> 8 | vD << 24 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = v5 >> 7 | v5 << 25 + v2 = v2 + v6 + W[row[5]] + vE = vE ~ v2 + vE = vE >> 16 | vE << 16 + vA = vA + vE + v6 = v6 ~ vA + v6 = v6 >> 12 | v6 << 20 + v2 = v2 + v6 + W[row[6]] + vE = vE ~ v2 + vE = vE >> 8 | vE << 24 + vA = vA + vE + v6 = v6 ~ vA + v6 = v6 >> 7 | v6 << 25 + v3 = v3 + v7 + W[row[7]] + vF = vF ~ v3 + vF = vF >> 16 | vF << 16 + vB = vB + vF + v7 = v7 ~ vB + v7 = v7 >> 12 | v7 << 20 + v3 = v3 + v7 + W[row[8]] + vF = vF ~ v3 + vF = vF >> 8 | vF << 24 + vB = vB + vF + v7 = v7 ~ vB + v7 = v7 >> 7 | v7 << 25 + v0 = v0 + v5 + W[row[9]] + vF = vF ~ v0 + vF = vF >> 16 | vF << 16 + vA = vA + vF + v5 = v5 ~ vA + v5 = v5 >> 12 | v5 << 20 + v0 = v0 + v5 + W[row[10]] + vF = vF ~ v0 + vF = vF >> 8 | vF << 24 + vA = vA + vF + v5 = v5 ~ vA + v5 = v5 >> 7 | v5 << 25 + v1 = v1 + v6 + W[row[11]] + vC = vC ~ v1 + vC = vC >> 16 | vC << 16 + vB = vB + vC + v6 = v6 ~ vB + v6 = v6 >> 12 | v6 << 20 + v1 = v1 + v6 + W[row[12]] + vC = vC ~ v1 + vC = vC >> 8 | vC << 24 + vB = vB + vC + v6 = v6 ~ vB + v6 = v6 >> 7 | v6 << 25 + v2 = v2 + v7 + W[row[13]] + vD = vD ~ v2 + vD = vD >> 16 | vD << 16 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = v7 >> 12 | v7 << 20 + v2 = v2 + v7 + W[row[14]] + vD = vD ~ v2 + vD = vD >> 8 | vD << 24 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = v7 >> 7 | v7 << 25 + v3 = v3 + v4 + W[row[15]] + vE = vE ~ v3 + vE = vE >> 16 | vE << 16 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = v4 >> 12 | v4 << 20 + v3 = v3 + v4 + W[row[16]] + vE = vE ~ v3 + vE = vE >> 8 | vE << 24 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = v4 >> 7 | v4 << 25 + end + h1 = h1 ~ v0 ~ v8 + h2 = h2 ~ v1 ~ v9 + h3 = h3 ~ v2 ~ vA + h4 = h4 ~ v3 ~ vB + h5 = h5 ~ v4 ~ vC + h6 = h6 ~ v5 ~ vD + h7 = h7 ~ v6 ~ vE + h8 = h8 ~ v7 ~ vF + end + H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 + return bytes_compressed + end + + local function blake2b_feed_128(H_lo, H_hi, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 128 + local W = common_W + 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] + 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] + for pos = offs + 1, offs + size, 128 do + if str then + W[1], W[2], W[3], W[4], W[5], W[6], W[7], W[8], W[9], W[10], W[11], W[12], W[13], W[14], W[15], W[16], + W[17], W[18], W[19], W[20], W[21], W[22], W[23], W[24], W[25], W[26], W[27], W[28], W[29], W[30], W[31], W[32] = + string_unpack("> 24 | v4_hi << 8, v4_hi >> 24 | v4_lo << 8 + k = row[2] * 2 + v0_lo = v0_lo % 2^32 + v4_lo % 2^32 + W[k-1] % 2^32 + v0_hi = v0_hi + v4_hi + floor(v0_lo / 2^32) + W[k] + v0_lo = 0|((v0_lo + 2^31) % 2^32 - 2^31) + vC_lo, vC_hi = vC_lo ~ v0_lo, vC_hi ~ v0_hi + vC_lo, vC_hi = vC_lo >> 16 | vC_hi << 16, vC_hi >> 16 | vC_lo << 16 + v8_lo = v8_lo % 2^32 + vC_lo % 2^32 + v8_hi = v8_hi + vC_hi + floor(v8_lo / 2^32) + v8_lo = 0|((v8_lo + 2^31) % 2^32 - 2^31) + v4_lo, v4_hi = v4_lo ~ v8_lo, v4_hi ~ v8_hi + v4_lo, v4_hi = v4_lo << 1 | v4_hi >> 31, v4_hi << 1 | v4_lo >> 31 + k = row[3] * 2 + v1_lo = v1_lo % 2^32 + v5_lo % 2^32 + W[k-1] % 2^32 + v1_hi = v1_hi + v5_hi + floor(v1_lo / 2^32) + W[k] + v1_lo = 0|((v1_lo + 2^31) % 2^32 - 2^31) + vD_lo, vD_hi = vD_hi ~ v1_hi, vD_lo ~ v1_lo + v9_lo = v9_lo % 2^32 + vD_lo % 2^32 + v9_hi = v9_hi + vD_hi + floor(v9_lo / 2^32) + v9_lo = 0|((v9_lo + 2^31) % 2^32 - 2^31) + v5_lo, v5_hi = v5_lo ~ v9_lo, v5_hi ~ v9_hi + v5_lo, v5_hi = v5_lo >> 24 | v5_hi << 8, v5_hi >> 24 | v5_lo << 8 + k = row[4] * 2 + v1_lo = v1_lo % 2^32 + v5_lo % 2^32 + W[k-1] % 2^32 + v1_hi = v1_hi + v5_hi + floor(v1_lo / 2^32) + W[k] + v1_lo = 0|((v1_lo + 2^31) % 2^32 - 2^31) + vD_lo, vD_hi = vD_lo ~ v1_lo, vD_hi ~ v1_hi + vD_lo, vD_hi = vD_lo >> 16 | vD_hi << 16, vD_hi >> 16 | vD_lo << 16 + v9_lo = v9_lo % 2^32 + vD_lo % 2^32 + v9_hi = v9_hi + vD_hi + floor(v9_lo / 2^32) + v9_lo = 0|((v9_lo + 2^31) % 2^32 - 2^31) + v5_lo, v5_hi = v5_lo ~ v9_lo, v5_hi ~ v9_hi + v5_lo, v5_hi = v5_lo << 1 | v5_hi >> 31, v5_hi << 1 | v5_lo >> 31 + k = row[5] * 2 + v2_lo = v2_lo % 2^32 + v6_lo % 2^32 + W[k-1] % 2^32 + v2_hi = v2_hi + v6_hi + floor(v2_lo / 2^32) + W[k] + v2_lo = 0|((v2_lo + 2^31) % 2^32 - 2^31) + vE_lo, vE_hi = vE_hi ~ v2_hi, vE_lo ~ v2_lo + vA_lo = vA_lo % 2^32 + vE_lo % 2^32 + vA_hi = vA_hi + vE_hi + floor(vA_lo / 2^32) + vA_lo = 0|((vA_lo + 2^31) % 2^32 - 2^31) + v6_lo, v6_hi = v6_lo ~ vA_lo, v6_hi ~ vA_hi + v6_lo, v6_hi = v6_lo >> 24 | v6_hi << 8, v6_hi >> 24 | v6_lo << 8 + k = row[6] * 2 + v2_lo = v2_lo % 2^32 + v6_lo % 2^32 + W[k-1] % 2^32 + v2_hi = v2_hi + v6_hi + floor(v2_lo / 2^32) + W[k] + v2_lo = 0|((v2_lo + 2^31) % 2^32 - 2^31) + vE_lo, vE_hi = vE_lo ~ v2_lo, vE_hi ~ v2_hi + vE_lo, vE_hi = vE_lo >> 16 | vE_hi << 16, vE_hi >> 16 | vE_lo << 16 + vA_lo = vA_lo % 2^32 + vE_lo % 2^32 + vA_hi = vA_hi + vE_hi + floor(vA_lo / 2^32) + vA_lo = 0|((vA_lo + 2^31) % 2^32 - 2^31) + v6_lo, v6_hi = v6_lo ~ vA_lo, v6_hi ~ vA_hi + v6_lo, v6_hi = v6_lo << 1 | v6_hi >> 31, v6_hi << 1 | v6_lo >> 31 + k = row[7] * 2 + v3_lo = v3_lo % 2^32 + v7_lo % 2^32 + W[k-1] % 2^32 + v3_hi = v3_hi + v7_hi + floor(v3_lo / 2^32) + W[k] + v3_lo = 0|((v3_lo + 2^31) % 2^32 - 2^31) + vF_lo, vF_hi = vF_hi ~ v3_hi, vF_lo ~ v3_lo + vB_lo = vB_lo % 2^32 + vF_lo % 2^32 + vB_hi = vB_hi + vF_hi + floor(vB_lo / 2^32) + vB_lo = 0|((vB_lo + 2^31) % 2^32 - 2^31) + v7_lo, v7_hi = v7_lo ~ vB_lo, v7_hi ~ vB_hi + v7_lo, v7_hi = v7_lo >> 24 | v7_hi << 8, v7_hi >> 24 | v7_lo << 8 + k = row[8] * 2 + v3_lo = v3_lo % 2^32 + v7_lo % 2^32 + W[k-1] % 2^32 + v3_hi = v3_hi + v7_hi + floor(v3_lo / 2^32) + W[k] + v3_lo = 0|((v3_lo + 2^31) % 2^32 - 2^31) + vF_lo, vF_hi = vF_lo ~ v3_lo, vF_hi ~ v3_hi + vF_lo, vF_hi = vF_lo >> 16 | vF_hi << 16, vF_hi >> 16 | vF_lo << 16 + vB_lo = vB_lo % 2^32 + vF_lo % 2^32 + vB_hi = vB_hi + vF_hi + floor(vB_lo / 2^32) + vB_lo = 0|((vB_lo + 2^31) % 2^32 - 2^31) + v7_lo, v7_hi = v7_lo ~ vB_lo, v7_hi ~ vB_hi + v7_lo, v7_hi = v7_lo << 1 | v7_hi >> 31, v7_hi << 1 | v7_lo >> 31 + k = row[9] * 2 + v0_lo = v0_lo % 2^32 + v5_lo % 2^32 + W[k-1] % 2^32 + v0_hi = v0_hi + v5_hi + floor(v0_lo / 2^32) + W[k] + v0_lo = 0|((v0_lo + 2^31) % 2^32 - 2^31) + vF_lo, vF_hi = vF_hi ~ v0_hi, vF_lo ~ v0_lo + vA_lo = vA_lo % 2^32 + vF_lo % 2^32 + vA_hi = vA_hi + vF_hi + floor(vA_lo / 2^32) + vA_lo = 0|((vA_lo + 2^31) % 2^32 - 2^31) + v5_lo, v5_hi = v5_lo ~ vA_lo, v5_hi ~ vA_hi + v5_lo, v5_hi = v5_lo >> 24 | v5_hi << 8, v5_hi >> 24 | v5_lo << 8 + k = row[10] * 2 + v0_lo = v0_lo % 2^32 + v5_lo % 2^32 + W[k-1] % 2^32 + v0_hi = v0_hi + v5_hi + floor(v0_lo / 2^32) + W[k] + v0_lo = 0|((v0_lo + 2^31) % 2^32 - 2^31) + vF_lo, vF_hi = vF_lo ~ v0_lo, vF_hi ~ v0_hi + vF_lo, vF_hi = vF_lo >> 16 | vF_hi << 16, vF_hi >> 16 | vF_lo << 16 + vA_lo = vA_lo % 2^32 + vF_lo % 2^32 + vA_hi = vA_hi + vF_hi + floor(vA_lo / 2^32) + vA_lo = 0|((vA_lo + 2^31) % 2^32 - 2^31) + v5_lo, v5_hi = v5_lo ~ vA_lo, v5_hi ~ vA_hi + v5_lo, v5_hi = v5_lo << 1 | v5_hi >> 31, v5_hi << 1 | v5_lo >> 31 + k = row[11] * 2 + v1_lo = v1_lo % 2^32 + v6_lo % 2^32 + W[k-1] % 2^32 + v1_hi = v1_hi + v6_hi + floor(v1_lo / 2^32) + W[k] + v1_lo = 0|((v1_lo + 2^31) % 2^32 - 2^31) + vC_lo, vC_hi = vC_hi ~ v1_hi, vC_lo ~ v1_lo + vB_lo = vB_lo % 2^32 + vC_lo % 2^32 + vB_hi = vB_hi + vC_hi + floor(vB_lo / 2^32) + vB_lo = 0|((vB_lo + 2^31) % 2^32 - 2^31) + v6_lo, v6_hi = v6_lo ~ vB_lo, v6_hi ~ vB_hi + v6_lo, v6_hi = v6_lo >> 24 | v6_hi << 8, v6_hi >> 24 | v6_lo << 8 + k = row[12] * 2 + v1_lo = v1_lo % 2^32 + v6_lo % 2^32 + W[k-1] % 2^32 + v1_hi = v1_hi + v6_hi + floor(v1_lo / 2^32) + W[k] + v1_lo = 0|((v1_lo + 2^31) % 2^32 - 2^31) + vC_lo, vC_hi = vC_lo ~ v1_lo, vC_hi ~ v1_hi + vC_lo, vC_hi = vC_lo >> 16 | vC_hi << 16, vC_hi >> 16 | vC_lo << 16 + vB_lo = vB_lo % 2^32 + vC_lo % 2^32 + vB_hi = vB_hi + vC_hi + floor(vB_lo / 2^32) + vB_lo = 0|((vB_lo + 2^31) % 2^32 - 2^31) + v6_lo, v6_hi = v6_lo ~ vB_lo, v6_hi ~ vB_hi + v6_lo, v6_hi = v6_lo << 1 | v6_hi >> 31, v6_hi << 1 | v6_lo >> 31 + k = row[13] * 2 + v2_lo = v2_lo % 2^32 + v7_lo % 2^32 + W[k-1] % 2^32 + v2_hi = v2_hi + v7_hi + floor(v2_lo / 2^32) + W[k] + v2_lo = 0|((v2_lo + 2^31) % 2^32 - 2^31) + vD_lo, vD_hi = vD_hi ~ v2_hi, vD_lo ~ v2_lo + v8_lo = v8_lo % 2^32 + vD_lo % 2^32 + v8_hi = v8_hi + vD_hi + floor(v8_lo / 2^32) + v8_lo = 0|((v8_lo + 2^31) % 2^32 - 2^31) + v7_lo, v7_hi = v7_lo ~ v8_lo, v7_hi ~ v8_hi + v7_lo, v7_hi = v7_lo >> 24 | v7_hi << 8, v7_hi >> 24 | v7_lo << 8 + k = row[14] * 2 + v2_lo = v2_lo % 2^32 + v7_lo % 2^32 + W[k-1] % 2^32 + v2_hi = v2_hi + v7_hi + floor(v2_lo / 2^32) + W[k] + v2_lo = 0|((v2_lo + 2^31) % 2^32 - 2^31) + vD_lo, vD_hi = vD_lo ~ v2_lo, vD_hi ~ v2_hi + vD_lo, vD_hi = vD_lo >> 16 | vD_hi << 16, vD_hi >> 16 | vD_lo << 16 + v8_lo = v8_lo % 2^32 + vD_lo % 2^32 + v8_hi = v8_hi + vD_hi + floor(v8_lo / 2^32) + v8_lo = 0|((v8_lo + 2^31) % 2^32 - 2^31) + v7_lo, v7_hi = v7_lo ~ v8_lo, v7_hi ~ v8_hi + v7_lo, v7_hi = v7_lo << 1 | v7_hi >> 31, v7_hi << 1 | v7_lo >> 31 + k = row[15] * 2 + v3_lo = v3_lo % 2^32 + v4_lo % 2^32 + W[k-1] % 2^32 + v3_hi = v3_hi + v4_hi + floor(v3_lo / 2^32) + W[k] + v3_lo = 0|((v3_lo + 2^31) % 2^32 - 2^31) + vE_lo, vE_hi = vE_hi ~ v3_hi, vE_lo ~ v3_lo + v9_lo = v9_lo % 2^32 + vE_lo % 2^32 + v9_hi = v9_hi + vE_hi + floor(v9_lo / 2^32) + v9_lo = 0|((v9_lo + 2^31) % 2^32 - 2^31) + v4_lo, v4_hi = v4_lo ~ v9_lo, v4_hi ~ v9_hi + v4_lo, v4_hi = v4_lo >> 24 | v4_hi << 8, v4_hi >> 24 | v4_lo << 8 + k = row[16] * 2 + v3_lo = v3_lo % 2^32 + v4_lo % 2^32 + W[k-1] % 2^32 + v3_hi = v3_hi + v4_hi + floor(v3_lo / 2^32) + W[k] + v3_lo = 0|((v3_lo + 2^31) % 2^32 - 2^31) + vE_lo, vE_hi = vE_lo ~ v3_lo, vE_hi ~ v3_hi + vE_lo, vE_hi = vE_lo >> 16 | vE_hi << 16, vE_hi >> 16 | vE_lo << 16 + v9_lo = v9_lo % 2^32 + vE_lo % 2^32 + v9_hi = v9_hi + vE_hi + floor(v9_lo / 2^32) + v9_lo = 0|((v9_lo + 2^31) % 2^32 - 2^31) + v4_lo, v4_hi = v4_lo ~ v9_lo, v4_hi ~ v9_hi + v4_lo, v4_hi = v4_lo << 1 | v4_hi >> 31, v4_hi << 1 | v4_lo >> 31 + end + h1_lo = h1_lo ~ v0_lo ~ v8_lo + h2_lo = h2_lo ~ v1_lo ~ v9_lo + h3_lo = h3_lo ~ v2_lo ~ vA_lo + h4_lo = h4_lo ~ v3_lo ~ vB_lo + h5_lo = h5_lo ~ v4_lo ~ vC_lo + h6_lo = h6_lo ~ v5_lo ~ vD_lo + h7_lo = h7_lo ~ v6_lo ~ vE_lo + h8_lo = h8_lo ~ v7_lo ~ vF_lo + h1_hi = h1_hi ~ v0_hi ~ v8_hi + h2_hi = h2_hi ~ v1_hi ~ v9_hi + h3_hi = h3_hi ~ v2_hi ~ vA_hi + h4_hi = h4_hi ~ v3_hi ~ vB_hi + h5_hi = h5_hi ~ v4_hi ~ vC_hi + h6_hi = h6_hi ~ v5_hi ~ vD_hi + h7_hi = h7_hi ~ v6_hi ~ vE_hi + h8_hi = h8_hi ~ v7_hi ~ vF_hi + end + 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 + 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 + return bytes_compressed + end + + local function blake3_feed_64(str, offs, size, flags, chunk_index, H_in, H_out, wide_output, block_length) + -- offs >= 0, size >= 0, size is multiple of 64 + block_length = block_length or 64 + local W = common_W + local h1, h2, h3, h4, h5, h6, h7, h8 = H_in[1], H_in[2], H_in[3], H_in[4], H_in[5], H_in[6], H_in[7], H_in[8] + H_out = H_out or H_in + for pos = offs + 1, offs + size, 64 do + if str then + W[1], W[2], W[3], W[4], W[5], W[6], W[7], W[8], W[9], W[10], W[11], W[12], W[13], W[14], W[15], W[16] = + string_unpack("> 16 | vC << 16 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = v4 >> 12 | v4 << 20 + v0 = v0 + v4 + W[perm_blake3[j + 14]] + vC = vC ~ v0 + vC = vC >> 8 | vC << 24 + v8 = v8 + vC + v4 = v4 ~ v8 + v4 = v4 >> 7 | v4 << 25 + v1 = v1 + v5 + W[perm_blake3[j + 1]] + vD = vD ~ v1 + vD = vD >> 16 | vD << 16 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = v5 >> 12 | v5 << 20 + v1 = v1 + v5 + W[perm_blake3[j + 2]] + vD = vD ~ v1 + vD = vD >> 8 | vD << 24 + v9 = v9 + vD + v5 = v5 ~ v9 + v5 = v5 >> 7 | v5 << 25 + v2 = v2 + v6 + W[perm_blake3[j + 16]] + vE = vE ~ v2 + vE = vE >> 16 | vE << 16 + vA = vA + vE + v6 = v6 ~ vA + v6 = v6 >> 12 | v6 << 20 + v2 = v2 + v6 + W[perm_blake3[j + 7]] + vE = vE ~ v2 + vE = vE >> 8 | vE << 24 + vA = vA + vE + v6 = v6 ~ vA + v6 = v6 >> 7 | v6 << 25 + v3 = v3 + v7 + W[perm_blake3[j + 15]] + vF = vF ~ v3 + vF = vF >> 16 | vF << 16 + vB = vB + vF + v7 = v7 ~ vB + v7 = v7 >> 12 | v7 << 20 + v3 = v3 + v7 + W[perm_blake3[j + 17]] + vF = vF ~ v3 + vF = vF >> 8 | vF << 24 + vB = vB + vF + v7 = v7 ~ vB + v7 = v7 >> 7 | v7 << 25 + v0 = v0 + v5 + W[perm_blake3[j + 21]] + vF = vF ~ v0 + vF = vF >> 16 | vF << 16 + vA = vA + vF + v5 = v5 ~ vA + v5 = v5 >> 12 | v5 << 20 + v0 = v0 + v5 + W[perm_blake3[j + 5]] + vF = vF ~ v0 + vF = vF >> 8 | vF << 24 + vA = vA + vF + v5 = v5 ~ vA + v5 = v5 >> 7 | v5 << 25 + v1 = v1 + v6 + W[perm_blake3[j + 3]] + vC = vC ~ v1 + vC = vC >> 16 | vC << 16 + vB = vB + vC + v6 = v6 ~ vB + v6 = v6 >> 12 | v6 << 20 + v1 = v1 + v6 + W[perm_blake3[j + 6]] + vC = vC ~ v1 + vC = vC >> 8 | vC << 24 + vB = vB + vC + v6 = v6 ~ vB + v6 = v6 >> 7 | v6 << 25 + v2 = v2 + v7 + W[perm_blake3[j + 4]] + vD = vD ~ v2 + vD = vD >> 16 | vD << 16 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = v7 >> 12 | v7 << 20 + v2 = v2 + v7 + W[perm_blake3[j + 18]] + vD = vD ~ v2 + vD = vD >> 8 | vD << 24 + v8 = v8 + vD + v7 = v7 ~ v8 + v7 = v7 >> 7 | v7 << 25 + v3 = v3 + v4 + W[perm_blake3[j + 19]] + vE = vE ~ v3 + vE = vE >> 16 | vE << 16 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = v4 >> 12 | v4 << 20 + v3 = v3 + v4 + W[perm_blake3[j + 20]] + vE = vE ~ v3 + vE = vE >> 8 | vE << 24 + v9 = v9 + vE + v4 = v4 ~ v9 + v4 = v4 >> 7 | v4 << 25 + end + if wide_output then + H_out[ 9] = h1 ~ v8 + H_out[10] = h2 ~ v9 + H_out[11] = h3 ~ vA + H_out[12] = h4 ~ vB + H_out[13] = h5 ~ vC + H_out[14] = h6 ~ vD + H_out[15] = h7 ~ vE + H_out[16] = h8 ~ vF + end + h1 = v0 ~ v8 + h2 = v1 ~ v9 + h3 = v2 ~ vA + h4 = v3 ~ vB + h5 = v4 ~ vC + h6 = v5 ~ vD + h7 = v6 ~ vE + h8 = v7 ~ vF + end + H_out[1], H_out[2], H_out[3], H_out[4], H_out[5], H_out[6], H_out[7], H_out[8] = h1, h2, h3, h4, h5, h6, h7, h8 + end + + return XORA5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed, blake2s_feed_64, blake2b_feed_128, blake3_feed_64 + ]=](md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo, sha3_RC_hi, sigma, common_W, sha2_H_lo, sha2_H_hi, perm_blake3) end +XOR = XOR or XORA5 if branch == "LIB32" or branch == "EMUL" then @@ -1903,26 +3210,36 @@ if branch == "LIB32" or branch == "EMUL" then end for j = 17, 64 do local a, b = W[j-15], W[j-2] - W[j] = XOR(ROR(a, 7), ROL(a, 14), SHR(a, 3)) + XOR(ROL(b, 15), ROL(b, 13), SHR(b, 10)) + W[j-7] + W[j-16] + local a7, a18, b17, b19 = a / 2^7, a / 2^18, b / 2^17, b / 2^19 + W[j] = (XOR(a7 % 1 * (2^32 - 1) + a7, a18 % 1 * (2^32 - 1) + a18, (a - a % 2^3) / 2^3) + W[j-16] + W[j-7] + + XOR(b17 % 1 * (2^32 - 1) + b17, b19 % 1 * (2^32 - 1) + b19, (b - b % 2^10) / 2^10)) % 2^32 end local a, b, c, d, e, f, g, h = h1, h2, h3, h4, h5, h6, h7, h8 for j = 1, 64 do - local z = XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + AND(e, f) + AND(-1-e, g) + h + K[j] + W[j] + e = e % 2^32 + local e6, e11, e7 = e / 2^6, e / 2^11, e * 2^7 + local e7_lo = e7 % 2^32 + local z = AND(e, f) + AND(-1-e, g) + h + K[j] + W[j] + + XOR(e6 % 1 * (2^32 - 1) + e6, e11 % 1 * (2^32 - 1) + e11, e7_lo + (e7 - e7_lo) / 2^32) h = g g = f f = e e = z + d d = c c = b - b = a - a = z + AND(d, c) + AND(a, XOR(d, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + b = a % 2^32 + local b2, b13, b10 = b / 2^2, b / 2^13, b * 2^10 + local b10_lo = b10 % 2^32 + a = z + AND(d, c) + AND(b, XOR(d, c)) + + XOR(b2 % 1 * (2^32 - 1) + b2, b13 % 1 * (2^32 - 1) + b13, b10_lo + (b10 - b10_lo) / 2^32) end - h1, h2, h3, h4 = (a + h1) % 4294967296, (b + h2) % 4294967296, (c + h3) % 4294967296, (d + h4) % 4294967296 - h5, h6, h7, h8 = (e + h5) % 4294967296, (f + h6) % 4294967296, (g + h7) % 4294967296, (h + h8) % 4294967296 + h1, h2, h3, h4 = (a + h1) % 2^32, (b + h2) % 2^32, (c + h3) % 2^32, (d + h4) % 2^32 + h5, h6, h7, h8 = (e + h5) % 2^32, (f + h6) % 2^32, (g + h7) % 2^32, (h + h8) % 2^32 end H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 end + function sha512_feed_128(H_lo, H_hi, str, offs, size) -- offs >= 0, size >= 0, size is multiple of 128 -- W1_hi, W1_lo, W2_hi, W2_lo, ... Wk_hi = W[2*k-1], Wk_lo = W[2*k] @@ -1936,122 +3253,195 @@ if branch == "LIB32" or branch == "EMUL" then W[j] = ((a * 256 + b) * 256 + c) * 256 + d end for jj = 17*2, 80*2, 2 do - local a_lo, a_hi, b_lo, b_hi = W[jj-30], W[jj-31], W[jj-4], W[jj-5] - local tmp1 = XOR(SHR(a_lo, 1) + SHL(a_hi, 31), SHR(a_lo, 8) + SHL(a_hi, 24), SHR(a_lo, 7) + SHL(a_hi, 25)) % 4294967296 + XOR(SHR(b_lo, 19) + SHL(b_hi, 13), SHL(b_lo, 3) + SHR(b_hi, 29), SHR(b_lo, 6) + SHL(b_hi, 26)) % 4294967296 + W[jj-14] + W[jj-32] - local tmp2 = tmp1 % 4294967296 - W[jj-1] = XOR(SHR(a_hi, 1) + SHL(a_lo, 31), SHR(a_hi, 8) + SHL(a_lo, 24), SHR(a_hi, 7)) + XOR(SHR(b_hi, 19) + SHL(b_lo, 13), SHL(b_hi, 3) + SHR(b_lo, 29), SHR(b_hi, 6)) + W[jj-15] + W[jj-33] + (tmp1 - tmp2) / 4294967296 + local a_hi, a_lo, b_hi, b_lo = W[jj-31], W[jj-30], W[jj-5], W[jj-4] + local b_hi_6, b_hi_19, b_hi_29, b_lo_19, b_lo_29, a_hi_1, a_hi_7, a_hi_8, a_lo_1, a_lo_8 = + b_hi % 2^6, b_hi % 2^19, b_hi % 2^29, b_lo % 2^19, b_lo % 2^29, a_hi % 2^1, a_hi % 2^7, a_hi % 2^8, a_lo % 2^1, a_lo % 2^8 + local tmp1 = XOR((a_lo - a_lo_1) / 2^1 + a_hi_1 * 2^31, (a_lo - a_lo_8) / 2^8 + a_hi_8 * 2^24, (a_lo - a_lo % 2^7) / 2^7 + a_hi_7 * 2^25) % 2^32 + + XOR((b_lo - b_lo_19) / 2^19 + b_hi_19 * 2^13, b_lo_29 * 2^3 + (b_hi - b_hi_29) / 2^29, (b_lo - b_lo % 2^6) / 2^6 + b_hi_6 * 2^26) % 2^32 + + W[jj-14] + W[jj-32] + local tmp2 = tmp1 % 2^32 + W[jj-1] = (XOR((a_hi - a_hi_1) / 2^1 + a_lo_1 * 2^31, (a_hi - a_hi_8) / 2^8 + a_lo_8 * 2^24, (a_hi - a_hi_7) / 2^7) + + XOR((b_hi - b_hi_19) / 2^19 + b_lo_19 * 2^13, b_hi_29 * 2^3 + (b_lo - b_lo_29) / 2^29, (b_hi - b_hi_6) / 2^6) + + W[jj-15] + W[jj-33] + (tmp1 - tmp2) / 2^32) % 2^32 W[jj] = tmp2 end 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 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 for j = 1, 80 do local jj = 2*j - local tmp1 = XOR(SHR(e_lo, 14) + SHL(e_hi, 18), SHR(e_lo, 18) + SHL(e_hi, 14), SHL(e_lo, 23) + SHR(e_hi, 9)) % 4294967296 + (AND(e_lo, f_lo) + AND(-1-e_lo, g_lo)) % 4294967296 + h_lo + K_lo[j] + W[jj] - local z_lo = tmp1 % 4294967296 - local z_hi = XOR(SHR(e_hi, 14) + SHL(e_lo, 18), SHR(e_hi, 18) + SHL(e_lo, 14), SHL(e_hi, 23) + SHR(e_lo, 9)) + AND(e_hi, f_hi) + AND(-1-e_hi, g_hi) + h_hi + K_hi[j] + W[jj-1] + (tmp1 - z_lo) / 4294967296 - h_lo = g_lo - h_hi = g_hi - g_lo = f_lo - g_hi = f_hi - f_lo = e_lo - f_hi = e_hi + local e_lo_9, e_lo_14, e_lo_18, e_hi_9, e_hi_14, e_hi_18 = e_lo % 2^9, e_lo % 2^14, e_lo % 2^18, e_hi % 2^9, e_hi % 2^14, e_hi % 2^18 + local tmp1 = (AND(e_lo, f_lo) + AND(-1-e_lo, g_lo)) % 2^32 + h_lo + K_lo[j] + W[jj] + + XOR((e_lo - e_lo_14) / 2^14 + e_hi_14 * 2^18, (e_lo - e_lo_18) / 2^18 + e_hi_18 * 2^14, e_lo_9 * 2^23 + (e_hi - e_hi_9) / 2^9) % 2^32 + local z_lo = tmp1 % 2^32 + local z_hi = AND(e_hi, f_hi) + AND(-1-e_hi, g_hi) + h_hi + K_hi[j] + W[jj-1] + (tmp1 - z_lo) / 2^32 + + XOR((e_hi - e_hi_14) / 2^14 + e_lo_14 * 2^18, (e_hi - e_hi_18) / 2^18 + e_lo_18 * 2^14, e_hi_9 * 2^23 + (e_lo - e_lo_9) / 2^9) + h_lo = g_lo; h_hi = g_hi + g_lo = f_lo; g_hi = f_hi + f_lo = e_lo; f_hi = e_hi tmp1 = z_lo + d_lo - e_lo = tmp1 % 4294967296 - e_hi = z_hi + d_hi + (tmp1 - e_lo) / 4294967296 - d_lo = c_lo - d_hi = c_hi - c_lo = b_lo - c_hi = b_hi - b_lo = a_lo - b_hi = a_hi - tmp1 = z_lo + (AND(d_lo, c_lo) + AND(b_lo, XOR(d_lo, c_lo))) % 4294967296 + XOR(SHR(b_lo, 28) + SHL(b_hi, 4), SHL(b_lo, 30) + SHR(b_hi, 2), SHL(b_lo, 25) + SHR(b_hi, 7)) % 4294967296 - a_lo = tmp1 % 4294967296 - a_hi = z_hi + (AND(d_hi, c_hi) + AND(b_hi, XOR(d_hi, c_hi))) + XOR(SHR(b_hi, 28) + SHL(b_lo, 4), SHL(b_hi, 30) + SHR(b_lo, 2), SHL(b_hi, 25) + SHR(b_lo, 7)) + (tmp1 - a_lo) / 4294967296 + e_lo = tmp1 % 2^32 + e_hi = (z_hi + d_hi + (tmp1 - e_lo) / 2^32) % 2^32 + d_lo = c_lo; d_hi = c_hi + c_lo = b_lo; c_hi = b_hi + b_lo = a_lo; b_hi = a_hi + local b_lo_2, b_lo_7, b_lo_28, b_hi_2, b_hi_7, b_hi_28 = b_lo % 2^2, b_lo % 2^7, b_lo % 2^28, b_hi % 2^2, b_hi % 2^7, b_hi % 2^28 + tmp1 = z_lo + (AND(d_lo, c_lo) + AND(b_lo, XOR(d_lo, c_lo))) % 2^32 + + XOR((b_lo - b_lo_28) / 2^28 + b_hi_28 * 2^4, b_lo_2 * 2^30 + (b_hi - b_hi_2) / 2^2, b_lo_7 * 2^25 + (b_hi - b_hi_7) / 2^7) % 2^32 + a_lo = tmp1 % 2^32 + a_hi = (z_hi + AND(d_hi, c_hi) + AND(b_hi, XOR(d_hi, c_hi)) + (tmp1 - a_lo) / 2^32 + + XOR((b_hi - b_hi_28) / 2^28 + b_lo_28 * 2^4, b_hi_2 * 2^30 + (b_lo - b_lo_2) / 2^2, b_hi_7 * 2^25 + (b_lo - b_lo_7) / 2^7)) % 2^32 end a_lo = h1_lo + a_lo - h1_lo = a_lo % 4294967296 - h1_hi = (h1_hi + a_hi + (a_lo - h1_lo) / 4294967296) % 4294967296 + h1_lo = a_lo % 2^32 + h1_hi = (h1_hi + a_hi + (a_lo - h1_lo) / 2^32) % 2^32 a_lo = h2_lo + b_lo - h2_lo = a_lo % 4294967296 - h2_hi = (h2_hi + b_hi + (a_lo - h2_lo) / 4294967296) % 4294967296 + h2_lo = a_lo % 2^32 + h2_hi = (h2_hi + b_hi + (a_lo - h2_lo) / 2^32) % 2^32 a_lo = h3_lo + c_lo - h3_lo = a_lo % 4294967296 - h3_hi = (h3_hi + c_hi + (a_lo - h3_lo) / 4294967296) % 4294967296 + h3_lo = a_lo % 2^32 + h3_hi = (h3_hi + c_hi + (a_lo - h3_lo) / 2^32) % 2^32 a_lo = h4_lo + d_lo - h4_lo = a_lo % 4294967296 - h4_hi = (h4_hi + d_hi + (a_lo - h4_lo) / 4294967296) % 4294967296 + h4_lo = a_lo % 2^32 + h4_hi = (h4_hi + d_hi + (a_lo - h4_lo) / 2^32) % 2^32 a_lo = h5_lo + e_lo - h5_lo = a_lo % 4294967296 - h5_hi = (h5_hi + e_hi + (a_lo - h5_lo) / 4294967296) % 4294967296 + h5_lo = a_lo % 2^32 + h5_hi = (h5_hi + e_hi + (a_lo - h5_lo) / 2^32) % 2^32 a_lo = h6_lo + f_lo - h6_lo = a_lo % 4294967296 - h6_hi = (h6_hi + f_hi + (a_lo - h6_lo) / 4294967296) % 4294967296 + h6_lo = a_lo % 2^32 + h6_hi = (h6_hi + f_hi + (a_lo - h6_lo) / 2^32) % 2^32 a_lo = h7_lo + g_lo - h7_lo = a_lo % 4294967296 - h7_hi = (h7_hi + g_hi + (a_lo - h7_lo) / 4294967296) % 4294967296 + h7_lo = a_lo % 2^32 + h7_hi = (h7_hi + g_hi + (a_lo - h7_lo) / 2^32) % 2^32 a_lo = h8_lo + h_lo - h8_lo = a_lo % 4294967296 - h8_hi = (h8_hi + h_hi + (a_lo - h8_lo) / 4294967296) % 4294967296 + h8_lo = a_lo % 2^32 + h8_hi = (h8_hi + h_hi + (a_lo - h8_lo) / 2^32) % 2^32 end 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 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 end - function md5_feed_64(H, str, offs, size) - -- offs >= 0, size >= 0, size is multiple of 64 - local W, K, md5_next_shift = common_W, md5_K, md5_next_shift - local h1, h2, h3, h4 = H[1], H[2], H[3], H[4] - for pos = offs, offs + size - 1, 64 do - for j = 1, 16 do - pos = pos + 4 - local a, b, c, d = byte(str, pos - 3, pos) - W[j] = ((d * 256 + c) * 256 + b) * 256 + a + + if branch == "LIB32" then + + function md5_feed_64(H, str, offs, size) + -- offs >= 0, size >= 0, size is multiple of 64 + local W, K, md5_next_shift = common_W, md5_K, md5_next_shift + local h1, h2, h3, h4 = H[1], H[2], H[3], H[4] + for pos = offs, offs + size - 1, 64 do + for j = 1, 16 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = ((d * 256 + c) * 256 + b) * 256 + a + end + local a, b, c, d = h1, h2, h3, h4 + local s = 25 + for j = 1, 16 do + local F = ROR(AND(b, c) + AND(-1-b, d) + a + K[j] + W[j], s) + b + s = md5_next_shift[s] + a = d + d = c + c = b + b = F + end + s = 27 + for j = 17, 32 do + local F = ROR(AND(d, b) + AND(-1-d, c) + a + K[j] + W[(5*j-4) % 16 + 1], s) + b + s = md5_next_shift[s] + a = d + d = c + c = b + b = F + end + s = 28 + for j = 33, 48 do + local F = ROR(XOR(XOR(b, c), d) + a + K[j] + W[(3*j+2) % 16 + 1], s) + b + s = md5_next_shift[s] + a = d + d = c + c = b + b = F + end + s = 26 + for j = 49, 64 do + local F = ROR(XOR(c, OR(b, -1-d)) + a + K[j] + W[(j*7-7) % 16 + 1], s) + b + s = md5_next_shift[s] + a = d + d = c + c = b + b = F + end + h1 = (a + h1) % 2^32 + h2 = (b + h2) % 2^32 + h3 = (c + h3) % 2^32 + h4 = (d + h4) % 2^32 end - local a, b, c, d = h1, h2, h3, h4 - local s = 32-7 - for j = 1, 16 do - local F = ROR(AND(b, c) + AND(-1-b, d) + a + K[j] + W[j], s) + b - s = md5_next_shift[s] - a = d - d = c - c = b - b = F - end - s = 32-5 - for j = 17, 32 do - local F = ROR(AND(d, b) + AND(-1-d, c) + a + K[j] + W[(5*j-4) % 16 + 1], s) + b - s = md5_next_shift[s] - a = d - d = c - c = b - b = F - end - s = 32-4 - for j = 33, 48 do - local F = ROR(XOR(XOR(b, c), d) + a + K[j] + W[(3*j+2) % 16 + 1], s) + b - s = md5_next_shift[s] - a = d - d = c - c = b - b = F - end - s = 32-6 - for j = 49, 64 do - local F = ROR(XOR(c, OR(b, -1-d)) + a + K[j] + W[(j*7-7) % 16 + 1], s) + b - s = md5_next_shift[s] - a = d - d = c - c = b - b = F - end - h1 = (a + h1) % 4294967296 - h2 = (b + h2) % 4294967296 - h3 = (c + h3) % 4294967296 - h4 = (d + h4) % 4294967296 + H[1], H[2], H[3], H[4] = h1, h2, h3, h4 end - H[1], H[2], H[3], H[4] = h1, h2, h3, h4 + + elseif branch == "EMUL" then + + function md5_feed_64(H, str, offs, size) + -- offs >= 0, size >= 0, size is multiple of 64 + local W, K, md5_next_shift = common_W, md5_K, md5_next_shift + local h1, h2, h3, h4 = H[1], H[2], H[3], H[4] + for pos = offs, offs + size - 1, 64 do + for j = 1, 16 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = ((d * 256 + c) * 256 + b) * 256 + a + end + local a, b, c, d = h1, h2, h3, h4 + local s = 25 + for j = 1, 16 do + local z = (AND(b, c) + AND(-1-b, d) + a + K[j] + W[j]) % 2^32 / 2^s + local y = z % 1 + s = md5_next_shift[s] + a = d + d = c + c = b + b = y * 2^32 + (z - y) + b + end + s = 27 + for j = 17, 32 do + local z = (AND(d, b) + AND(-1-d, c) + a + K[j] + W[(5*j-4) % 16 + 1]) % 2^32 / 2^s + local y = z % 1 + s = md5_next_shift[s] + a = d + d = c + c = b + b = y * 2^32 + (z - y) + b + end + s = 28 + for j = 33, 48 do + local z = (XOR(XOR(b, c), d) + a + K[j] + W[(3*j+2) % 16 + 1]) % 2^32 / 2^s + local y = z % 1 + s = md5_next_shift[s] + a = d + d = c + c = b + b = y * 2^32 + (z - y) + b + end + s = 26 + for j = 49, 64 do + local z = (XOR(c, OR(b, -1-d)) + a + K[j] + W[(j*7-7) % 16 + 1]) % 2^32 / 2^s + local y = z % 1 + s = md5_next_shift[s] + a = d + d = c + c = b + b = y * 2^32 + (z - y) + b + end + h1 = (a + h1) % 2^32 + h2 = (b + h2) % 2^32 + h3 = (c + h3) % 2^32 + h4 = (d + h4) % 2^32 + end + H[1], H[2], H[3], H[4] = h1, h2, h3, h4 + end + end + function sha1_feed_64(H, str, offs, size) -- offs >= 0, size >= 0, size is multiple of 64 local W = common_W @@ -2063,50 +3453,65 @@ if branch == "LIB32" or branch == "EMUL" then W[j] = ((a * 256 + b) * 256 + c) * 256 + d end for j = 17, 80 do - W[j] = ROL(XOR(W[j-3], W[j-8], W[j-14], W[j-16]), 1) + local a = XOR(W[j-3], W[j-8], W[j-14], W[j-16]) % 2^32 * 2 + local b = a % 2^32 + W[j] = b + (a - b) / 2^32 end local a, b, c, d, e = h1, h2, h3, h4, h5 for j = 1, 20 do - local z = ROL(a, 5) + AND(b, c) + AND(-1-b, d) + 0x5A827999 + W[j] + e -- constant = floor(2^30 * sqrt(2)) + local a5 = a * 2^5 + local z = a5 % 2^32 + z = z + (a5 - z) / 2^32 + AND(b, c) + AND(-1-b, d) + 0x5A827999 + W[j] + e -- constant = floor(2^30 * sqrt(2)) e = d d = c - c = ROR(b, 2) + c = b / 2^2 + c = c % 1 * (2^32 - 1) + c b = a - a = z + a = z % 2^32 end for j = 21, 40 do - local z = ROL(a, 5) + XOR(b, c, d) + 0x6ED9EBA1 + W[j] + e -- 2^30 * sqrt(3) + local a5 = a * 2^5 + local z = a5 % 2^32 + z = z + (a5 - z) / 2^32 + XOR(b, c, d) + 0x6ED9EBA1 + W[j] + e -- 2^30 * sqrt(3) e = d d = c - c = ROR(b, 2) + c = b / 2^2 + c = c % 1 * (2^32 - 1) + c b = a - a = z + a = z % 2^32 end for j = 41, 60 do - local z = ROL(a, 5) + AND(d, c) + AND(b, XOR(d, c)) + 0x8F1BBCDC + W[j] + e -- 2^30 * sqrt(5) + local a5 = a * 2^5 + local z = a5 % 2^32 + z = z + (a5 - z) / 2^32 + AND(d, c) + AND(b, XOR(d, c)) + 0x8F1BBCDC + W[j] + e -- 2^30 * sqrt(5) e = d d = c - c = ROR(b, 2) + c = b / 2^2 + c = c % 1 * (2^32 - 1) + c b = a - a = z + a = z % 2^32 end for j = 61, 80 do - local z = ROL(a, 5) + XOR(b, c, d) + 0xCA62C1D6 + W[j] + e -- 2^30 * sqrt(10) + local a5 = a * 2^5 + local z = a5 % 2^32 + z = z + (a5 - z) / 2^32 + XOR(b, c, d) + 0xCA62C1D6 + W[j] + e -- 2^30 * sqrt(10) e = d d = c - c = ROR(b, 2) + c = b / 2^2 + c = c % 1 * (2^32 - 1) + c b = a - a = z + a = z % 2^32 end - h1 = (a + h1) % 4294967296 - h2 = (b + h2) % 4294967296 - h3 = (c + h3) % 4294967296 - h4 = (d + h4) % 4294967296 - h5 = (e + h5) % 4294967296 + h1 = (a + h1) % 2^32 + h2 = (b + h2) % 2^32 + h3 = (c + h3) % 2^32 + h4 = (d + h4) % 2^32 + h5 = (e + h5) % 2^32 end H[1], H[2], H[3], H[4], H[5] = h1, h2, h3, h4, h5 end + function keccak_feed(lanes_lo, lanes_hi, str, offs, size, block_size_in_bytes) -- This is an example of a Lua function having 79 local variables :-) -- offs >= 0, size >= 0, size is multiple of block_size_in_bytes, block_size_in_bytes is positive multiple of 8 @@ -2260,59 +3665,561 @@ if branch == "LIB32" or branch == "EMUL" then L01_lo = XOR(L01_lo, RC_lo[round_idx]) 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 end - lanes_lo[1] = L01_lo - lanes_hi[1] = L01_hi - lanes_lo[2] = L02_lo - lanes_hi[2] = L02_hi - lanes_lo[3] = L03_lo - lanes_hi[3] = L03_hi - lanes_lo[4] = L04_lo - lanes_hi[4] = L04_hi - lanes_lo[5] = L05_lo - lanes_hi[5] = L05_hi - lanes_lo[6] = L06_lo - lanes_hi[6] = L06_hi - lanes_lo[7] = L07_lo - lanes_hi[7] = L07_hi - lanes_lo[8] = L08_lo - lanes_hi[8] = L08_hi - lanes_lo[9] = L09_lo - lanes_hi[9] = L09_hi - lanes_lo[10] = L10_lo - lanes_hi[10] = L10_hi - lanes_lo[11] = L11_lo - lanes_hi[11] = L11_hi - lanes_lo[12] = L12_lo - lanes_hi[12] = L12_hi - lanes_lo[13] = L13_lo - lanes_hi[13] = L13_hi - lanes_lo[14] = L14_lo - lanes_hi[14] = L14_hi - lanes_lo[15] = L15_lo - lanes_hi[15] = L15_hi - lanes_lo[16] = L16_lo - lanes_hi[16] = L16_hi - lanes_lo[17] = L17_lo - lanes_hi[17] = L17_hi - lanes_lo[18] = L18_lo - lanes_hi[18] = L18_hi - lanes_lo[19] = L19_lo - lanes_hi[19] = L19_hi - lanes_lo[20] = L20_lo - lanes_hi[20] = L20_hi - lanes_lo[21] = L21_lo - lanes_hi[21] = L21_hi - lanes_lo[22] = L22_lo - lanes_hi[22] = L22_hi - lanes_lo[23] = L23_lo - lanes_hi[23] = L23_hi - lanes_lo[24] = L24_lo - lanes_hi[24] = L24_hi - lanes_lo[25] = L25_lo - lanes_hi[25] = L25_hi + lanes_lo[1] = L01_lo; lanes_hi[1] = L01_hi + lanes_lo[2] = L02_lo; lanes_hi[2] = L02_hi + lanes_lo[3] = L03_lo; lanes_hi[3] = L03_hi + lanes_lo[4] = L04_lo; lanes_hi[4] = L04_hi + lanes_lo[5] = L05_lo; lanes_hi[5] = L05_hi + lanes_lo[6] = L06_lo; lanes_hi[6] = L06_hi + lanes_lo[7] = L07_lo; lanes_hi[7] = L07_hi + lanes_lo[8] = L08_lo; lanes_hi[8] = L08_hi + lanes_lo[9] = L09_lo; lanes_hi[9] = L09_hi + lanes_lo[10] = L10_lo; lanes_hi[10] = L10_hi + lanes_lo[11] = L11_lo; lanes_hi[11] = L11_hi + lanes_lo[12] = L12_lo; lanes_hi[12] = L12_hi + lanes_lo[13] = L13_lo; lanes_hi[13] = L13_hi + lanes_lo[14] = L14_lo; lanes_hi[14] = L14_hi + lanes_lo[15] = L15_lo; lanes_hi[15] = L15_hi + lanes_lo[16] = L16_lo; lanes_hi[16] = L16_hi + lanes_lo[17] = L17_lo; lanes_hi[17] = L17_hi + lanes_lo[18] = L18_lo; lanes_hi[18] = L18_hi + lanes_lo[19] = L19_lo; lanes_hi[19] = L19_hi + lanes_lo[20] = L20_lo; lanes_hi[20] = L20_hi + lanes_lo[21] = L21_lo; lanes_hi[21] = L21_hi + lanes_lo[22] = L22_lo; lanes_hi[22] = L22_hi + lanes_lo[23] = L23_lo; lanes_hi[23] = L23_hi + lanes_lo[24] = L24_lo; lanes_hi[24] = L24_hi + lanes_lo[25] = L25_lo; lanes_hi[25] = L25_hi end end + + function blake2s_feed_64(H, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 64 + local W = common_W + 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] + for pos = offs, offs + size - 1, 64 do + if str then + for j = 1, 16 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = ((d * 256 + c) * 256 + b) * 256 + a + end + end + local v0, v1, v2, v3, v4, v5, v6, v7 = h1, h2, h3, h4, h5, h6, h7, h8 + local v8, v9, vA, vB, vC, vD, vE, vF = sha2_H_hi[1], sha2_H_hi[2], sha2_H_hi[3], sha2_H_hi[4], sha2_H_hi[5], sha2_H_hi[6], sha2_H_hi[7], sha2_H_hi[8] + bytes_compressed = bytes_compressed + (last_block_size or 64) + local t0 = bytes_compressed % 2^32 + local t1 = (bytes_compressed - t0) / 2^32 + vC = XOR(vC, t0) -- t0 = low_4_bytes(bytes_compressed) + vD = XOR(vD, t1) -- t1 = high_4_bytes(bytes_compressed) + if last_block_size then -- flag f0 + vE = -1 - vE + end + if is_last_node then -- flag f1 + vF = -1 - vF + end + for j = 1, 10 do + local row = sigma[j] + v0 = v0 + v4 + W[row[1]] + vC = XOR(vC, v0) % 2^32 / 2^16 + vC = vC % 1 * (2^32 - 1) + vC + v8 = v8 + vC + v4 = XOR(v4, v8) % 2^32 / 2^12 + v4 = v4 % 1 * (2^32 - 1) + v4 + v0 = v0 + v4 + W[row[2]] + vC = XOR(vC, v0) % 2^32 / 2^8 + vC = vC % 1 * (2^32 - 1) + vC + v8 = v8 + vC + v4 = XOR(v4, v8) % 2^32 / 2^7 + v4 = v4 % 1 * (2^32 - 1) + v4 + v1 = v1 + v5 + W[row[3]] + vD = XOR(vD, v1) % 2^32 / 2^16 + vD = vD % 1 * (2^32 - 1) + vD + v9 = v9 + vD + v5 = XOR(v5, v9) % 2^32 / 2^12 + v5 = v5 % 1 * (2^32 - 1) + v5 + v1 = v1 + v5 + W[row[4]] + vD = XOR(vD, v1) % 2^32 / 2^8 + vD = vD % 1 * (2^32 - 1) + vD + v9 = v9 + vD + v5 = XOR(v5, v9) % 2^32 / 2^7 + v5 = v5 % 1 * (2^32 - 1) + v5 + v2 = v2 + v6 + W[row[5]] + vE = XOR(vE, v2) % 2^32 / 2^16 + vE = vE % 1 * (2^32 - 1) + vE + vA = vA + vE + v6 = XOR(v6, vA) % 2^32 / 2^12 + v6 = v6 % 1 * (2^32 - 1) + v6 + v2 = v2 + v6 + W[row[6]] + vE = XOR(vE, v2) % 2^32 / 2^8 + vE = vE % 1 * (2^32 - 1) + vE + vA = vA + vE + v6 = XOR(v6, vA) % 2^32 / 2^7 + v6 = v6 % 1 * (2^32 - 1) + v6 + v3 = v3 + v7 + W[row[7]] + vF = XOR(vF, v3) % 2^32 / 2^16 + vF = vF % 1 * (2^32 - 1) + vF + vB = vB + vF + v7 = XOR(v7, vB) % 2^32 / 2^12 + v7 = v7 % 1 * (2^32 - 1) + v7 + v3 = v3 + v7 + W[row[8]] + vF = XOR(vF, v3) % 2^32 / 2^8 + vF = vF % 1 * (2^32 - 1) + vF + vB = vB + vF + v7 = XOR(v7, vB) % 2^32 / 2^7 + v7 = v7 % 1 * (2^32 - 1) + v7 + v0 = v0 + v5 + W[row[9]] + vF = XOR(vF, v0) % 2^32 / 2^16 + vF = vF % 1 * (2^32 - 1) + vF + vA = vA + vF + v5 = XOR(v5, vA) % 2^32 / 2^12 + v5 = v5 % 1 * (2^32 - 1) + v5 + v0 = v0 + v5 + W[row[10]] + vF = XOR(vF, v0) % 2^32 / 2^8 + vF = vF % 1 * (2^32 - 1) + vF + vA = vA + vF + v5 = XOR(v5, vA) % 2^32 / 2^7 + v5 = v5 % 1 * (2^32 - 1) + v5 + v1 = v1 + v6 + W[row[11]] + vC = XOR(vC, v1) % 2^32 / 2^16 + vC = vC % 1 * (2^32 - 1) + vC + vB = vB + vC + v6 = XOR(v6, vB) % 2^32 / 2^12 + v6 = v6 % 1 * (2^32 - 1) + v6 + v1 = v1 + v6 + W[row[12]] + vC = XOR(vC, v1) % 2^32 / 2^8 + vC = vC % 1 * (2^32 - 1) + vC + vB = vB + vC + v6 = XOR(v6, vB) % 2^32 / 2^7 + v6 = v6 % 1 * (2^32 - 1) + v6 + v2 = v2 + v7 + W[row[13]] + vD = XOR(vD, v2) % 2^32 / 2^16 + vD = vD % 1 * (2^32 - 1) + vD + v8 = v8 + vD + v7 = XOR(v7, v8) % 2^32 / 2^12 + v7 = v7 % 1 * (2^32 - 1) + v7 + v2 = v2 + v7 + W[row[14]] + vD = XOR(vD, v2) % 2^32 / 2^8 + vD = vD % 1 * (2^32 - 1) + vD + v8 = v8 + vD + v7 = XOR(v7, v8) % 2^32 / 2^7 + v7 = v7 % 1 * (2^32 - 1) + v7 + v3 = v3 + v4 + W[row[15]] + vE = XOR(vE, v3) % 2^32 / 2^16 + vE = vE % 1 * (2^32 - 1) + vE + v9 = v9 + vE + v4 = XOR(v4, v9) % 2^32 / 2^12 + v4 = v4 % 1 * (2^32 - 1) + v4 + v3 = v3 + v4 + W[row[16]] + vE = XOR(vE, v3) % 2^32 / 2^8 + vE = vE % 1 * (2^32 - 1) + vE + v9 = v9 + vE + v4 = XOR(v4, v9) % 2^32 / 2^7 + v4 = v4 % 1 * (2^32 - 1) + v4 + end + h1 = XOR(h1, v0, v8) + h2 = XOR(h2, v1, v9) + h3 = XOR(h3, v2, vA) + h4 = XOR(h4, v3, vB) + h5 = XOR(h5, v4, vC) + h6 = XOR(h6, v5, vD) + h7 = XOR(h7, v6, vE) + h8 = XOR(h8, v7, vF) + end + H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8 + return bytes_compressed + end + + + function blake2b_feed_128(H_lo, H_hi, str, offs, size, bytes_compressed, last_block_size, is_last_node) + -- offs >= 0, size >= 0, size is multiple of 128 + local W = common_W + 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] + 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] + for pos = offs, offs + size - 1, 128 do + if str then + for j = 1, 32 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = ((d * 256 + c) * 256 + b) * 256 + a + end + end + local v0_lo, v1_lo, v2_lo, v3_lo, v4_lo, v5_lo, v6_lo, v7_lo = h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo + local v0_hi, v1_hi, v2_hi, v3_hi, v4_hi, v5_hi, v6_hi, v7_hi = h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi + local v8_lo, v9_lo, vA_lo, vB_lo, vC_lo, vD_lo, vE_lo, vF_lo = sha2_H_lo[1], sha2_H_lo[2], sha2_H_lo[3], sha2_H_lo[4], sha2_H_lo[5], sha2_H_lo[6], sha2_H_lo[7], sha2_H_lo[8] + local v8_hi, v9_hi, vA_hi, vB_hi, vC_hi, vD_hi, vE_hi, vF_hi = sha2_H_hi[1], sha2_H_hi[2], sha2_H_hi[3], sha2_H_hi[4], sha2_H_hi[5], sha2_H_hi[6], sha2_H_hi[7], sha2_H_hi[8] + bytes_compressed = bytes_compressed + (last_block_size or 128) + local t0_lo = bytes_compressed % 2^32 + local t0_hi = (bytes_compressed - t0_lo) / 2^32 + vC_lo = XOR(vC_lo, t0_lo) -- t0 = low_8_bytes(bytes_compressed) + vC_hi = XOR(vC_hi, t0_hi) + -- t1 = high_8_bytes(bytes_compressed) = 0, message length is always below 2^53 bytes + if last_block_size then -- flag f0 + vE_lo = -1 - vE_lo + vE_hi = -1 - vE_hi + end + if is_last_node then -- flag f1 + vF_lo = -1 - vF_lo + vF_hi = -1 - vF_hi + end + for j = 1, 12 do + local row = sigma[j] + local k = row[1] * 2 + local z = v0_lo % 2^32 + v4_lo % 2^32 + W[k-1] + v0_lo = z % 2^32 + v0_hi = v0_hi + v4_hi + (z - v0_lo) / 2^32 + W[k] + vC_lo, vC_hi = XOR(vC_hi, v0_hi), XOR(vC_lo, v0_lo) + z = v8_lo % 2^32 + vC_lo % 2^32 + v8_lo = z % 2^32 + v8_hi = v8_hi + vC_hi + (z - v8_lo) / 2^32 + v4_lo, v4_hi = XOR(v4_lo, v8_lo), XOR(v4_hi, v8_hi) + local z_lo, z_hi = v4_lo % 2^24, v4_hi % 2^24 + v4_lo, v4_hi = (v4_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v4_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[2] * 2 + z = v0_lo % 2^32 + v4_lo % 2^32 + W[k-1] + v0_lo = z % 2^32 + v0_hi = v0_hi + v4_hi + (z - v0_lo) / 2^32 + W[k] + vC_lo, vC_hi = XOR(vC_lo, v0_lo), XOR(vC_hi, v0_hi) + z_lo, z_hi = vC_lo % 2^16, vC_hi % 2^16 + vC_lo, vC_hi = (vC_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vC_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = v8_lo % 2^32 + vC_lo % 2^32 + v8_lo = z % 2^32 + v8_hi = v8_hi + vC_hi + (z - v8_lo) / 2^32 + v4_lo, v4_hi = XOR(v4_lo, v8_lo), XOR(v4_hi, v8_hi) + z_lo, z_hi = v4_lo % 2^31, v4_hi % 2^31 + v4_lo, v4_hi = z_lo * 2^1 + (v4_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v4_lo - z_lo) / 2^31 % 2^1 + k = row[3] * 2 + z = v1_lo % 2^32 + v5_lo % 2^32 + W[k-1] + v1_lo = z % 2^32 + v1_hi = v1_hi + v5_hi + (z - v1_lo) / 2^32 + W[k] + vD_lo, vD_hi = XOR(vD_hi, v1_hi), XOR(vD_lo, v1_lo) + z = v9_lo % 2^32 + vD_lo % 2^32 + v9_lo = z % 2^32 + v9_hi = v9_hi + vD_hi + (z - v9_lo) / 2^32 + v5_lo, v5_hi = XOR(v5_lo, v9_lo), XOR(v5_hi, v9_hi) + z_lo, z_hi = v5_lo % 2^24, v5_hi % 2^24 + v5_lo, v5_hi = (v5_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v5_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[4] * 2 + z = v1_lo % 2^32 + v5_lo % 2^32 + W[k-1] + v1_lo = z % 2^32 + v1_hi = v1_hi + v5_hi + (z - v1_lo) / 2^32 + W[k] + vD_lo, vD_hi = XOR(vD_lo, v1_lo), XOR(vD_hi, v1_hi) + z_lo, z_hi = vD_lo % 2^16, vD_hi % 2^16 + vD_lo, vD_hi = (vD_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vD_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = v9_lo % 2^32 + vD_lo % 2^32 + v9_lo = z % 2^32 + v9_hi = v9_hi + vD_hi + (z - v9_lo) / 2^32 + v5_lo, v5_hi = XOR(v5_lo, v9_lo), XOR(v5_hi, v9_hi) + z_lo, z_hi = v5_lo % 2^31, v5_hi % 2^31 + v5_lo, v5_hi = z_lo * 2^1 + (v5_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v5_lo - z_lo) / 2^31 % 2^1 + k = row[5] * 2 + z = v2_lo % 2^32 + v6_lo % 2^32 + W[k-1] + v2_lo = z % 2^32 + v2_hi = v2_hi + v6_hi + (z - v2_lo) / 2^32 + W[k] + vE_lo, vE_hi = XOR(vE_hi, v2_hi), XOR(vE_lo, v2_lo) + z = vA_lo % 2^32 + vE_lo % 2^32 + vA_lo = z % 2^32 + vA_hi = vA_hi + vE_hi + (z - vA_lo) / 2^32 + v6_lo, v6_hi = XOR(v6_lo, vA_lo), XOR(v6_hi, vA_hi) + z_lo, z_hi = v6_lo % 2^24, v6_hi % 2^24 + v6_lo, v6_hi = (v6_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v6_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[6] * 2 + z = v2_lo % 2^32 + v6_lo % 2^32 + W[k-1] + v2_lo = z % 2^32 + v2_hi = v2_hi + v6_hi + (z - v2_lo) / 2^32 + W[k] + vE_lo, vE_hi = XOR(vE_lo, v2_lo), XOR(vE_hi, v2_hi) + z_lo, z_hi = vE_lo % 2^16, vE_hi % 2^16 + vE_lo, vE_hi = (vE_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vE_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = vA_lo % 2^32 + vE_lo % 2^32 + vA_lo = z % 2^32 + vA_hi = vA_hi + vE_hi + (z - vA_lo) / 2^32 + v6_lo, v6_hi = XOR(v6_lo, vA_lo), XOR(v6_hi, vA_hi) + z_lo, z_hi = v6_lo % 2^31, v6_hi % 2^31 + v6_lo, v6_hi = z_lo * 2^1 + (v6_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v6_lo - z_lo) / 2^31 % 2^1 + k = row[7] * 2 + z = v3_lo % 2^32 + v7_lo % 2^32 + W[k-1] + v3_lo = z % 2^32 + v3_hi = v3_hi + v7_hi + (z - v3_lo) / 2^32 + W[k] + vF_lo, vF_hi = XOR(vF_hi, v3_hi), XOR(vF_lo, v3_lo) + z = vB_lo % 2^32 + vF_lo % 2^32 + vB_lo = z % 2^32 + vB_hi = vB_hi + vF_hi + (z - vB_lo) / 2^32 + v7_lo, v7_hi = XOR(v7_lo, vB_lo), XOR(v7_hi, vB_hi) + z_lo, z_hi = v7_lo % 2^24, v7_hi % 2^24 + v7_lo, v7_hi = (v7_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v7_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[8] * 2 + z = v3_lo % 2^32 + v7_lo % 2^32 + W[k-1] + v3_lo = z % 2^32 + v3_hi = v3_hi + v7_hi + (z - v3_lo) / 2^32 + W[k] + vF_lo, vF_hi = XOR(vF_lo, v3_lo), XOR(vF_hi, v3_hi) + z_lo, z_hi = vF_lo % 2^16, vF_hi % 2^16 + vF_lo, vF_hi = (vF_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vF_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = vB_lo % 2^32 + vF_lo % 2^32 + vB_lo = z % 2^32 + vB_hi = vB_hi + vF_hi + (z - vB_lo) / 2^32 + v7_lo, v7_hi = XOR(v7_lo, vB_lo), XOR(v7_hi, vB_hi) + z_lo, z_hi = v7_lo % 2^31, v7_hi % 2^31 + v7_lo, v7_hi = z_lo * 2^1 + (v7_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v7_lo - z_lo) / 2^31 % 2^1 + k = row[9] * 2 + z = v0_lo % 2^32 + v5_lo % 2^32 + W[k-1] + v0_lo = z % 2^32 + v0_hi = v0_hi + v5_hi + (z - v0_lo) / 2^32 + W[k] + vF_lo, vF_hi = XOR(vF_hi, v0_hi), XOR(vF_lo, v0_lo) + z = vA_lo % 2^32 + vF_lo % 2^32 + vA_lo = z % 2^32 + vA_hi = vA_hi + vF_hi + (z - vA_lo) / 2^32 + v5_lo, v5_hi = XOR(v5_lo, vA_lo), XOR(v5_hi, vA_hi) + z_lo, z_hi = v5_lo % 2^24, v5_hi % 2^24 + v5_lo, v5_hi = (v5_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v5_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[10] * 2 + z = v0_lo % 2^32 + v5_lo % 2^32 + W[k-1] + v0_lo = z % 2^32 + v0_hi = v0_hi + v5_hi + (z - v0_lo) / 2^32 + W[k] + vF_lo, vF_hi = XOR(vF_lo, v0_lo), XOR(vF_hi, v0_hi) + z_lo, z_hi = vF_lo % 2^16, vF_hi % 2^16 + vF_lo, vF_hi = (vF_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vF_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = vA_lo % 2^32 + vF_lo % 2^32 + vA_lo = z % 2^32 + vA_hi = vA_hi + vF_hi + (z - vA_lo) / 2^32 + v5_lo, v5_hi = XOR(v5_lo, vA_lo), XOR(v5_hi, vA_hi) + z_lo, z_hi = v5_lo % 2^31, v5_hi % 2^31 + v5_lo, v5_hi = z_lo * 2^1 + (v5_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v5_lo - z_lo) / 2^31 % 2^1 + k = row[11] * 2 + z = v1_lo % 2^32 + v6_lo % 2^32 + W[k-1] + v1_lo = z % 2^32 + v1_hi = v1_hi + v6_hi + (z - v1_lo) / 2^32 + W[k] + vC_lo, vC_hi = XOR(vC_hi, v1_hi), XOR(vC_lo, v1_lo) + z = vB_lo % 2^32 + vC_lo % 2^32 + vB_lo = z % 2^32 + vB_hi = vB_hi + vC_hi + (z - vB_lo) / 2^32 + v6_lo, v6_hi = XOR(v6_lo, vB_lo), XOR(v6_hi, vB_hi) + z_lo, z_hi = v6_lo % 2^24, v6_hi % 2^24 + v6_lo, v6_hi = (v6_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v6_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[12] * 2 + z = v1_lo % 2^32 + v6_lo % 2^32 + W[k-1] + v1_lo = z % 2^32 + v1_hi = v1_hi + v6_hi + (z - v1_lo) / 2^32 + W[k] + vC_lo, vC_hi = XOR(vC_lo, v1_lo), XOR(vC_hi, v1_hi) + z_lo, z_hi = vC_lo % 2^16, vC_hi % 2^16 + vC_lo, vC_hi = (vC_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vC_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = vB_lo % 2^32 + vC_lo % 2^32 + vB_lo = z % 2^32 + vB_hi = vB_hi + vC_hi + (z - vB_lo) / 2^32 + v6_lo, v6_hi = XOR(v6_lo, vB_lo), XOR(v6_hi, vB_hi) + z_lo, z_hi = v6_lo % 2^31, v6_hi % 2^31 + v6_lo, v6_hi = z_lo * 2^1 + (v6_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v6_lo - z_lo) / 2^31 % 2^1 + k = row[13] * 2 + z = v2_lo % 2^32 + v7_lo % 2^32 + W[k-1] + v2_lo = z % 2^32 + v2_hi = v2_hi + v7_hi + (z - v2_lo) / 2^32 + W[k] + vD_lo, vD_hi = XOR(vD_hi, v2_hi), XOR(vD_lo, v2_lo) + z = v8_lo % 2^32 + vD_lo % 2^32 + v8_lo = z % 2^32 + v8_hi = v8_hi + vD_hi + (z - v8_lo) / 2^32 + v7_lo, v7_hi = XOR(v7_lo, v8_lo), XOR(v7_hi, v8_hi) + z_lo, z_hi = v7_lo % 2^24, v7_hi % 2^24 + v7_lo, v7_hi = (v7_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v7_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[14] * 2 + z = v2_lo % 2^32 + v7_lo % 2^32 + W[k-1] + v2_lo = z % 2^32 + v2_hi = v2_hi + v7_hi + (z - v2_lo) / 2^32 + W[k] + vD_lo, vD_hi = XOR(vD_lo, v2_lo), XOR(vD_hi, v2_hi) + z_lo, z_hi = vD_lo % 2^16, vD_hi % 2^16 + vD_lo, vD_hi = (vD_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vD_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = v8_lo % 2^32 + vD_lo % 2^32 + v8_lo = z % 2^32 + v8_hi = v8_hi + vD_hi + (z - v8_lo) / 2^32 + v7_lo, v7_hi = XOR(v7_lo, v8_lo), XOR(v7_hi, v8_hi) + z_lo, z_hi = v7_lo % 2^31, v7_hi % 2^31 + v7_lo, v7_hi = z_lo * 2^1 + (v7_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v7_lo - z_lo) / 2^31 % 2^1 + k = row[15] * 2 + z = v3_lo % 2^32 + v4_lo % 2^32 + W[k-1] + v3_lo = z % 2^32 + v3_hi = v3_hi + v4_hi + (z - v3_lo) / 2^32 + W[k] + vE_lo, vE_hi = XOR(vE_hi, v3_hi), XOR(vE_lo, v3_lo) + z = v9_lo % 2^32 + vE_lo % 2^32 + v9_lo = z % 2^32 + v9_hi = v9_hi + vE_hi + (z - v9_lo) / 2^32 + v4_lo, v4_hi = XOR(v4_lo, v9_lo), XOR(v4_hi, v9_hi) + z_lo, z_hi = v4_lo % 2^24, v4_hi % 2^24 + v4_lo, v4_hi = (v4_lo - z_lo) / 2^24 % 2^8 + z_hi * 2^8, (v4_hi - z_hi) / 2^24 % 2^8 + z_lo * 2^8 + k = row[16] * 2 + z = v3_lo % 2^32 + v4_lo % 2^32 + W[k-1] + v3_lo = z % 2^32 + v3_hi = v3_hi + v4_hi + (z - v3_lo) / 2^32 + W[k] + vE_lo, vE_hi = XOR(vE_lo, v3_lo), XOR(vE_hi, v3_hi) + z_lo, z_hi = vE_lo % 2^16, vE_hi % 2^16 + vE_lo, vE_hi = (vE_lo - z_lo) / 2^16 % 2^16 + z_hi * 2^16, (vE_hi - z_hi) / 2^16 % 2^16 + z_lo * 2^16 + z = v9_lo % 2^32 + vE_lo % 2^32 + v9_lo = z % 2^32 + v9_hi = v9_hi + vE_hi + (z - v9_lo) / 2^32 + v4_lo, v4_hi = XOR(v4_lo, v9_lo), XOR(v4_hi, v9_hi) + z_lo, z_hi = v4_lo % 2^31, v4_hi % 2^31 + v4_lo, v4_hi = z_lo * 2^1 + (v4_hi - z_hi) / 2^31 % 2^1, z_hi * 2^1 + (v4_lo - z_lo) / 2^31 % 2^1 + end + h1_lo = XOR(h1_lo, v0_lo, v8_lo) % 2^32 + h2_lo = XOR(h2_lo, v1_lo, v9_lo) % 2^32 + h3_lo = XOR(h3_lo, v2_lo, vA_lo) % 2^32 + h4_lo = XOR(h4_lo, v3_lo, vB_lo) % 2^32 + h5_lo = XOR(h5_lo, v4_lo, vC_lo) % 2^32 + h6_lo = XOR(h6_lo, v5_lo, vD_lo) % 2^32 + h7_lo = XOR(h7_lo, v6_lo, vE_lo) % 2^32 + h8_lo = XOR(h8_lo, v7_lo, vF_lo) % 2^32 + h1_hi = XOR(h1_hi, v0_hi, v8_hi) % 2^32 + h2_hi = XOR(h2_hi, v1_hi, v9_hi) % 2^32 + h3_hi = XOR(h3_hi, v2_hi, vA_hi) % 2^32 + h4_hi = XOR(h4_hi, v3_hi, vB_hi) % 2^32 + h5_hi = XOR(h5_hi, v4_hi, vC_hi) % 2^32 + h6_hi = XOR(h6_hi, v5_hi, vD_hi) % 2^32 + h7_hi = XOR(h7_hi, v6_hi, vE_hi) % 2^32 + h8_hi = XOR(h8_hi, v7_hi, vF_hi) % 2^32 + end + 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 + 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 + return bytes_compressed + end + + + function blake3_feed_64(str, offs, size, flags, chunk_index, H_in, H_out, wide_output, block_length) + -- offs >= 0, size >= 0, size is multiple of 64 + block_length = block_length or 64 + local W = common_W + local h1, h2, h3, h4, h5, h6, h7, h8 = H_in[1], H_in[2], H_in[3], H_in[4], H_in[5], H_in[6], H_in[7], H_in[8] + H_out = H_out or H_in + for pos = offs, offs + size - 1, 64 do + if str then + for j = 1, 16 do + pos = pos + 4 + local a, b, c, d = byte(str, pos - 3, pos) + W[j] = ((d * 256 + c) * 256 + b) * 256 + a + end + end + local v0, v1, v2, v3, v4, v5, v6, v7 = h1, h2, h3, h4, h5, h6, h7, h8 + local v8, v9, vA, vB = sha2_H_hi[1], sha2_H_hi[2], sha2_H_hi[3], sha2_H_hi[4] + local vC = chunk_index % 2^32 -- t0 = low_4_bytes(chunk_index) + local vD = (chunk_index - vC) / 2^32 -- t1 = high_4_bytes(chunk_index) + local vE, vF = block_length, flags + for j = 1, 7 do + v0 = v0 + v4 + W[perm_blake3[j]] + vC = XOR(vC, v0) % 2^32 / 2^16 + vC = vC % 1 * (2^32 - 1) + vC + v8 = v8 + vC + v4 = XOR(v4, v8) % 2^32 / 2^12 + v4 = v4 % 1 * (2^32 - 1) + v4 + v0 = v0 + v4 + W[perm_blake3[j + 14]] + vC = XOR(vC, v0) % 2^32 / 2^8 + vC = vC % 1 * (2^32 - 1) + vC + v8 = v8 + vC + v4 = XOR(v4, v8) % 2^32 / 2^7 + v4 = v4 % 1 * (2^32 - 1) + v4 + v1 = v1 + v5 + W[perm_blake3[j + 1]] + vD = XOR(vD, v1) % 2^32 / 2^16 + vD = vD % 1 * (2^32 - 1) + vD + v9 = v9 + vD + v5 = XOR(v5, v9) % 2^32 / 2^12 + v5 = v5 % 1 * (2^32 - 1) + v5 + v1 = v1 + v5 + W[perm_blake3[j + 2]] + vD = XOR(vD, v1) % 2^32 / 2^8 + vD = vD % 1 * (2^32 - 1) + vD + v9 = v9 + vD + v5 = XOR(v5, v9) % 2^32 / 2^7 + v5 = v5 % 1 * (2^32 - 1) + v5 + v2 = v2 + v6 + W[perm_blake3[j + 16]] + vE = XOR(vE, v2) % 2^32 / 2^16 + vE = vE % 1 * (2^32 - 1) + vE + vA = vA + vE + v6 = XOR(v6, vA) % 2^32 / 2^12 + v6 = v6 % 1 * (2^32 - 1) + v6 + v2 = v2 + v6 + W[perm_blake3[j + 7]] + vE = XOR(vE, v2) % 2^32 / 2^8 + vE = vE % 1 * (2^32 - 1) + vE + vA = vA + vE + v6 = XOR(v6, vA) % 2^32 / 2^7 + v6 = v6 % 1 * (2^32 - 1) + v6 + v3 = v3 + v7 + W[perm_blake3[j + 15]] + vF = XOR(vF, v3) % 2^32 / 2^16 + vF = vF % 1 * (2^32 - 1) + vF + vB = vB + vF + v7 = XOR(v7, vB) % 2^32 / 2^12 + v7 = v7 % 1 * (2^32 - 1) + v7 + v3 = v3 + v7 + W[perm_blake3[j + 17]] + vF = XOR(vF, v3) % 2^32 / 2^8 + vF = vF % 1 * (2^32 - 1) + vF + vB = vB + vF + v7 = XOR(v7, vB) % 2^32 / 2^7 + v7 = v7 % 1 * (2^32 - 1) + v7 + v0 = v0 + v5 + W[perm_blake3[j + 21]] + vF = XOR(vF, v0) % 2^32 / 2^16 + vF = vF % 1 * (2^32 - 1) + vF + vA = vA + vF + v5 = XOR(v5, vA) % 2^32 / 2^12 + v5 = v5 % 1 * (2^32 - 1) + v5 + v0 = v0 + v5 + W[perm_blake3[j + 5]] + vF = XOR(vF, v0) % 2^32 / 2^8 + vF = vF % 1 * (2^32 - 1) + vF + vA = vA + vF + v5 = XOR(v5, vA) % 2^32 / 2^7 + v5 = v5 % 1 * (2^32 - 1) + v5 + v1 = v1 + v6 + W[perm_blake3[j + 3]] + vC = XOR(vC, v1) % 2^32 / 2^16 + vC = vC % 1 * (2^32 - 1) + vC + vB = vB + vC + v6 = XOR(v6, vB) % 2^32 / 2^12 + v6 = v6 % 1 * (2^32 - 1) + v6 + v1 = v1 + v6 + W[perm_blake3[j + 6]] + vC = XOR(vC, v1) % 2^32 / 2^8 + vC = vC % 1 * (2^32 - 1) + vC + vB = vB + vC + v6 = XOR(v6, vB) % 2^32 / 2^7 + v6 = v6 % 1 * (2^32 - 1) + v6 + v2 = v2 + v7 + W[perm_blake3[j + 4]] + vD = XOR(vD, v2) % 2^32 / 2^16 + vD = vD % 1 * (2^32 - 1) + vD + v8 = v8 + vD + v7 = XOR(v7, v8) % 2^32 / 2^12 + v7 = v7 % 1 * (2^32 - 1) + v7 + v2 = v2 + v7 + W[perm_blake3[j + 18]] + vD = XOR(vD, v2) % 2^32 / 2^8 + vD = vD % 1 * (2^32 - 1) + vD + v8 = v8 + vD + v7 = XOR(v7, v8) % 2^32 / 2^7 + v7 = v7 % 1 * (2^32 - 1) + v7 + v3 = v3 + v4 + W[perm_blake3[j + 19]] + vE = XOR(vE, v3) % 2^32 / 2^16 + vE = vE % 1 * (2^32 - 1) + vE + v9 = v9 + vE + v4 = XOR(v4, v9) % 2^32 / 2^12 + v4 = v4 % 1 * (2^32 - 1) + v4 + v3 = v3 + v4 + W[perm_blake3[j + 20]] + vE = XOR(vE, v3) % 2^32 / 2^8 + vE = vE % 1 * (2^32 - 1) + vE + v9 = v9 + vE + v4 = XOR(v4, v9) % 2^32 / 2^7 + v4 = v4 % 1 * (2^32 - 1) + v4 + end + if wide_output then + H_out[ 9] = XOR(h1, v8) + H_out[10] = XOR(h2, v9) + H_out[11] = XOR(h3, vA) + H_out[12] = XOR(h4, vB) + H_out[13] = XOR(h5, vC) + H_out[14] = XOR(h6, vD) + H_out[15] = XOR(h7, vE) + H_out[16] = XOR(h8, vF) + end + h1 = XOR(v0, v8) + h2 = XOR(v1, v9) + h3 = XOR(v2, vA) + h4 = XOR(v3, vB) + h5 = XOR(v4, vC) + h6 = XOR(v5, vD) + h7 = XOR(v6, vE) + h8 = XOR(v7, vF) + end + H_out[1], H_out[2], H_out[3], H_out[4], H_out[5], H_out[6], H_out[7], H_out[8] = h1, h2, h3, h4, h5, h6, h7, h8 + end + end @@ -2382,15 +4289,15 @@ end -- Calculating IVs for SHA512/224 and SHA512/256 for width = 224, 256, 32 do local H_lo, H_hi = {} - if XOR64A5 then + if HEX64 then for j = 1, 8 do - H_lo[j] = XOR64A5(sha2_H_lo[j]) + H_lo[j] = XORA5(sha2_H_lo[j]) end else H_hi = {} for j = 1, 8 do - H_lo[j] = XOR32A5(sha2_H_lo[j]) - H_hi[j] = XOR32A5(sha2_H_hi[j]) + H_lo[j] = XORA5(sha2_H_lo[j]) + H_hi[j] = XORA5(sha2_H_hi[j]) end end sha512_feed_128(H_lo, H_hi, "SHA-512/"..tostring(width).."\128"..string_rep("\0", 115).."\88", 0, 128) @@ -2408,14 +4315,16 @@ do end end --- Constants for SHA3 +-- Constants for SHA-3 do local sh_reg = 29 + local function next_bit() local r = sh_reg % 2 sh_reg = XOR_BYTE((sh_reg - r) / 2, 142 * r) return r end + for idx = 1, 24 do local lo, m = 0 for _ = 1, 6 do @@ -2427,13 +4336,24 @@ do end end +if branch == "FFI" then + sha2_K_hi = ffi.new("uint32_t[?]", #sha2_K_hi + 1, 0, unpack(sha2_K_hi)) + sha2_K_lo = ffi.new("int64_t[?]", #sha2_K_lo + 1, 0, unpack(sha2_K_lo)) + --md5_K = ffi.new("uint32_t[?]", #md5_K + 1, 0, unpack(md5_K)) + if hi_factor_keccak == 0 then + sha3_RC_lo = ffi.new("uint32_t[?]", #sha3_RC_lo + 1, 0, unpack(sha3_RC_lo)) + sha3_RC_hi = ffi.new("uint32_t[?]", #sha3_RC_hi + 1, 0, unpack(sha3_RC_hi)) + else + sha3_RC_lo = ffi.new("int64_t[?]", #sha3_RC_lo + 1, 0, unpack(sha3_RC_lo)) + end +end + -------------------------------------------------------------------------------- -- MAIN FUNCTIONS -------------------------------------------------------------------------------- local function sha256ext(width, message) - -- Create an instance (private objects for current calculation) local H, length, tail = {unpack(sha2_H_ext256[width])}, 0.0, "" @@ -2487,12 +4407,10 @@ local function sha256ext(width, message) -- 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 return partial end - end local function sha512ext(width, message) - -- Create an instance (private objects for current calculation) local length, tail, H_lo, H_hi = 0.0, "", {unpack(sha2_H_ext512_lo[width])}, not HEX64 and {unpack(sha2_H_ext512_hi[width])} @@ -2552,12 +4470,10 @@ local function sha512ext(width, message) -- 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 return partial end - end local function md5(message) - -- Create an instance (private objects for current calculation) local H, length, tail = {unpack(md5_sha1_H, 1, 4)}, 0.0, "" @@ -2608,12 +4524,10 @@ local function md5(message) -- 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 return partial end - end local function sha1(message) - -- Create an instance (private objects for current calculation) local H, length, tail = {unpack(md5_sha1_H)}, 0.0, "" @@ -2665,7 +4579,6 @@ local function sha1(message) -- 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 return partial end - end @@ -2678,24 +4591,10 @@ local function keccak(block_size_in_bytes, digest_size_in_bytes, is_SHAKE, messa -- it's easy to forget about this swap, hence the check error("Argument 'digest_size_in_bytes' must be a number", 2) end - -- Create an instance (private objects for current calculation) local tail, lanes_lo, lanes_hi = "", create_array_of_lanes(), hi_factor_keccak == 0 and create_array_of_lanes() local result ---~ 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), ---~ break P into n consecutive r-bit pieces P0, ..., Pn-1 (last is zero-padded) ---~ initialize the state S to a string of b 0 bits. ---~ absorb the input into the state: For each block Pi, ---~ extend Pi at the end by a string of c 0 bits, yielding one of length b, ---~ XOR that with S and ---~ apply the block permutation f to the result, yielding a new state S ---~ initialize Z to be the empty string ---~ while the length of Z is less than d: ---~ append the first r bits of S to Z ---~ if Z is still less than d bits long, apply f to S, yielding a new state S. ---~ truncate Z to d bits - local function partial(message_part) if message_part then if tail then @@ -2715,12 +4614,11 @@ local function keccak(block_size_in_bytes, digest_size_in_bytes, is_SHAKE, messa end else if tail then - -- append the following bits to the message: for usual SHA3: 011(0*)1, for SHAKE: 11111(0*)1 + -- append the following bits to the message: for usual SHA-3: 011(0*)1, for SHAKE: 11111(0*)1 local gap_start = is_SHAKE and 31 or 6 tail = tail..(#tail + 1 == block_size_in_bytes and char(gap_start + 128) or char(gap_start)..string_rep("\0", (-2 - #tail) % block_size_in_bytes).."\128") keccak_feed(lanes_lo, lanes_hi, tail, 0, #tail, block_size_in_bytes) tail = nil - local lanes_used = 0 local total_lanes = floor(block_size_in_bytes / 8) local qwords = {} @@ -2790,28 +4688,25 @@ local function keccak(block_size_in_bytes, digest_size_in_bytes, is_SHAKE, messa else result = get_next_part_of_digest(digest_size_in_bytes) end - end return result end end if message then - -- Actually perform calculations and return the SHA3 digest of a message + -- Actually perform calculations and return the SHA-3 digest of a message return partial(message)() else -- Return function for chunk-by-chunk loading - -- 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 + -- User should feed every chunk of input data as single argument to this function and finally get SHA-3 digest by invoking this function without an argument return partial end - end -local hex2bin, bin2base64, base642bin +local hex_to_bin, bin_to_hex, bin_to_base64, base64_to_bin do - - function hex2bin(hex_string) + function hex_to_bin(hex_string) return (gsub(hex_string, "%x%x", function (hh) return char(tonumber(hh, 16)) @@ -2819,6 +4714,14 @@ do )) end + function bin_to_hex(binary_string) + return (gsub(binary_string, ".", + function (c) + return string_format("%02x", byte(c)) + end + )) + end + local base64_symbols = { ['+'] = 62, ['-'] = 62, [62] = '+', ['/'] = 63, ['_'] = 63, [63] = '/', @@ -2834,7 +4737,7 @@ do end end - function bin2base64(binary_string) + function bin_to_base64(binary_string) local result = {} for pos = 1, #binary_string, 3 do local c1, c2, c3, c4 = byte(sub(binary_string, pos, pos + 2)..'\0', 1, -1) @@ -2847,7 +4750,7 @@ do return table_concat(result) end - function base642bin(base64_string) + function base64_to_bin(base64_string) local result, chars_qty = {}, 3 for pos, ch in gmatch(gsub(base64_string, '%s+', ''), '()(.)') do local code = base64_symbols[ch] @@ -2882,21 +4785,20 @@ local function pad_and_xor(str, result_length, byte_for_xor) end local function hmac(hash_func, key, message) - -- Create an instance (private objects for current calculation) local block_size = block_size_for_HMAC[hash_func] if not block_size then error("Unknown hash function", 2) end if #key > block_size then - key = hex2bin(hash_func(key)) + key = hex_to_bin(hash_func(key)) end local append = hash_func()(pad_and_xor(key, block_size, 0x36)) local result local function partial(message_part) if not message_part then - result = result or hash_func(pad_and_xor(key, block_size, 0x5C)..hex2bin(append())) + result = result or hash_func(pad_and_xor(key, block_size, 0x5C)..hex_to_bin(append())) return result elseif result then error("Adding more chunks is not allowed after receiving the result", 2) @@ -2914,48 +4816,859 @@ local function hmac(hash_func, key, message) -- 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 return partial end +end + + +local function xor_blake2_salt(salt, letter, H_lo, H_hi) + -- salt: concatenation of "Salt"+"Personalization" fields + local max_size = letter == "s" and 16 or 32 + local salt_size = #salt + if salt_size > max_size then + error(string_format("For BLAKE2%s/BLAKE2%sp/BLAKE2X%s the 'salt' parameter length must not exceed %d bytes", letter, letter, letter, max_size), 2) + end + if H_lo then + local offset, blake2_word_size, xor = 0, letter == "s" and 4 or 8, letter == "s" and XOR or XORA5 + for j = 5, 4 + ceil(salt_size / blake2_word_size) do + local prev, last + for _ = 1, blake2_word_size, 4 do + offset = offset + 4 + local a, b, c, d = byte(salt, offset - 3, offset) + local four_bytes = (((d or 0) * 256 + (c or 0)) * 256 + (b or 0)) * 256 + (a or 0) + prev, last = last, four_bytes + end + H_lo[j] = xor(H_lo[j], prev and last * hi_factor + prev or last) + if H_hi then + H_hi[j] = xor(H_hi[j], last) + end + end + end +end + +local function blake2s(message, key, salt, digest_size_in_bytes, XOF_length, B2_offset) + -- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode) + -- key: (optional) binary string up to 32 bytes, by default empty string + -- salt: (optional) binary string up to 16 bytes, by default empty string + -- digest_size_in_bytes: (optional) integer from 1 to 32, by default 32 + -- The last two parameters "XOF_length" and "B2_offset" are for internal use only, user must omit them (or pass nil) + digest_size_in_bytes = digest_size_in_bytes or 32 + if digest_size_in_bytes < 1 or digest_size_in_bytes > 32 then + error("BLAKE2s digest length must be from 1 to 32 bytes", 2) + end + key = key or "" + local key_length = #key + if key_length > 32 then + error("BLAKE2s key length must not exceed 32 bytes", 2) + end + salt = salt or "" + local bytes_compressed, tail, H = 0.0, "", {unpack(sha2_H_hi)} + if B2_offset then + H[1] = XOR(H[1], digest_size_in_bytes) + H[2] = XOR(H[2], 0x20) + H[3] = XOR(H[3], B2_offset) + H[4] = XOR(H[4], 0x20000000 + XOF_length) + else + H[1] = XOR(H[1], 0x01010000 + key_length * 256 + digest_size_in_bytes) + if XOF_length then + H[4] = XOR(H[4], XOF_length) + end + end + if salt ~= "" then + xor_blake2_salt(salt, "s", H) + end + + local function partial(message_part) + if message_part then + if tail then + local offs = 0 + if tail ~= "" and #tail + #message_part > 64 then + offs = 64 - #tail + bytes_compressed = blake2s_feed_64(H, tail..sub(message_part, 1, offs), 0, 64, bytes_compressed) + tail = "" + end + local size = #message_part - offs + local size_tail = size > 0 and (size - 1) % 64 + 1 or 0 + bytes_compressed = blake2s_feed_64(H, message_part, offs, size - size_tail, bytes_compressed) + tail = tail..sub(message_part, #message_part + 1 - size_tail) + return partial + else + error("Adding more chunks is not allowed after receiving the result", 2) + end + else + if tail then + if B2_offset then + blake2s_feed_64(H, nil, 0, 64, 0, 32) + else + blake2s_feed_64(H, tail..string_rep("\0", 64 - #tail), 0, 64, bytes_compressed, #tail) + end + tail = nil + if not XOF_length or B2_offset then + local max_reg = ceil(digest_size_in_bytes / 4) + for j = 1, max_reg do + H[j] = HEX(H[j]) + end + H = sub(gsub(table_concat(H, "", 1, max_reg), "(..)(..)(..)(..)", "%4%3%2%1"), 1, digest_size_in_bytes * 2) + end + end + return H + end + end + + if key_length > 0 then + partial(key..string_rep("\0", 64 - key_length)) + end + if B2_offset then + return partial() + elseif message then + -- Actually perform calculations and return the BLAKE2s digest of a message + return partial(message)() + else + -- Return function for chunk-by-chunk loading + -- User should feed every chunk of input data as single argument to this function and finally get BLAKE2s digest by invoking this function without an argument + return partial + end +end + +local function blake2b(message, key, salt, digest_size_in_bytes, XOF_length, B2_offset) + -- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode) + -- key: (optional) binary string up to 64 bytes, by default empty string + -- salt: (optional) binary string up to 32 bytes, by default empty string + -- digest_size_in_bytes: (optional) integer from 1 to 64, by default 64 + -- The last two parameters "XOF_length" and "B2_offset" are for internal use only, user must omit them (or pass nil) + digest_size_in_bytes = floor(digest_size_in_bytes or 64) + if digest_size_in_bytes < 1 or digest_size_in_bytes > 64 then + error("BLAKE2b digest length must be from 1 to 64 bytes", 2) + end + key = key or "" + local key_length = #key + if key_length > 64 then + error("BLAKE2b key length must not exceed 64 bytes", 2) + end + salt = salt or "" + local bytes_compressed, tail, H_lo, H_hi = 0.0, "", {unpack(sha2_H_lo)}, not HEX64 and {unpack(sha2_H_hi)} + if B2_offset then + if H_hi then + H_lo[1] = XORA5(H_lo[1], digest_size_in_bytes) + H_hi[1] = XORA5(H_hi[1], 0x40) + H_lo[2] = XORA5(H_lo[2], B2_offset) + H_hi[2] = XORA5(H_hi[2], XOF_length) + else + H_lo[1] = XORA5(H_lo[1], 0x40 * hi_factor + digest_size_in_bytes) + H_lo[2] = XORA5(H_lo[2], XOF_length * hi_factor + B2_offset) + end + H_lo[3] = XORA5(H_lo[3], 0x4000) + else + H_lo[1] = XORA5(H_lo[1], 0x01010000 + key_length * 256 + digest_size_in_bytes) + if XOF_length then + if H_hi then + H_hi[2] = XORA5(H_hi[2], XOF_length) + else + H_lo[2] = XORA5(H_lo[2], XOF_length * hi_factor) + end + end + end + if salt ~= "" then + xor_blake2_salt(salt, "b", H_lo, H_hi) + end + + local function partial(message_part) + if message_part then + if tail then + local offs = 0 + if tail ~= "" and #tail + #message_part > 128 then + offs = 128 - #tail + bytes_compressed = blake2b_feed_128(H_lo, H_hi, tail..sub(message_part, 1, offs), 0, 128, bytes_compressed) + tail = "" + end + local size = #message_part - offs + local size_tail = size > 0 and (size - 1) % 128 + 1 or 0 + bytes_compressed = blake2b_feed_128(H_lo, H_hi, message_part, offs, size - size_tail, bytes_compressed) + tail = tail..sub(message_part, #message_part + 1 - size_tail) + return partial + else + error("Adding more chunks is not allowed after receiving the result", 2) + end + else + if tail then + if B2_offset then + blake2b_feed_128(H_lo, H_hi, nil, 0, 128, 0, 64) + else + blake2b_feed_128(H_lo, H_hi, tail..string_rep("\0", 128 - #tail), 0, 128, bytes_compressed, #tail) + end + tail = nil + if XOF_length and not B2_offset then + if H_hi then + for j = 8, 1, -1 do + H_lo[j*2] = H_hi[j] + H_lo[j*2-1] = H_lo[j] + end + return H_lo, 16 + end + else + local max_reg = ceil(digest_size_in_bytes / 8) + if H_hi then + for j = 1, max_reg do + H_lo[j] = HEX(H_hi[j])..HEX(H_lo[j]) + end + else + for j = 1, max_reg do + H_lo[j] = HEX64(H_lo[j]) + end + end + H_lo = sub(gsub(table_concat(H_lo, "", 1, max_reg), "(..)(..)(..)(..)(..)(..)(..)(..)", "%8%7%6%5%4%3%2%1"), 1, digest_size_in_bytes * 2) + end + H_hi = nil + end + return H_lo + end + end + + if key_length > 0 then + partial(key..string_rep("\0", 128 - key_length)) + end + if B2_offset then + return partial() + elseif message then + -- Actually perform calculations and return the BLAKE2b digest of a message + return partial(message)() + else + -- Return function for chunk-by-chunk loading + -- User should feed every chunk of input data as single argument to this function and finally get BLAKE2b digest by invoking this function without an argument + return partial + end +end + +local function blake2sp(message, key, salt, digest_size_in_bytes) + -- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode) + -- key: (optional) binary string up to 32 bytes, by default empty string + -- salt: (optional) binary string up to 16 bytes, by default empty string + -- digest_size_in_bytes: (optional) integer from 1 to 32, by default 32 + digest_size_in_bytes = digest_size_in_bytes or 32 + if digest_size_in_bytes < 1 or digest_size_in_bytes > 32 then + error("BLAKE2sp digest length must be from 1 to 32 bytes", 2) + end + key = key or "" + local key_length = #key + if key_length > 32 then + error("BLAKE2sp key length must not exceed 32 bytes", 2) + end + salt = salt or "" + local instances, length, first_dword_of_parameter_block, result = {}, 0.0, 0x02080000 + key_length * 256 + digest_size_in_bytes + for j = 1, 8 do + local bytes_compressed, tail, H = 0.0, "", {unpack(sha2_H_hi)} + instances[j] = {bytes_compressed, tail, H} + H[1] = XOR(H[1], first_dword_of_parameter_block) + H[3] = XOR(H[3], j-1) + H[4] = XOR(H[4], 0x20000000) + if salt ~= "" then + xor_blake2_salt(salt, "s", H) + end + end + + local function partial(message_part) + if message_part then + if instances then + local from = 0 + while true do + local to = math_min(from + 64 - length % 64, #message_part) + if to > from then + local inst = instances[floor(length / 64) % 8 + 1] + local part = sub(message_part, from + 1, to) + length, from = length + to - from, to + local bytes_compressed, tail = inst[1], inst[2] + if #tail < 64 then + tail = tail..part + else + local H = inst[3] + bytes_compressed = blake2s_feed_64(H, tail, 0, 64, bytes_compressed) + tail = part + end + inst[1], inst[2] = bytes_compressed, tail + else + break + end + end + return partial + else + error("Adding more chunks is not allowed after receiving the result", 2) + end + else + if instances then + local root_H = {unpack(sha2_H_hi)} + root_H[1] = XOR(root_H[1], first_dword_of_parameter_block) + root_H[4] = XOR(root_H[4], 0x20010000) + if salt ~= "" then + xor_blake2_salt(salt, "s", root_H) + end + for j = 1, 8 do + local inst = instances[j] + local bytes_compressed, tail, H = inst[1], inst[2], inst[3] + blake2s_feed_64(H, tail..string_rep("\0", 64 - #tail), 0, 64, bytes_compressed, #tail, j == 8) + if j % 2 == 0 then + local index = 0 + for k = j - 1, j do + local inst = instances[k] + local H = inst[3] + for i = 1, 8 do + index = index + 1 + common_W_blake2s[index] = H[i] + end + end + blake2s_feed_64(root_H, nil, 0, 64, 64 * (j/2 - 1), j == 8 and 64, j == 8) + end + end + instances = nil + local max_reg = ceil(digest_size_in_bytes / 4) + for j = 1, max_reg do + root_H[j] = HEX(root_H[j]) + end + result = sub(gsub(table_concat(root_H, "", 1, max_reg), "(..)(..)(..)(..)", "%4%3%2%1"), 1, digest_size_in_bytes * 2) + end + return result + end + end + + if key_length > 0 then + key = key..string_rep("\0", 64 - key_length) + for j = 1, 8 do + partial(key) + end + end + if message then + -- Actually perform calculations and return the BLAKE2sp digest of a message + return partial(message)() + else + -- Return function for chunk-by-chunk loading + -- User should feed every chunk of input data as single argument to this function and finally get BLAKE2sp digest by invoking this function without an argument + return partial + end end +local function blake2bp(message, key, salt, digest_size_in_bytes) + -- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode) + -- key: (optional) binary string up to 64 bytes, by default empty string + -- salt: (optional) binary string up to 32 bytes, by default empty string + -- digest_size_in_bytes: (optional) integer from 1 to 64, by default 64 + digest_size_in_bytes = digest_size_in_bytes or 64 + if digest_size_in_bytes < 1 or digest_size_in_bytes > 64 then + error("BLAKE2bp digest length must be from 1 to 64 bytes", 2) + end + key = key or "" + local key_length = #key + if key_length > 64 then + error("BLAKE2bp key length must not exceed 64 bytes", 2) + end + salt = salt or "" + local instances, length, first_dword_of_parameter_block, result = {}, 0.0, 0x02040000 + key_length * 256 + digest_size_in_bytes + for j = 1, 4 do + local bytes_compressed, tail, H_lo, H_hi = 0.0, "", {unpack(sha2_H_lo)}, not HEX64 and {unpack(sha2_H_hi)} + instances[j] = {bytes_compressed, tail, H_lo, H_hi} + H_lo[1] = XORA5(H_lo[1], first_dword_of_parameter_block) + H_lo[2] = XORA5(H_lo[2], j-1) + H_lo[3] = XORA5(H_lo[3], 0x4000) + if salt ~= "" then + xor_blake2_salt(salt, "b", H_lo, H_hi) + end + end + + local function partial(message_part) + if message_part then + if instances then + local from = 0 + while true do + local to = math_min(from + 128 - length % 128, #message_part) + if to > from then + local inst = instances[floor(length / 128) % 4 + 1] + local part = sub(message_part, from + 1, to) + length, from = length + to - from, to + local bytes_compressed, tail = inst[1], inst[2] + if #tail < 128 then + tail = tail..part + else + local H_lo, H_hi = inst[3], inst[4] + bytes_compressed = blake2b_feed_128(H_lo, H_hi, tail, 0, 128, bytes_compressed) + tail = part + end + inst[1], inst[2] = bytes_compressed, tail + else + break + end + end + return partial + else + error("Adding more chunks is not allowed after receiving the result", 2) + end + else + if instances then + local root_H_lo, root_H_hi = {unpack(sha2_H_lo)}, not HEX64 and {unpack(sha2_H_hi)} + root_H_lo[1] = XORA5(root_H_lo[1], first_dword_of_parameter_block) + root_H_lo[3] = XORA5(root_H_lo[3], 0x4001) + if salt ~= "" then + xor_blake2_salt(salt, "b", root_H_lo, root_H_hi) + end + for j = 1, 4 do + local inst = instances[j] + local bytes_compressed, tail, H_lo, H_hi = inst[1], inst[2], inst[3], inst[4] + blake2b_feed_128(H_lo, H_hi, tail..string_rep("\0", 128 - #tail), 0, 128, bytes_compressed, #tail, j == 4) + if j % 2 == 0 then + local index = 0 + for k = j - 1, j do + local inst = instances[k] + local H_lo, H_hi = inst[3], inst[4] + for i = 1, 8 do + index = index + 1 + common_W_blake2b[index] = H_lo[i] + if H_hi then + index = index + 1 + common_W_blake2b[index] = H_hi[i] + end + end + end + blake2b_feed_128(root_H_lo, root_H_hi, nil, 0, 128, 128 * (j/2 - 1), j == 4 and 128, j == 4) + end + end + instances = nil + local max_reg = ceil(digest_size_in_bytes / 8) + if HEX64 then + for j = 1, max_reg do + root_H_lo[j] = HEX64(root_H_lo[j]) + end + else + for j = 1, max_reg do + root_H_lo[j] = HEX(root_H_hi[j])..HEX(root_H_lo[j]) + end + end + result = sub(gsub(table_concat(root_H_lo, "", 1, max_reg), "(..)(..)(..)(..)(..)(..)(..)(..)", "%8%7%6%5%4%3%2%1"), 1, digest_size_in_bytes * 2) + end + return result + end + end + + if key_length > 0 then + key = key..string_rep("\0", 128 - key_length) + for j = 1, 4 do + partial(key) + end + end + if message then + -- Actually perform calculations and return the BLAKE2bp digest of a message + return partial(message)() + else + -- Return function for chunk-by-chunk loading + -- User should feed every chunk of input data as single argument to this function and finally get BLAKE2bp digest by invoking this function without an argument + return partial + end + +end + +local function blake2x(inner_func, inner_func_letter, common_W_blake2, block_size, digest_size_in_bytes, message, key, salt) + local XOF_digest_length_limit, XOF_digest_length, chunk_by_chunk_output = 2^(block_size / 2) - 1 + if digest_size_in_bytes == -1 then -- infinite digest + digest_size_in_bytes = math_huge + XOF_digest_length = floor(XOF_digest_length_limit) + chunk_by_chunk_output = true + else + if digest_size_in_bytes < 0 then + digest_size_in_bytes = -1.0 * digest_size_in_bytes + chunk_by_chunk_output = true + end + XOF_digest_length = floor(digest_size_in_bytes) + if XOF_digest_length >= XOF_digest_length_limit then + error("Requested digest is too long. BLAKE2X"..inner_func_letter.." finite digest is limited by (2^"..floor(block_size / 2)..")-2 bytes. Hint: you can generate infinite digest.", 2) + end + end + salt = salt or "" + if salt ~= "" then + xor_blake2_salt(salt, inner_func_letter) -- don't xor, only check the size of salt + end + local inner_partial = inner_func(nil, key, salt, nil, XOF_digest_length) + local result + + local function partial(message_part) + if message_part then + if inner_partial then + inner_partial(message_part) + return partial + else + error("Adding more chunks is not allowed after receiving the result", 2) + end + else + if inner_partial then + local half_W, half_W_size = inner_partial() + half_W_size, inner_partial = half_W_size or 8 + + local function get_hash_block(block_no) + -- block_no = 0...(2^32-1) + local size = math_min(block_size, digest_size_in_bytes - block_no * block_size) + if size <= 0 then + return "" + end + for j = 1, half_W_size do + common_W_blake2[j] = half_W[j] + end + for j = half_W_size + 1, 2 * half_W_size do + common_W_blake2[j] = 0 + end + return inner_func(nil, nil, salt, size, XOF_digest_length, floor(block_no)) + end + + local hash = {} + if chunk_by_chunk_output then + local pos, period, cached_block_no, cached_block = 0, block_size * 2^32 + + local function get_next_part_of_digest(arg1, arg2) + if arg1 == "seek" then + -- Usage #1: get_next_part_of_digest("seek", new_pos) + pos = arg2 % period + else + -- Usage #2: hex_string = get_next_part_of_digest(size) + local size, index = arg1 or 1, 0 + while size > 0 do + local block_offset = pos % block_size + local block_no = (pos - block_offset) / block_size + local part_size = math_min(size, block_size - block_offset) + if cached_block_no ~= block_no then + cached_block_no = block_no + cached_block = get_hash_block(block_no) + end + index = index + 1 + hash[index] = sub(cached_block, block_offset * 2 + 1, (block_offset + part_size) * 2) + size = size - part_size + pos = (pos + part_size) % period + end + return table_concat(hash, "", 1, index) + end + end + + result = get_next_part_of_digest + else + for j = 1.0, ceil(digest_size_in_bytes / block_size) do + hash[j] = get_hash_block(j - 1.0) + end + result = table_concat(hash) + end + end + return result + end + end + + if message then + -- Actually perform calculations and return the BLAKE2X digest of a message + return partial(message)() + else + -- Return function for chunk-by-chunk loading + -- User should feed every chunk of input data as single argument to this function and finally get BLAKE2X digest by invoking this function without an argument + return partial + end +end + +local function blake2xs(digest_size_in_bytes, message, key, salt) + -- digest_size_in_bytes: + -- 0..65534 = get finite digest as single Lua string + -- (-1) = get infinite digest in "chunk-by-chunk" output mode + -- (-2)..(-65534) = get finite digest in "chunk-by-chunk" output mode + -- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode) + -- key: (optional) binary string up to 32 bytes, by default empty string + -- salt: (optional) binary string up to 16 bytes, by default empty string + return blake2x(blake2s, "s", common_W_blake2s, 32, digest_size_in_bytes, message, key, salt) +end + +local function blake2xb(digest_size_in_bytes, message, key, salt) + -- digest_size_in_bytes: + -- 0..4294967294 = get finite digest as single Lua string + -- (-1) = get infinite digest in "chunk-by-chunk" output mode + -- (-2)..(-4294967294) = get finite digest in "chunk-by-chunk" output mode + -- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode) + -- key: (optional) binary string up to 64 bytes, by default empty string + -- salt: (optional) binary string up to 32 bytes, by default empty string + return blake2x(blake2b, "b", common_W_blake2b, 64, digest_size_in_bytes, message, key, salt) +end + + +local function blake3(message, key, digest_size_in_bytes, message_flags, K, return_array) + -- message: binary string to be hashed (or nil for "chunk-by-chunk" input mode) + -- key: (optional) binary string up to 32 bytes, by default empty string + -- digest_size_in_bytes: (optional) by default 32 + -- 0,1,2,3,4,... = get finite digest as single Lua string + -- (-1) = get infinite digest in "chunk-by-chunk" output mode + -- -2,-3,-4,... = get finite digest in "chunk-by-chunk" output mode + -- The last three parameters "message_flags", "K" and "return_array" are for internal use only, user must omit them (or pass nil) + key = key or "" + digest_size_in_bytes = digest_size_in_bytes or 32 + message_flags = message_flags or 0 + if key == "" then + K = K or sha2_H_hi + else + local key_length = #key + if key_length > 32 then + error("BLAKE3 key length must not exceed 32 bytes", 2) + end + key = key..string_rep("\0", 32 - key_length) + K = {} + for j = 1, 8 do + local a, b, c, d = byte(key, 4*j-3, 4*j) + K[j] = ((d * 256 + c) * 256 + b) * 256 + a + end + message_flags = message_flags + 16 -- flag:KEYED_HASH + end + local tail, H, chunk_index, blocks_in_chunk, stack_size, stack = "", {}, 0, 0, 0, {} + local final_H_in, final_block_length, chunk_by_chunk_output, result, wide_output = K + local final_compression_flags = 3 -- flags:CHUNK_START,CHUNK_END + + local function feed_blocks(str, offs, size) + -- size >= 0, size is multiple of 64 + while size > 0 do + local part_size_in_blocks, block_flags, H_in = 1, 0, H + if blocks_in_chunk == 0 then + block_flags = 1 -- flag:CHUNK_START + H_in, final_H_in = K, H + final_compression_flags = 2 -- flag:CHUNK_END + elseif blocks_in_chunk == 15 then + block_flags = 2 -- flag:CHUNK_END + final_compression_flags = 3 -- flags:CHUNK_START,CHUNK_END + final_H_in = K + else + part_size_in_blocks = math_min(size / 64, 15 - blocks_in_chunk) + end + local part_size = part_size_in_blocks * 64 + blake3_feed_64(str, offs, part_size, message_flags + block_flags, chunk_index, H_in, H) + offs, size = offs + part_size, size - part_size + blocks_in_chunk = (blocks_in_chunk + part_size_in_blocks) % 16 + if blocks_in_chunk == 0 then + -- completing the currect chunk + chunk_index = chunk_index + 1.0 + local divider = 2.0 + while chunk_index % divider == 0 do + divider = divider * 2.0 + stack_size = stack_size - 8 + for j = 1, 8 do + common_W_blake2s[j] = stack[stack_size + j] + end + for j = 1, 8 do + common_W_blake2s[j + 8] = H[j] + end + blake3_feed_64(nil, 0, 64, message_flags + 4, 0, K, H) -- flag:PARENT + end + for j = 1, 8 do + stack[stack_size + j] = H[j] + end + stack_size = stack_size + 8 + end + end + end + + local function get_hash_block(block_no) + local size = math_min(64, digest_size_in_bytes - block_no * 64) + if block_no < 0 or size <= 0 then + return "" + end + if chunk_by_chunk_output then + for j = 1, 16 do + common_W_blake2s[j] = stack[j + 16] + end + end + blake3_feed_64(nil, 0, 64, final_compression_flags, block_no, final_H_in, stack, wide_output, final_block_length) + if return_array then + return stack + end + local max_reg = ceil(size / 4) + for j = 1, max_reg do + stack[j] = HEX(stack[j]) + end + return sub(gsub(table_concat(stack, "", 1, max_reg), "(..)(..)(..)(..)", "%4%3%2%1"), 1, size * 2) + end + + local function partial(message_part) + if message_part then + if tail then + local offs = 0 + if tail ~= "" and #tail + #message_part > 64 then + offs = 64 - #tail + feed_blocks(tail..sub(message_part, 1, offs), 0, 64) + tail = "" + end + local size = #message_part - offs + local size_tail = size > 0 and (size - 1) % 64 + 1 or 0 + feed_blocks(message_part, offs, size - size_tail) + tail = tail..sub(message_part, #message_part + 1 - size_tail) + return partial + else + error("Adding more chunks is not allowed after receiving the result", 2) + end + else + if tail then + final_block_length = #tail + tail = tail..string_rep("\0", 64 - #tail) + if common_W_blake2s[0] then + for j = 1, 16 do + local a, b, c, d = byte(tail, 4*j-3, 4*j) + common_W_blake2s[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a) + end + else + for j = 1, 16 do + local a, b, c, d = byte(tail, 4*j-3, 4*j) + common_W_blake2s[j] = ((d * 256 + c) * 256 + b) * 256 + a + end + end + tail = nil + for stack_size = stack_size - 8, 0, -8 do + blake3_feed_64(nil, 0, 64, message_flags + final_compression_flags, chunk_index, final_H_in, H, nil, final_block_length) + chunk_index, final_block_length, final_H_in, final_compression_flags = 0, 64, K, 4 -- flag:PARENT + for j = 1, 8 do + common_W_blake2s[j] = stack[stack_size + j] + end + for j = 1, 8 do + common_W_blake2s[j + 8] = H[j] + end + end + final_compression_flags = message_flags + final_compression_flags + 8 -- flag:ROOT + if digest_size_in_bytes < 0 then + if digest_size_in_bytes == -1 then -- infinite digest + digest_size_in_bytes = math_huge + else + digest_size_in_bytes = -1.0 * digest_size_in_bytes + end + chunk_by_chunk_output = true + for j = 1, 16 do + stack[j + 16] = common_W_blake2s[j] + end + end + digest_size_in_bytes = math_min(2^53, digest_size_in_bytes) + wide_output = digest_size_in_bytes > 32 + if chunk_by_chunk_output then + local pos, cached_block_no, cached_block = 0.0 + + local function get_next_part_of_digest(arg1, arg2) + if arg1 == "seek" then + -- Usage #1: get_next_part_of_digest("seek", new_pos) + pos = arg2 * 1.0 + else + -- Usage #2: hex_string = get_next_part_of_digest(size) + local size, index = arg1 or 1, 32 + while size > 0 do + local block_offset = pos % 64 + local block_no = (pos - block_offset) / 64 + local part_size = math_min(size, 64 - block_offset) + if cached_block_no ~= block_no then + cached_block_no = block_no + cached_block = get_hash_block(block_no) + end + index = index + 1 + stack[index] = sub(cached_block, block_offset * 2 + 1, (block_offset + part_size) * 2) + size = size - part_size + pos = pos + part_size + end + return table_concat(stack, "", 33, index) + end + end + + result = get_next_part_of_digest + elseif digest_size_in_bytes <= 64 then + result = get_hash_block(0) + else + local last_block_no = ceil(digest_size_in_bytes / 64) - 1 + for block_no = 0.0, last_block_no do + stack[33 + block_no] = get_hash_block(block_no) + end + result = table_concat(stack, "", 33, 33 + last_block_no) + end + end + return result + end + end + + if message then + -- Actually perform calculations and return the BLAKE3 digest of a message + return partial(message)() + else + -- Return function for chunk-by-chunk loading + -- User should feed every chunk of input data as single argument to this function and finally get BLAKE3 digest by invoking this function without an argument + return partial + end +end + +local function blake3_derive_key(key_material, context_string, derived_key_size_in_bytes) + -- key_material: (string) your source of entropy to derive a key from (for example, it can be a master password) + -- set to nil for feeding the key material in "chunk-by-chunk" input mode + -- context_string: (string) unique description of the derived key + -- digest_size_in_bytes: (optional) by default 32 + -- 0,1,2,3,4,... = get finite derived key as single Lua string + -- (-1) = get infinite derived key in "chunk-by-chunk" output mode + -- -2,-3,-4,... = get finite derived key in "chunk-by-chunk" output mode + if type(context_string) ~= "string" then + error("'context_string' parameter must be a Lua string", 2) + end + local K = blake3(context_string, nil, nil, 32, nil, true) -- flag:DERIVE_KEY_CONTEXT + return blake3(key_material, nil, derived_key_size_in_bytes, 64, K) -- flag:DERIVE_KEY_MATERIAL +end + + local sha = { md5 = md5, -- MD5 sha1 = sha1, -- SHA-1 - -- SHA2 hash functions: + -- SHA-2 hash functions: sha224 = function (message) return sha256ext(224, message) end, -- SHA-224 sha256 = function (message) return sha256ext(256, message) end, -- SHA-256 sha512_224 = function (message) return sha512ext(224, message) end, -- SHA-512/224 sha512_256 = function (message) return sha512ext(256, message) end, -- SHA-512/256 sha384 = function (message) return sha512ext(384, message) end, -- SHA-384 sha512 = function (message) return sha512ext(512, message) end, -- SHA-512 - -- SHA3 hash functions: + -- SHA-3 hash functions: sha3_224 = function (message) return keccak((1600 - 2 * 224) / 8, 224 / 8, false, message) end, -- SHA3-224 sha3_256 = function (message) return keccak((1600 - 2 * 256) / 8, 256 / 8, false, message) end, -- SHA3-256 sha3_384 = function (message) return keccak((1600 - 2 * 384) / 8, 384 / 8, false, message) end, -- SHA3-384 sha3_512 = function (message) return keccak((1600 - 2 * 512) / 8, 512 / 8, false, message) end, -- SHA3-512 shake128 = function (digest_size_in_bytes, message) return keccak((1600 - 2 * 128) / 8, digest_size_in_bytes, true, message) end, -- SHAKE128 shake256 = function (digest_size_in_bytes, message) return keccak((1600 - 2 * 256) / 8, digest_size_in_bytes, true, message) end, -- SHAKE256 + -- HMAC: + hmac = hmac, -- HMAC(hash_func, key, message) is applicable to any hash function from this module except SHAKE* and BLAKE* -- misc utilities: - hmac = hmac, -- HMAC(hash_func, key, message) is applicable to any hash function from this module except SHAKE* - hex2bin = hex2bin, -- converts hexadecimal representation to binary string - base642bin = base642bin, -- converts base64 representation to binary string - bin2base64 = bin2base64, -- converts binary string to base64 representation + hex_to_bin = hex_to_bin, -- converts hexadecimal representation to binary string + bin_to_hex = bin_to_hex, -- converts binary string to hexadecimal representation + base64_to_bin = base64_to_bin, -- converts base64 representation to binary string + bin_to_base64 = bin_to_base64, -- converts binary string to base64 representation + -- old style names for backward compatibility: + hex2bin = hex_to_bin, + bin2hex = bin_to_hex, + base642bin = base64_to_bin, + bin2base64 = bin_to_base64, + -- BLAKE2 hash functions: + blake2b = blake2b, -- BLAKE2b (message, key, salt, digest_size_in_bytes) + blake2s = blake2s, -- BLAKE2s (message, key, salt, digest_size_in_bytes) + blake2bp = blake2bp, -- BLAKE2bp(message, key, salt, digest_size_in_bytes) + blake2sp = blake2sp, -- BLAKE2sp(message, key, salt, digest_size_in_bytes) + blake2xb = blake2xb, -- BLAKE2Xb(digest_size_in_bytes, message, key, salt) + blake2xs = blake2xs, -- BLAKE2Xs(digest_size_in_bytes, message, key, salt) + -- BLAKE2 aliases: + blake2 = blake2b, + blake2b_160 = function (message, key, salt) return blake2b(message, key, salt, 20) end, -- BLAKE2b-160 + blake2b_256 = function (message, key, salt) return blake2b(message, key, salt, 32) end, -- BLAKE2b-256 + blake2b_384 = function (message, key, salt) return blake2b(message, key, salt, 48) end, -- BLAKE2b-384 + blake2b_512 = blake2b, -- 64 -- BLAKE2b-512 + blake2s_128 = function (message, key, salt) return blake2s(message, key, salt, 16) end, -- BLAKE2s-128 + blake2s_160 = function (message, key, salt) return blake2s(message, key, salt, 20) end, -- BLAKE2s-160 + blake2s_224 = function (message, key, salt) return blake2s(message, key, salt, 28) end, -- BLAKE2s-224 + blake2s_256 = blake2s, -- 32 -- BLAKE2s-256 + -- BLAKE3 hash function + blake3 = blake3, -- BLAKE3 (message, key, digest_size_in_bytes) + blake3_derive_key = blake3_derive_key, -- BLAKE3_KDF(key_material, context_string, derived_key_size_in_bytes) } block_size_for_HMAC = { - [sha.md5] = 64, - [sha.sha1] = 64, - [sha.sha224] = 64, - [sha.sha256] = 64, + [sha.md5] = 64, + [sha.sha1] = 64, + [sha.sha224] = 64, + [sha.sha256] = 64, [sha.sha512_224] = 128, [sha.sha512_256] = 128, [sha.sha384] = 128, [sha.sha512] = 128, - [sha.sha3_224] = (1600 - 2 * 224) / 8, - [sha.sha3_256] = (1600 - 2 * 256) / 8, - [sha.sha3_384] = (1600 - 2 * 384) / 8, - [sha.sha3_512] = (1600 - 2 * 512) / 8, + [sha.sha3_224] = 144, -- (1600 - 2 * 224) / 8 + [sha.sha3_256] = 136, -- (1600 - 2 * 256) / 8 + [sha.sha3_384] = 104, -- (1600 - 2 * 384) / 8 + [sha.sha3_512] = 72, -- (1600 - 2 * 512) / 8 } diff --git a/src/libs/utils.lua b/src/libs/utils.lua index 229f29e..0f26f92 100644 --- a/src/libs/utils.lua +++ b/src/libs/utils.lua @@ -3,10 +3,13 @@ local _M = {} local sha = require("sha") local secret_bucket_duration = tonumber(os.getenv("BUCKET_DURATION")) -function _M.generate_secret(context, salt, is_applet, iterations) +function _M.generate_secret(context, salt, user_key, is_applet) + + -- time bucket for expiry local start_sec = core.now()['sec'] local bucket = start_sec - (start_sec % secret_bucket_duration) - local ip = context.sf:src() + + -- user agent to counter very dumb spammers local user_agent = "" if is_applet == true then user_agent = context.headers['user-agent'] or {} @@ -15,13 +18,17 @@ function _M.generate_secret(context, salt, is_applet, iterations) --note req_fhdr not req_hdr otherwise commas in useragent become a delimiter user_agent = context.sf:req_fhdr('user-agent') or "" end - if iterations == nil then - --hcaptcha secret is just this - return context.sc:xxh32(salt .. bucket .. ip .. user_agent) - else - --POW secret adds the iteration number by the user - return sha.sha1(salt .. bucket .. ip .. user_agent .. iterations) + + return sha.sha256(salt .. bucket .. user_key .. user_agent) + +end + +function _M.split(inputstr, sep) + local t = {} + for str in string.gmatch(inputstr, "([^"..sep.."]+)") do + table.insert(t, str) end + return t end return _M diff --git a/src/scripts/hcaptcha.lua b/src/scripts/hcaptcha.lua index b960a03..9d26d2a 100644 --- a/src/scripts/hcaptcha.lua +++ b/src/scripts/hcaptcha.lua @@ -5,15 +5,35 @@ local utils = require("utils") local cookie = require("cookie") local json = require("json") local sha = require("sha") +local randbytes = require("randbytes") +--require("print_r") -local captcha_secret = os.getenv("HCAPTCHA_SECRET") -local captcha_sitekey = os.getenv("HCAPTCHA_SITEKEY") -local hcaptcha_cookie_secret = os.getenv("CAPTCHA_COOKIE_SECRET") +local captcha_secret = os.getenv("HCAPTCHA_SECRET") or os.getenv("RECAPTCHA_SECRET") +local captcha_sitekey = os.getenv("HCAPTCHA_SITEKEY") or os.getenv("RECAPTCHA_SITEKEY") +local captcha_cookie_secret = os.getenv("CAPTCHA_COOKIE_SECRET") local pow_cookie_secret = os.getenv("POW_COOKIE_SECRET") +local hmac_cookie_secret = os.getenv("HMAC_COOKIE_SECRET") local ray_id = os.getenv("RAY_ID") -local captcha_provider_domain = "hcaptcha.com" local captcha_map = Map.new("/etc/haproxy/ddos.map", Map._str); +local captcha_provider_domain = "" +local captcha_classname = "" +local captcha_script_src = "" +local captcha_siteverify_path = "" +local captcha_backend_name = "" +if os.getenv("HCAPTCHA_SITEKEY") then + captcha_provider_domain = "hcaptcha.com" + captcha_classname = "h-captcha" + captcha_script_src = "https://hcaptcha.com/1/api.js" + captcha_siteverify_path = "/siteverify" + captcha_backend_name = "hcaptcha" +else + captcha_provider_domain = "www.google.com" + captcha_classname = "g-recaptcha" + captcha_script_src = "https://www.google.com/recaptcha/api.js" + captcha_siteverify_path = "/recaptcha/api/siteverify" + captcha_backend_name = "recaptcha" +end function _M.setup_servers() local backend_name = os.getenv("BACKEND_NAME") @@ -50,7 +70,7 @@ local body_template = [[