Created
August 6, 2014 15:29
-
-
Save katlogic/1cfe0dee78fba51324b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local s,m,t,sm = string,math,table,setmetatable | |
local mt = {} -- holds initial vector too | |
local S = {} -- S-box | |
-- As per FIPS 180-4 | |
local conv = function(i) | |
return s.format("%.0f", m.floor(2^32*select(2,m.modf(i))))>>0 | |
end | |
for i=2,311 do | |
for _,v in ipairs {2,3,5,7,11,13,17} do | |
if (i ~= v) and (i % v == 0) then goto notprime end | |
end | |
if i <= 19 then | |
t.insert(mt, conv(i^0.5)) -- fmod 8 square roots of primes 2..19 | |
end | |
t.insert(S, conv(i^(1/3))) -- fmod 64 cubic roots of primes 2..311 | |
::notprime:: | |
end | |
-- Transform blocks | |
local ror32 = bit and bit.ror or function(n, bits) | |
return ((n >> bits) | (n << (32-bits))) & 0xffffffff | |
end | |
function mt:update(buf) | |
local input = self.input .. buf | |
if #input < 64 then self.input = input return self end | |
local stop = (#input & ~63) | |
local w = {} | |
local a,b,c,d,e,f,g,h = | |
self[1],self[2],self[3],self[4],self[5],self[6],self[7],self[8] | |
local pos = 1 | |
while pos < stop do | |
for i=1,16 do -- Load 16 32-bit words and expand to 64 words | |
w[i], pos = input:undumpint(pos, 4, "b"), pos + 4 | |
end | |
for i=17,64 do | |
local t15, t2 = w[i-15], w[i-2] | |
local s0 = ror32(t15, 7) ~ ror32(t15, 18) ~ (t15 >> 3) | |
local s1 = ror32(t2, 17) ~ ror32(t2, 19) ~ (t2 >> 10) | |
w[i] = (s1 + w[i-7] + s0 + w[i-16]) | |
end | |
local _a,_b,_c,_d,_e,_f,_g,_h=a,b,c,d,e,f,g,h | |
for i=1,64 do -- Perform 64 SHA-256 rounds | |
local ch = (g ~ (e & (f ~ g))) | |
local maj = (a & b) | (c & (a | b)) | |
local s0 = ror32(a, 2) ~ ror32(a, 13) ~ ror32(a, 22) | |
local s1 = ror32(e, 6) ~ ror32(e, 11) ~ ror32(e, 25) | |
local t1 = (h + s1 + ch + S[i] + w[i]) | |
local t2 = (s0 + maj) | |
h, g, f, e, d, c, b, a = | |
g, f, e, d+t1, c, b, a, t1+t2 | |
end | |
a,b,c,d,e,f,g,h=_a+a,_b+b,_c+c,_d+d,_e+e,_f+f,_g+g,_h+h | |
end | |
self[1],self[2],self[3],self[4],self[5],self[6],self[7],self[8] = | |
a,b,c,d,e,f,g,h | |
self.total, self.input = | |
self.total + pos - 1, input:sub(pos) | |
return self | |
end | |
function mt:final(str) | |
if str then self:update(str) end | |
local inlen = #self.input | |
self:update("\x80" .. s.rep("\x00", ((inlen < 55) and (55 - inlen)) or (119 - inlen)) .. | |
s.dumpint((self.total + inlen) << 3, 8, "b")) | |
return self | |
end | |
function mt:hex() | |
return s.format(s.rep("%08x", 8), t.unpack(self)) | |
end | |
function mt:digest() | |
local res = {} | |
for i=1,8 do res[i] = s.dumpint(self[i], 4, "b") end | |
return t.concat(res) | |
end | |
function mt:__call(str) | |
local r = sm({}, mt) | |
return str and r:final(str):hex() or r | |
end | |
mt.__index = mt | |
mt.input = "" | |
mt.total = 0 | |
local sha256 = sm({}, mt) | |
if not ... then | |
assert(sha256("abc") | |
=='ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad') | |
assert(sha256('This is exactly 64 bytes long, not counting the terminating byte') | |
=='ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8') | |
assert(sha256('For this sample, this 63-byte string will be used as input data') | |
=='f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342') | |
assert(sha256() | |
:update('etwetewutyweituweytuiqoqteyquotyeoqewovbdaljdasghdlashgasdgasdgasdg') | |
:update('xxxxxxxxxxxx') | |
:update('wrwetwetwexxxxxxxxxxxx') | |
:update('wrewgdfjkl') | |
:final('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') | |
:hex() == '5f367286ee6d1ea7164e43420d20772dbdbd948c39e99d44cd206fe18d7248bc') | |
end | |
return sha256 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment