local n=require(script.common)local W=require(script.bit32_ops)local Y=W.uint32_lrot local v=W.byte_xor local g=W.uint32_xor_3 local N=W.uint32_xor_4 local m=W.uint32_ternary local j=W.uint32_majority local d=n.bytes_to_uint32 local o=n.uint32_to_bytes local c=string.byte local Z=string.char local y=string.format local T=string.rep local function k(n)return n:gsub("\046\046",function(n)return Z(tonumber(n,16))end)end local t={}function t.sha1(n)local W=Z(128)local v=(#n+1)+8 local k=T(Z(0),-v%64)local t=Z(0,0,0,0,o(#n*8))n=n..(W..(k..t))assert(#n%64==0,"")local a=1732584193 local q=4023233417 local E=2562383102 local P=271733878 local S=3285377520 local p={}for W=1,#n,64 do local v=W for W=0,15,1 do p[W]=d(c(n,v,v+3))v=v+4 end for n=16,79,1 do p[n]=Y(N(p[n-3],p[n-8],p[n-14],p[n-16]),1)end local o=a local Z=q local y=E local T=P local k=S for n=0,79,1 do local W local v if n<=19 then W=m(Z,y,T)v=1518500249 elseif n<=39 then W=g(Z,y,T)v=1859775393 elseif n<=59 then W=j(Z,y,T)v=2400959708 else W=g(Z,y,T)v=3395469782 end local N=((((Y(o,5)+W)+k)+v)+p[n])%4294967296 k=T T=y y=Y(Z,30)Z=o o=N end a=(a+o)%4294967296 q=(q+Z)%4294967296 E=(E+y)%4294967296 P=(P+T)%4294967296 S=(S+k)%4294967296 end return y("\037\048\056\120\037\048\056\120\037\048\056\120\037\048\056\120\037\048\056\120",a,q,E,P,S)end function t.binary(n)return k(t.sha1(n))end local a={}local q={}for n=0,255,1 do a[Z(n)]=Z(v(92,n))q[Z(n)]=Z(v(54,n))end local E=64 function t.hmac(n,W)if#n>E then n=t.binary(n)end local Y=n:gsub("\046",q)..T(Z(54),E-#n)local v=n:gsub("\046",a)..T(Z(92),E-#n)return t.sha1(v..t.binary(Y..W))end function t.hmac_binary(n,W)return k(t.hmac(n,W))end setmetatable(t,{__call=function(n,W)return t.sha1(W)end})return t
local common = require(script.common)
local ops = require(script.bit32_ops)
local uint32_lrot = ops.uint32_lrot
local byte_xor = ops.byte_xor
local uint32_xor_3 = ops.uint32_xor_3
local uint32_xor_4 = ops.uint32_xor_4
local uint32_ternary = ops.uint32_ternary
local uint32_majority = ops.uint32_majority

local bytes_to_uint32 = common.bytes_to_uint32
local uint32_to_bytes = common.uint32_to_bytes

local sbyte = string.byte
local schar = string.char
local sformat = string.format
local srep = string.rep

local function hex_to_binary(hex)
   return (hex:gsub("..", function(hexval)
      return schar(tonumber(hexval, 16))
   end))
end

local sha1 = {}

-- Calculates SHA1 for a string, returns it encoded as 40 hexadecimal digits.
function sha1.sha1(str)
   -- Input preprocessing.
   -- First, append a `1` bit and seven `0` bits.
   local first_append = schar(0x80)

   -- Next, append some zero bytes to make the length of the final message a multiple of 64.
   -- Eight more bytes will be added next.
   local non_zero_message_bytes = #str + 1 + 8
   local second_append = srep(schar(0), -non_zero_message_bytes % 64)

   -- Finally, append the length of the original message in bits as a 64-bit number.
   -- Assume that it fits into the lower 32 bits.
   local third_append = schar(0, 0, 0, 0, uint32_to_bytes(#str * 8))

   str = str .. first_append .. second_append .. third_append
   assert(#str % 64 == 0, "")

   -- Initialize hash value.
   local h0 = 0x67452301
   local h1 = 0xEFCDAB89
   local h2 = 0x98BADCFE
   local h3 = 0x10325476
   local h4 = 0xC3D2E1F0

   local w = {}

   -- Process the input in successive 64-byte chunks.
   for chunk_start = 1, #str, 64 do
      -- Load the chunk into W[0..15] as uint32 numbers.
      local uint32_start = chunk_start

      for i = 0, 15 do
         w[i] = bytes_to_uint32(sbyte(str, uint32_start, uint32_start + 3))
         uint32_start = uint32_start + 4
      end

      -- Extend the input vector.
      for i = 16, 79 do
         w[i] = uint32_lrot(uint32_xor_4(w[i - 3], w[i - 8], w[i - 14], w[i - 16]), 1)
      end

      -- Initialize hash value for this chunk.
      local a = h0
      local b = h1
      local c = h2
      local d = h3
      local e = h4

      -- Main loop.
      for i = 0, 79 do
         local f
         local k

         if i <= 19 then
            f = uint32_ternary(b, c, d)
            k = 0x5A827999
         elseif i <= 39 then
            f = uint32_xor_3(b, c, d)
            k = 0x6ED9EBA1
         elseif i <= 59 then
            f = uint32_majority(b, c, d)
            k = 0x8F1BBCDC
         else
            f = uint32_xor_3(b, c, d)
            k = 0xCA62C1D6
         end

         local temp = (uint32_lrot(a, 5) + f + e + k + w[i]) % 4294967296
         e = d
         d = c
         c = uint32_lrot(b, 30)
         b = a
         a = temp
      end

      -- Add this chunk's hash to result so far.
      h0 = (h0 + a) % 4294967296
      h1 = (h1 + b) % 4294967296
      h2 = (h2 + c) % 4294967296
      h3 = (h3 + d) % 4294967296
      h4 = (h4 + e) % 4294967296
   end

   return sformat("%08x%08x%08x%08x%08x", h0, h1, h2, h3, h4)
end

function sha1.binary(str)
   return hex_to_binary(sha1.sha1(str))
end

-- Precalculate replacement tables.
local xor_with_0x5c = {}
local xor_with_0x36 = {}

for i = 0, 0xff do
   xor_with_0x5c[schar(i)] = schar(byte_xor(0x5c, i))
   xor_with_0x36[schar(i)] = schar(byte_xor(0x36, i))
end

-- 512 bits.
local BLOCK_SIZE = 64

function sha1.hmac(key, text)
   if #key > BLOCK_SIZE then
      key = sha1.binary(key)
   end

   local key_xord_with_0x36 = key:gsub('.', xor_with_0x36) .. srep(schar(0x36), BLOCK_SIZE - #key)
   local key_xord_with_0x5c = key:gsub('.', xor_with_0x5c) .. srep(schar(0x5c), BLOCK_SIZE - #key)

   return sha1.sha1(key_xord_with_0x5c .. sha1.binary(key_xord_with_0x36 .. text))
end

function sha1.hmac_binary(key, text)
   return hex_to_binary(sha1.hmac(key, text))
end

setmetatable(
   sha1,
   {
      __call = function(_, str)
         return sha1.sha1(str)
      end
   }
)

return sha1
