Skip to content

Instantly share code, notes, and snippets.

@katlogic
Created August 6, 2014 15:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save katlogic/1cfe0dee78fba51324b4 to your computer and use it in GitHub Desktop.
Save katlogic/1cfe0dee78fba51324b4 to your computer and use it in GitHub Desktop.
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