Advertisement
PG23186706924

ecc.lua

Feb 12th, 2019 (edited)
2,683
2
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 52.46 KB | None | 2 0
  1. -- Elliptic Curve Cryptography in Computercraft
  2.  
  3. ---- Update (Jun  7 2023)
  4. -- Fix string inputs not working on signatures
  5. -- Switch internal byte arrays to strings on most places
  6. -- Improve entropy gathering by using counting
  7. -- Other general improvements to syntax
  8. ---- Update (Jun  4 2021)
  9. -- Fix compatibility with CraftOS-PC
  10. ---- Update (Jul 30 2020)
  11. -- Make randomModQ and use it instead of hashing from random.random()
  12. ---- Update (Feb 10 2020)
  13. -- Make a more robust encoding/decoding implementation
  14. ---- Update (Dec 30 2019)
  15. -- Fix rng not accumulating entropy from loop
  16. -- (older versions should be fine from other sources + stored in disk)
  17. ---- Update (Dec 28 2019)
  18. -- Slightly better integer multiplication and squaring
  19. -- Fix global variable declarations in modQ division and verify() (no security concerns)
  20. -- Small tweaks from SquidDev's illuaminate (https://github.com/SquidDev/illuaminate/)
  21.  
  22. local function mapToStr(t)
  23.     if type(t) == "table" then
  24.         return string.char(unpack(t))
  25.     else
  26.         return tostring(t)
  27.     end
  28. end
  29.  
  30. local byteTableMT = {
  31.     __tostring = mapToStr,
  32.     __index = {
  33.         toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end,
  34.         isEqual = function(self, t)
  35.             if type(t) ~= "table" then return false end
  36.             if #self ~= #t then return false end
  37.             local ret = 0
  38.             for i = 1, #self do
  39.                 ret = bit32.bor(ret, bit32.bxor(self[i], t[i]))
  40.             end
  41.             return ret == 0
  42.         end
  43.     }
  44. }
  45.  
  46. local function strToByteArr(s)
  47.     return setmetatable({s:byte(1, -1)}, byteTableMT)
  48. end
  49.  
  50. -- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
  51. -- By Anavrins
  52. -- For help and details, you can PM me on the CC forums
  53. -- You may use this code in your projects without asking me, as long as credit is given and this header is kept intact
  54. -- http://www.computercraft.info/forums2/index.php?/user/12870-anavrins
  55. -- http://pastebin.com/6UV4qfNF
  56. -- Last update: October 10, 2017
  57. local sha256 = (function()
  58.     local mod32 = 2^32
  59.     local band    = bit32 and bit32.band or bit.band
  60.     local bnot    = bit32 and bit32.bnot or bit.bnot
  61.     local bxor    = bit32 and bit32.bxor or bit.bxor
  62.     local blshift = bit32 and bit32.lshift or bit.blshift
  63.     local upack   = unpack
  64.  
  65.     local function rrotate(n, b)
  66.         local s = n/(2^b)
  67.         local f = s%1
  68.         return (s-f) + f*mod32
  69.     end
  70.     local function brshift(int, by) -- Thanks bit32 for bad rshift
  71.         local s = int / (2^by)
  72.         return s - s%1
  73.     end
  74.  
  75.     local H = {
  76.         0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  77.         0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
  78.     }
  79.  
  80.     local K = {
  81.         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  82.         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  83.         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  84.         0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  85.         0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  86.         0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  87.         0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  88.         0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
  89.     }
  90.  
  91.     local function counter(incr)
  92.         local t1, t2 = 0, 0
  93.         if 0xFFFFFFFF - t1 < incr then
  94.             t2 = t2 + 1
  95.             t1 = incr - (0xFFFFFFFF - t1) - 1
  96.         else t1 = t1 + incr
  97.         end
  98.         return t2, t1
  99.     end
  100.  
  101.     local function BE_toInt(bs, i)
  102.         return blshift((bs[i] or 0), 24) + blshift((bs[i+1] or 0), 16) + blshift((bs[i+2] or 0), 8) + (bs[i+3] or 0)
  103.     end
  104.  
  105.     local function preprocess(data)
  106.         local len = #data
  107.         local proc = {}
  108.         data[#data+1] = 0x80
  109.         while #data%64~=56 do data[#data+1] = 0 end
  110.         local blocks = math.ceil(#data/64)
  111.         for i = 1, blocks do
  112.             proc[i] = {}
  113.             for j = 1, 16 do
  114.                 proc[i][j] = BE_toInt(data, 1+((i-1)*64)+((j-1)*4))
  115.             end
  116.         end
  117.         proc[blocks][15], proc[blocks][16] = counter(len*8)
  118.         return proc
  119.     end
  120.  
  121.     local function digestblock(w, C)
  122.         for j = 17, 64 do
  123.             local s0 = bxor(bxor(rrotate(w[j-15], 7), rrotate(w[j-15], 18)), brshift(w[j-15], 3))
  124.             local s1 = bxor(bxor(rrotate(w[j-2], 17), rrotate(w[j-2], 19)), brshift(w[j-2], 10))
  125.             w[j] = (w[j-16] + s0 + w[j-7] + s1)%mod32
  126.         end
  127.         local a, b, c, d, e, f, g, h = upack(C)
  128.         for j = 1, 64 do
  129.             local S1 = bxor(bxor(rrotate(e, 6), rrotate(e, 11)), rrotate(e, 25))
  130.             local ch = bxor(band(e, f), band(bnot(e), g))
  131.             local temp1 = (h + S1 + ch + K[j] + w[j])%mod32
  132.             local S0 = bxor(bxor(rrotate(a, 2), rrotate(a, 13)), rrotate(a, 22))
  133.             local maj = bxor(bxor(band(a, b), band(a, c)), band(b, c))
  134.             local temp2 = (S0 + maj)%mod32
  135.             h, g, f, e, d, c, b, a = g, f, e, (d+temp1)%mod32, c, b, a, (temp1+temp2)%mod32
  136.         end
  137.         C[1] = (C[1] + a)%mod32
  138.         C[2] = (C[2] + b)%mod32
  139.         C[3] = (C[3] + c)%mod32
  140.         C[4] = (C[4] + d)%mod32
  141.         C[5] = (C[5] + e)%mod32
  142.         C[6] = (C[6] + f)%mod32
  143.         C[7] = (C[7] + g)%mod32
  144.         C[8] = (C[8] + h)%mod32
  145.         return C
  146.     end
  147.  
  148.     local function toBytes(t, n)
  149.         local b = {}
  150.         for i = 1, n do
  151.             b[(i-1)*4+1] = band(brshift(t[i], 24), 0xFF)
  152.             b[(i-1)*4+2] = band(brshift(t[i], 16), 0xFF)
  153.             b[(i-1)*4+3] = band(brshift(t[i], 8), 0xFF)
  154.             b[(i-1)*4+4] = band(t[i], 0xFF)
  155.         end
  156.         return setmetatable(b, byteTableMT)
  157.     end
  158.  
  159.     local function digest(data)
  160.         data = preprocess(strToByteArr(mapToStr(data or "")))
  161.         local C = {upack(H)}
  162.         for i = 1, #data do C = digestblock(data[i], C) end
  163.         return toBytes(C, 8)
  164.     end
  165.  
  166.     local function hmac(data, key)
  167.         data = strToByteArr(mapToStr(data))
  168.         key = mapToStr(key)
  169.  
  170.         local blocksize = 64
  171.  
  172.         key = #key > blocksize and digest(key) or strToByteArr(key)
  173.  
  174.         local ipad = {}
  175.         local opad = {}
  176.         local padded_key = {}
  177.  
  178.         for i = 1, blocksize do
  179.             ipad[i] = bxor(0x36, key[i] or 0)
  180.             opad[i] = bxor(0x5C, key[i] or 0)
  181.         end
  182.  
  183.         for i = 1, #data do
  184.             ipad[blocksize+i] = data[i]
  185.         end
  186.  
  187.         ipad = digest(ipad)
  188.  
  189.         for i = 1, blocksize do
  190.             padded_key[i] = opad[i]
  191.             padded_key[blocksize+i] = ipad[i]
  192.         end
  193.  
  194.         return digest(padded_key)
  195.     end
  196.  
  197.     local function pbkdf2(pass, salt, iter, dklen)
  198.         salt = strToByteArr(mapToStr(salt))
  199.         local hashlen = 32
  200.         iter = tonumber(iter) or 1000
  201.         dklen = tonumber(dklen) or 32
  202.         local block = 1
  203.         local out = {}
  204.  
  205.         while dklen > 0 do
  206.             local ikey = {}
  207.             local isalt = {upack(salt)}
  208.             local clen = dklen > hashlen and hashlen or dklen
  209.  
  210.             isalt[#isalt+1] = band(brshift(block, 24), 0xFF)
  211.             isalt[#isalt+1] = band(brshift(block, 16), 0xFF)
  212.             isalt[#isalt+1] = band(brshift(block, 8), 0xFF)
  213.             isalt[#isalt+1] = band(block, 0xFF)
  214.  
  215.             for j = 1, iter do
  216.                 isalt = hmac(isalt, mapToStr(pass))
  217.                 for k = 1, clen do ikey[k] = bxor(isalt[k], ikey[k] or 0) end
  218.                 if j % 200 == 0 then os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") end
  219.             end
  220.             dklen = dklen - clen
  221.             block = block+1
  222.             for k = 1, clen do out[#out+1] = ikey[k] end
  223.         end
  224.  
  225.         return setmetatable(out, byteTableMT)
  226.     end
  227.  
  228.     return {
  229.         digest = digest,
  230.         hmac = hmac,
  231.         pbkdf2 = pbkdf2
  232.     }
  233. end)()
  234.  
  235. -- Chacha20 cipher in ComputerCraft
  236. -- By Anavrins
  237. -- For help and details, you can PM me on the CC forums
  238. -- You may use this code in your projects without asking me, as long as credit is given and this header is kept intact
  239. -- http://www.computercraft.info/forums2/index.php?/user/12870-anavrins
  240. -- http://pastebin.com/GPzf9JSa
  241. -- Last update: April 17, 2017
  242. local chacha20 = (function()
  243.     local bxor = bit32.bxor
  244.     local band = bit32.band
  245.     local blshift = bit32.lshift
  246.     local brshift = bit32.arshift
  247.  
  248.     local mod = 2^32
  249.     local tau = {("expand 16-byte k"):byte(1,-1)}
  250.     local sigma = {("expand 32-byte k"):byte(1,-1)}
  251.  
  252.     local function rotl(n, b)
  253.         local s = n/(2^(32-b))
  254.         local f = s%1
  255.         return (s-f) + f*mod
  256.     end
  257.  
  258.     local function quarterRound(s, a, b, c, d)
  259.         s[a] = (s[a]+s[b])%mod; s[d] = rotl(bxor(s[d], s[a]), 16)
  260.         s[c] = (s[c]+s[d])%mod; s[b] = rotl(bxor(s[b], s[c]), 12)
  261.         s[a] = (s[a]+s[b])%mod; s[d] = rotl(bxor(s[d], s[a]), 8)
  262.         s[c] = (s[c]+s[d])%mod; s[b] = rotl(bxor(s[b], s[c]), 7)
  263.         return s
  264.     end
  265.  
  266.     local function hashBlock(state, rnd)
  267.         local s = {unpack(state)}
  268.         for i = 1, rnd do
  269.             local r = i%2==1
  270.             s = r and quarterRound(s, 1, 5,  9, 13) or quarterRound(s, 1, 6, 11, 16)
  271.             s = r and quarterRound(s, 2, 6, 10, 14) or quarterRound(s, 2, 7, 12, 13)
  272.             s = r and quarterRound(s, 3, 7, 11, 15) or quarterRound(s, 3, 8,  9, 14)
  273.             s = r and quarterRound(s, 4, 8, 12, 16) or quarterRound(s, 4, 5, 10, 15)
  274.         end
  275.         for i = 1, 16 do s[i] = (s[i]+state[i])%mod end
  276.         return s
  277.     end
  278.  
  279.     local function LE_toInt(bs, i)
  280.         return (bs[i+1] or 0)+
  281.         blshift((bs[i+2] or 0), 8)+
  282.         blshift((bs[i+3] or 0), 16)+
  283.         blshift((bs[i+4] or 0), 24)
  284.     end
  285.  
  286.     local function initState(key, nonce, counter)
  287.         local isKey256 = #key == 32
  288.         local const = isKey256 and sigma or tau
  289.         local state = {}
  290.  
  291.         state[ 1] = LE_toInt(const, 0)
  292.         state[ 2] = LE_toInt(const, 4)
  293.         state[ 3] = LE_toInt(const, 8)
  294.         state[ 4] = LE_toInt(const, 12)
  295.  
  296.         state[ 5] = LE_toInt(key, 0)
  297.         state[ 6] = LE_toInt(key, 4)
  298.         state[ 7] = LE_toInt(key, 8)
  299.         state[ 8] = LE_toInt(key, 12)
  300.         state[ 9] = LE_toInt(key, isKey256 and 16 or 0)
  301.         state[10] = LE_toInt(key, isKey256 and 20 or 4)
  302.         state[11] = LE_toInt(key, isKey256 and 24 or 8)
  303.         state[12] = LE_toInt(key, isKey256 and 28 or 12)
  304.  
  305.         state[13] = counter
  306.         state[14] = LE_toInt(nonce, 0)
  307.         state[15] = LE_toInt(nonce, 4)
  308.         state[16] = LE_toInt(nonce, 8)
  309.  
  310.         return state
  311.     end
  312.  
  313.     local function serialize(state)
  314.         local r = {}
  315.         for i = 1, 16 do
  316.             r[#r+1] = band(state[i], 0xFF)
  317.             r[#r+1] = band(brshift(state[i], 8), 0xFF)
  318.             r[#r+1] = band(brshift(state[i], 16), 0xFF)
  319.             r[#r+1] = band(brshift(state[i], 24), 0xFF)
  320.         end
  321.         return r
  322.     end
  323.  
  324.     local function crypt(data, key, nonce, cntr, round)
  325.         data = strToByteArr(mapToStr(data))
  326.         key = strToByteArr(mapToStr(key))
  327.         nonce = strToByteArr(mapToStr(nonce))
  328.         assert(#key == 16 or #key == 32, "ChaCha20: Invalid key length ("..#key.."), must be 16 or 32")
  329.         assert(#nonce == 12, "ChaCha20: Invalid nonce length ("..#nonce.."), must be 12")
  330.         cntr = tonumber(cntr) or 1
  331.         round = tonumber(round) or 20
  332.  
  333.         local out = {}
  334.         local state = initState(key, nonce, cntr)
  335.         local blockAmt = math.floor(#data/64)
  336.         for i = 0, blockAmt do
  337.             local ks = serialize(hashBlock(state, round))
  338.             state[13] = (state[13]+1) % mod
  339.  
  340.             local block = {}
  341.             for j = 1, 64 do
  342.                 block[j] = data[((i)*64)+j]
  343.             end
  344.             for j = 1, #block do
  345.                 out[#out+1] = bxor(block[j], ks[j])
  346.             end
  347.  
  348.             if i % 1000 == 0 then
  349.                 os.queueEvent("")
  350.                 os.pullEvent("")
  351.             end
  352.         end
  353.         return setmetatable(out, byteTableMT)
  354.     end
  355.  
  356.     return {
  357.         crypt = crypt
  358.     }
  359. end)()
  360.  
  361. -- random.lua - Random Byte Generator
  362. local random = (function()
  363.     local entropy = ""
  364.     local accumulator = ""
  365.     local entropyPath = "/.random"
  366.  
  367.     local function feed(data)
  368.         accumulator = accumulator .. (data or "")
  369.     end
  370.  
  371.     local function digest()
  372.         entropy = tostring(sha256.digest(entropy .. accumulator))
  373.         accumulator = ""
  374.     end
  375.  
  376.     if fs.exists(entropyPath) then
  377.         local entropyFile = fs.open(entropyPath, "rb")
  378.         feed(entropyFile.readAll())
  379.         entropyFile.close()
  380.     end
  381.  
  382.     -- Add context.
  383.     feed("init")
  384.     feed(tostring(math.random(1, 2^31 - 1)))
  385.     feed("|")
  386.     feed(tostring(math.random(1, 2^31 - 1)))
  387.     feed("|")
  388.     feed(tostring(math.random(1, 2^4)))
  389.     feed("|")
  390.     feed(tostring(os.epoch("utc")))
  391.     feed("|")
  392.     feed(tostring({}))
  393.     feed(tostring({}))
  394.     digest()
  395.     feed(tostring(os.epoch("utc")))
  396.     digest()
  397.  
  398.     -- Add entropy by counting.
  399.     local countTable = {}
  400.     local inner = "function()return{" .. ("e'utc',"):rep(256) .. "}end"
  401.     local countf = assert(load("local e=os.epoch return " .. inner))()
  402.     for i = 1, 300 do
  403.         while true do
  404.             local t = countf()
  405.             local t1 = t[1]
  406.             if t1 ~= t[256] then
  407.                 for j = 1, 256 do
  408.                     if t1 ~= t[j] then
  409.                         countTable[i] = j - 1
  410.                         break
  411.                     end
  412.                 end
  413.                 break
  414.             end
  415.         end
  416.     end
  417.  
  418.     feed(mapToStr(countTable))
  419.     digest()
  420.  
  421.     local function save()
  422.         feed("save")
  423.         feed(tostring(os.epoch("utc")))
  424.         feed(tostring({}))
  425.         digest()
  426.  
  427.         local entropyFile = fs.open(entropyPath, "wb")
  428.         entropyFile.write(tostring(sha256.hmac("save", entropy)))
  429.         entropy = tostring(sha256.digest(entropy))
  430.         entropyFile.close()
  431.     end
  432.     save()
  433.  
  434.     local function seed(data)
  435.         feed("seed")
  436.         feed(tostring(os.epoch("utc")))
  437.         feed(tostring({}))
  438.         feed(mapToStr(data))
  439.         digest()
  440.         save()
  441.     end
  442.  
  443.     local function random()
  444.         feed("random")
  445.         feed(tostring(os.epoch("utc")))
  446.         feed(tostring({}))
  447.         digest()
  448.         save()
  449.  
  450.         local result = sha256.hmac("out", entropy)
  451.         entropy = tostring(sha256.digest(entropy))
  452.  
  453.         return result
  454.     end
  455.  
  456.     return {
  457.         seed = seed,
  458.         save = save,
  459.         random = random
  460.     }
  461. end)()
  462.  
  463. -- Big integer arithmetic for 168-bit (and 336-bit) numbers
  464. -- Numbers are represented as little-endian tables of 24-bit integers
  465. local arith = (function()
  466.     local function isEqual(a, b)
  467.         return (
  468.             a[1] == b[1]
  469.             and a[2] == b[2]
  470.             and a[3] == b[3]
  471.             and a[4] == b[4]
  472.             and a[5] == b[5]
  473.             and a[6] == b[6]
  474.             and a[7] == b[7]
  475.         )
  476.     end
  477.  
  478.     local function compare(a, b)
  479.         for i = 7, 1, -1 do
  480.             if a[i] > b[i] then
  481.                 return 1
  482.             elseif a[i] < b[i] then
  483.                 return -1
  484.             end
  485.         end
  486.  
  487.         return 0
  488.     end
  489.  
  490.     local function add(a, b)
  491.         -- c7 may be greater than 2^24 before reduction
  492.         local c1 = a[1] + b[1]
  493.         local c2 = a[2] + b[2]
  494.         local c3 = a[3] + b[3]
  495.         local c4 = a[4] + b[4]
  496.         local c5 = a[5] + b[5]
  497.         local c6 = a[6] + b[6]
  498.         local c7 = a[7] + b[7]
  499.  
  500.         if c1 > 0xffffff then
  501.             c2 = c2 + 1
  502.             c1 = c1 - 0x1000000
  503.         end
  504.         if c2 > 0xffffff then
  505.             c3 = c3 + 1
  506.             c2 = c2 - 0x1000000
  507.         end
  508.         if c3 > 0xffffff then
  509.             c4 = c4 + 1
  510.             c3 = c3 - 0x1000000
  511.         end
  512.         if c4 > 0xffffff then
  513.             c5 = c5 + 1
  514.             c4 = c4 - 0x1000000
  515.         end
  516.         if c5 > 0xffffff then
  517.             c6 = c6 + 1
  518.             c5 = c5 - 0x1000000
  519.         end
  520.         if c6 > 0xffffff then
  521.             c7 = c7 + 1
  522.             c6 = c6 - 0x1000000
  523.         end
  524.  
  525.         return {c1, c2, c3, c4, c5, c6, c7}
  526.     end
  527.  
  528.     local function sub(a, b)
  529.         -- c7 may be negative before reduction
  530.         local c1 = a[1] - b[1]
  531.         local c2 = a[2] - b[2]
  532.         local c3 = a[3] - b[3]
  533.         local c4 = a[4] - b[4]
  534.         local c5 = a[5] - b[5]
  535.         local c6 = a[6] - b[6]
  536.         local c7 = a[7] - b[7]
  537.  
  538.         if c1 < 0 then
  539.             c2 = c2 - 1
  540.             c1 = c1 + 0x1000000
  541.         end
  542.         if c2 < 0 then
  543.             c3 = c3 - 1
  544.             c2 = c2 + 0x1000000
  545.         end
  546.         if c3 < 0 then
  547.             c4 = c4 - 1
  548.             c3 = c3 + 0x1000000
  549.         end
  550.         if c4 < 0 then
  551.             c5 = c5 - 1
  552.             c4 = c4 + 0x1000000
  553.         end
  554.         if c5 < 0 then
  555.             c6 = c6 - 1
  556.             c5 = c5 + 0x1000000
  557.         end
  558.         if c6 < 0 then
  559.             c7 = c7 - 1
  560.             c6 = c6 + 0x1000000
  561.         end
  562.  
  563.         return {c1, c2, c3, c4, c5, c6, c7}
  564.     end
  565.  
  566.     local function rShift(a)
  567.         local c1 = a[1]
  568.         local c2 = a[2]
  569.         local c3 = a[3]
  570.         local c4 = a[4]
  571.         local c5 = a[5]
  572.         local c6 = a[6]
  573.         local c7 = a[7]
  574.  
  575.         c1 = c1 / 2
  576.         c1 = c1 - c1 % 1
  577.         c1 = c1 + (c2 % 2) * 0x800000
  578.         c2 = c2 / 2
  579.         c2 = c2 - c2 % 1
  580.         c2 = c2 + (c3 % 2) * 0x800000
  581.         c3 = c3 / 2
  582.         c3 = c3 - c3 % 1
  583.         c3 = c3 + (c4 % 2) * 0x800000
  584.         c4 = c4 / 2
  585.         c4 = c4 - c4 % 1
  586.         c4 = c4 + (c5 % 2) * 0x800000
  587.         c5 = c5 / 2
  588.         c5 = c5 - c5 % 1
  589.         c5 = c5 + (c6 % 2) * 0x800000
  590.         c6 = c6 / 2
  591.         c6 = c6 - c6 % 1
  592.         c6 = c6 + (c7 % 2) * 0x800000
  593.         c7 = c7 / 2
  594.         c7 = c7 - c7 % 1
  595.  
  596.         return {c1, c2, c3, c4, c5, c6, c7}
  597.     end
  598.  
  599.     local function addDouble(a, b)
  600.         -- a and b are 336-bit integers (14 words)
  601.         local c1 = a[1] + b[1]
  602.         local c2 = a[2] + b[2]
  603.         local c3 = a[3] + b[3]
  604.         local c4 = a[4] + b[4]
  605.         local c5 = a[5] + b[5]
  606.         local c6 = a[6] + b[6]
  607.         local c7 = a[7] + b[7]
  608.         local c8 = a[8] + b[8]
  609.         local c9 = a[9] + b[9]
  610.         local c10 = a[10] + b[10]
  611.         local c11 = a[11] + b[11]
  612.         local c12 = a[12] + b[12]
  613.         local c13 = a[13] + b[13]
  614.         local c14 = a[14] + b[14]
  615.  
  616.         if c1 > 0xffffff then
  617.             c2 = c2 + 1
  618.             c1 = c1 - 0x1000000
  619.         end
  620.         if c2 > 0xffffff then
  621.             c3 = c3 + 1
  622.             c2 = c2 - 0x1000000
  623.         end
  624.         if c3 > 0xffffff then
  625.             c4 = c4 + 1
  626.             c3 = c3 - 0x1000000
  627.         end
  628.         if c4 > 0xffffff then
  629.             c5 = c5 + 1
  630.             c4 = c4 - 0x1000000
  631.         end
  632.         if c5 > 0xffffff then
  633.             c6 = c6 + 1
  634.             c5 = c5 - 0x1000000
  635.         end
  636.         if c6 > 0xffffff then
  637.             c7 = c7 + 1
  638.             c6 = c6 - 0x1000000
  639.         end
  640.         if c7 > 0xffffff then
  641.             c8 = c8 + 1
  642.             c7 = c7 - 0x1000000
  643.         end
  644.         if c8 > 0xffffff then
  645.             c9 = c9 + 1
  646.             c8 = c8 - 0x1000000
  647.         end
  648.         if c9 > 0xffffff then
  649.             c10 = c10 + 1
  650.             c9 = c9 - 0x1000000
  651.         end
  652.         if c10 > 0xffffff then
  653.             c11 = c11 + 1
  654.             c10 = c10 - 0x1000000
  655.         end
  656.         if c11 > 0xffffff then
  657.             c12 = c12 + 1
  658.             c11 = c11 - 0x1000000
  659.         end
  660.         if c12 > 0xffffff then
  661.             c13 = c13 + 1
  662.             c12 = c12 - 0x1000000
  663.         end
  664.         if c13 > 0xffffff then
  665.             c14 = c14 + 1
  666.             c13 = c13 - 0x1000000
  667.         end
  668.  
  669.         return {c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14}
  670.     end
  671.  
  672.     local function mult(a, b, half_multiply)
  673.         local a1, a2, a3, a4, a5, a6, a7 = unpack(a)
  674.         local b1, b2, b3, b4, b5, b6, b7 = unpack(b)
  675.  
  676.         local c1 = a1 * b1
  677.         local c2 = a1 * b2 + a2 * b1
  678.         local c3 = a1 * b3 + a2 * b2 + a3 * b1
  679.         local c4 = a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1
  680.         local c5 = a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1
  681.         local c6 = a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1
  682.         local c7 = a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2
  683.                    + a7 * b1
  684.         local c8, c9, c10, c11, c12, c13, c14
  685.         if not half_multiply then
  686.             c8 = a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2
  687.             c9 = a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3
  688.             c10 = a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4
  689.             c11 = a5 * b7 + a6 * b6 + a7 * b5
  690.             c12 = a6 * b7 + a7 * b6
  691.             c13 = a7 * b7
  692.             c14 = 0
  693.         else
  694.             c8 = 0
  695.         end
  696.  
  697.         local temp
  698.         temp = c1
  699.         c1 = c1 % 0x1000000
  700.         c2 = c2 + (temp - c1) / 0x1000000
  701.         temp = c2
  702.         c2 = c2 % 0x1000000
  703.         c3 = c3 + (temp - c2) / 0x1000000
  704.         temp = c3
  705.         c3 = c3 % 0x1000000
  706.         c4 = c4 + (temp - c3) / 0x1000000
  707.         temp = c4
  708.         c4 = c4 % 0x1000000
  709.         c5 = c5 + (temp - c4) / 0x1000000
  710.         temp = c5
  711.         c5 = c5 % 0x1000000
  712.         c6 = c6 + (temp - c5) / 0x1000000
  713.         temp = c6
  714.         c6 = c6 % 0x1000000
  715.         c7 = c7 + (temp - c6) / 0x1000000
  716.         temp = c7
  717.         c7 = c7 % 0x1000000
  718.         if not half_multiply then
  719.             c8 = c8 + (temp - c7) / 0x1000000
  720.             temp = c8
  721.             c8 = c8 % 0x1000000
  722.             c9 = c9 + (temp - c8) / 0x1000000
  723.             temp = c9
  724.             c9 = c9 % 0x1000000
  725.             c10 = c10 + (temp - c9) / 0x1000000
  726.             temp = c10
  727.             c10 = c10 % 0x1000000
  728.             c11 = c11 + (temp - c10) / 0x1000000
  729.             temp = c11
  730.             c11 = c11 % 0x1000000
  731.             c12 = c12 + (temp - c11) / 0x1000000
  732.             temp = c12
  733.             c12 = c12 % 0x1000000
  734.             c13 = c13 + (temp - c12) / 0x1000000
  735.             temp = c13
  736.             c13 = c13 % 0x1000000
  737.             c14 = c14 + (temp - c13) / 0x1000000
  738.         end
  739.  
  740.         return {c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14}
  741.     end
  742.  
  743.     local function square(a)
  744.         -- returns a 336-bit integer (14 words)
  745.         local a1, a2, a3, a4, a5, a6, a7 = unpack(a)
  746.  
  747.         local c1 = a1 * a1
  748.         local c2 = a1 * a2 * 2
  749.         local c3 = a1 * a3 * 2 + a2 * a2
  750.         local c4 = a1 * a4 * 2 + a2 * a3 * 2
  751.         local c5 = a1 * a5 * 2 + a2 * a4 * 2 + a3 * a3
  752.         local c6 = a1 * a6 * 2 + a2 * a5 * 2 + a3 * a4 * 2
  753.         local c7 = a1 * a7 * 2 + a2 * a6 * 2 + a3 * a5 * 2 + a4 * a4
  754.         local c8 = a2 * a7 * 2 + a3 * a6 * 2 + a4 * a5 * 2
  755.         local c9 = a3 * a7 * 2 + a4 * a6 * 2 + a5 * a5
  756.         local c10 = a4 * a7 * 2 + a5 * a6 * 2
  757.         local c11 = a5 * a7 * 2 + a6 * a6
  758.         local c12 = a6 * a7 * 2
  759.         local c13 = a7 * a7
  760.         local c14 = 0
  761.  
  762.         local temp
  763.         temp = c1
  764.         c1 = c1 % 0x1000000
  765.         c2 = c2 + (temp - c1) / 0x1000000
  766.         temp = c2
  767.         c2 = c2 % 0x1000000
  768.         c3 = c3 + (temp - c2) / 0x1000000
  769.         temp = c3
  770.         c3 = c3 % 0x1000000
  771.         c4 = c4 + (temp - c3) / 0x1000000
  772.         temp = c4
  773.         c4 = c4 % 0x1000000
  774.         c5 = c5 + (temp - c4) / 0x1000000
  775.         temp = c5
  776.         c5 = c5 % 0x1000000
  777.         c6 = c6 + (temp - c5) / 0x1000000
  778.         temp = c6
  779.         c6 = c6 % 0x1000000
  780.         c7 = c7 + (temp - c6) / 0x1000000
  781.         temp = c7
  782.         c7 = c7 % 0x1000000
  783.         c8 = c8 + (temp - c7) / 0x1000000
  784.         temp = c8
  785.         c8 = c8 % 0x1000000
  786.         c9 = c9 + (temp - c8) / 0x1000000
  787.         temp = c9
  788.         c9 = c9 % 0x1000000
  789.         c10 = c10 + (temp - c9) / 0x1000000
  790.         temp = c10
  791.         c10 = c10 % 0x1000000
  792.         c11 = c11 + (temp - c10) / 0x1000000
  793.         temp = c11
  794.         c11 = c11 % 0x1000000
  795.         c12 = c12 + (temp - c11) / 0x1000000
  796.         temp = c12
  797.         c12 = c12 % 0x1000000
  798.         c13 = c13 + (temp - c12) / 0x1000000
  799.         temp = c13
  800.         c13 = c13 % 0x1000000
  801.         c14 = c14 + (temp - c13) / 0x1000000
  802.  
  803.         return {c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14}
  804.     end
  805.  
  806.     local function encodeInt(a)
  807.         local enc = {}
  808.  
  809.         for i = 1, 7 do
  810.             local word = a[i]
  811.             for j = 1, 3 do
  812.                 enc[#enc + 1] = word % 256
  813.                 word = math.floor(word / 256)
  814.             end
  815.         end
  816.  
  817.         return enc
  818.     end
  819.  
  820.     local function decodeInt(enc)
  821.         local a = {}
  822.         local encCopy = {}
  823.  
  824.         for i = 1, 21 do
  825.             local byte = enc[i]
  826.             assert(type(byte) == "number", "integer decoding failure")
  827.             assert(byte >= 0 and byte <= 255, "integer decoding failure")
  828.             assert(byte % 1 == 0, "integer decoding failure")
  829.             encCopy[i] = byte
  830.         end
  831.  
  832.         for i = 1, 21, 3 do
  833.             local word = 0
  834.             for j = 2, 0, -1 do
  835.                 word = word * 256
  836.                 word = word + encCopy[i + j]
  837.             end
  838.             a[#a + 1] = word
  839.         end
  840.  
  841.         return a
  842.     end
  843.  
  844.     local function mods(d, w)
  845.         local result = d[1] % 2^w
  846.  
  847.         if result >= 2^(w - 1) then
  848.             result = result - 2^w
  849.         end
  850.  
  851.         return result
  852.     end
  853.  
  854.     -- Represents a 168-bit number as the (2^w)-ary Non-Adjacent Form
  855.     local function NAF(d, w)
  856.         local t = {}
  857.         local d = {unpack(d)}
  858.  
  859.         for _ = 1, 168 do
  860.             if d[1] % 2 == 1 then
  861.                 t[#t + 1] = mods(d, w)
  862.                 d = sub(d, {t[#t], 0, 0, 0, 0, 0, 0})
  863.             else
  864.                 t[#t + 1] = 0
  865.             end
  866.  
  867.             d = rShift(d)
  868.         end
  869.  
  870.         return t
  871.     end
  872.  
  873.     return {
  874.         isEqual = isEqual,
  875.         compare = compare,
  876.         add = add,
  877.         sub = sub,
  878.         addDouble = addDouble,
  879.         mult = mult,
  880.         square = square,
  881.         encodeInt = encodeInt,
  882.         decodeInt = decodeInt,
  883.         NAF = NAF
  884.     }
  885. end)()
  886.  
  887. -- Arithmetic on the finite field of integers modulo p
  888. -- Where p is the finite field modulus
  889. local modp = (function()
  890.     local add = arith.add
  891.     local sub = arith.sub
  892.     local addDouble = arith.addDouble
  893.     local mult = arith.mult
  894.     local square = arith.square
  895.  
  896.     local p = {3, 0, 0, 0, 0, 0, 15761408}
  897.  
  898.     -- We're using the Montgomery Reduction for fast modular multiplication.
  899.     -- https://en.wikipedia.org/wiki/Montgomery_modular_multiplication
  900.     -- r = 2^168
  901.     -- p * pInverse = -1 (mod r)
  902.     -- r2 = r * r (mod p)
  903.     local pInverse = {5592405, 5592405, 5592405, 5592405, 5592405, 5592405, 14800213}
  904.     local r2 = {13533400, 837116, 6278376, 13533388, 837116, 6278376, 7504076}
  905.  
  906.     local function multByP(a)
  907.         local a1, a2, a3, a4, a5, a6, a7 = unpack(a)
  908.  
  909.         local c1 = a1 * 3
  910.         local c2 = a2 * 3
  911.         local c3 = a3 * 3
  912.         local c4 = a4 * 3
  913.         local c5 = a5 * 3
  914.         local c6 = a6 * 3
  915.         local c7 = a1 * 15761408
  916.         c7 = c7 + a7 * 3
  917.         local c8 = a2 * 15761408
  918.         local c9 = a3 * 15761408
  919.         local c10 = a4 * 15761408
  920.         local c11 = a5 * 15761408
  921.         local c12 = a6 * 15761408
  922.         local c13 = a7 * 15761408
  923.         local c14 = 0
  924.  
  925.         local temp
  926.         temp = c1 / 0x1000000
  927.         c2 = c2 + (temp - temp % 1)
  928.         c1 = c1 % 0x1000000
  929.         temp = c2 / 0x1000000
  930.         c3 = c3 + (temp - temp % 1)
  931.         c2 = c2 % 0x1000000
  932.         temp = c3 / 0x1000000
  933.         c4 = c4 + (temp - temp % 1)
  934.         c3 = c3 % 0x1000000
  935.         temp = c4 / 0x1000000
  936.         c5 = c5 + (temp - temp % 1)
  937.         c4 = c4 % 0x1000000
  938.         temp = c5 / 0x1000000
  939.         c6 = c6 + (temp - temp % 1)
  940.         c5 = c5 % 0x1000000
  941.         temp = c6 / 0x1000000
  942.         c7 = c7 + (temp - temp % 1)
  943.         c6 = c6 % 0x1000000
  944.         temp = c7 / 0x1000000
  945.         c8 = c8 + (temp - temp % 1)
  946.         c7 = c7 % 0x1000000
  947.         temp = c8 / 0x1000000
  948.         c9 = c9 + (temp - temp % 1)
  949.         c8 = c8 % 0x1000000
  950.         temp = c9 / 0x1000000
  951.         c10 = c10 + (temp - temp % 1)
  952.         c9 = c9 % 0x1000000
  953.         temp = c10 / 0x1000000
  954.         c11 = c11 + (temp - temp % 1)
  955.         c10 = c10 % 0x1000000
  956.         temp = c11 / 0x1000000
  957.         c12 = c12 + (temp - temp % 1)
  958.         c11 = c11 % 0x1000000
  959.         temp = c12 / 0x1000000
  960.         c13 = c13 + (temp - temp % 1)
  961.         c12 = c12 % 0x1000000
  962.         temp = c13 / 0x1000000
  963.         c14 = c14 + (temp - temp % 1)
  964.         c13 = c13 % 0x1000000
  965.  
  966.         return {c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14}
  967.     end
  968.  
  969.     -- Reduces a number from [0, 2p - 1] to [0, p - 1]
  970.     local function reduceModP(a)
  971.         -- a < p
  972.         if a[7] < 15761408 or a[7] == 15761408 and a[1] < 3 then
  973.             return {unpack(a)}
  974.         end
  975.  
  976.         -- a > p
  977.         local c1 = a[1]
  978.         local c2 = a[2]
  979.         local c3 = a[3]
  980.         local c4 = a[4]
  981.         local c5 = a[5]
  982.         local c6 = a[6]
  983.         local c7 = a[7]
  984.  
  985.         c1 = c1 - 3
  986.         c7 = c7 - 15761408
  987.  
  988.         if c1 < 0 then
  989.             c2 = c2 - 1
  990.             c1 = c1 + 0x1000000
  991.         end
  992.         if c2 < 0 then
  993.             c3 = c3 - 1
  994.             c2 = c2 + 0x1000000
  995.         end
  996.         if c3 < 0 then
  997.             c4 = c4 - 1
  998.             c3 = c3 + 0x1000000
  999.         end
  1000.         if c4 < 0 then
  1001.             c5 = c5 - 1
  1002.             c4 = c4 + 0x1000000
  1003.         end
  1004.         if c5 < 0 then
  1005.             c6 = c6 - 1
  1006.             c5 = c5 + 0x1000000
  1007.         end
  1008.         if c6 < 0 then
  1009.             c7 = c7 - 1
  1010.             c6 = c6 + 0x1000000
  1011.         end
  1012.  
  1013.         return {c1, c2, c3, c4, c5, c6, c7}
  1014.     end
  1015.  
  1016.     local function addModP(a, b)
  1017.         return reduceModP(add(a, b))
  1018.     end
  1019.  
  1020.     local function subModP(a, b)
  1021.         local result = sub(a, b)
  1022.  
  1023.         if result[7] < 0 then
  1024.             result = add(result, p)
  1025.         end
  1026.  
  1027.         return result
  1028.     end
  1029.  
  1030.     -- Montgomery REDC algorithn
  1031.     -- Reduces a number from [0, p^2 - 1] to [0, p - 1]
  1032.     local function REDC(T)
  1033.         local m = mult(T, pInverse, true)
  1034.         local t = {unpack(addDouble(T, multByP(m)), 8, 14)}
  1035.  
  1036.         return reduceModP(t)
  1037.     end
  1038.  
  1039.     local function multModP(a, b)
  1040.         -- Only works with a, b in Montgomery form
  1041.         return REDC(mult(a, b))
  1042.     end
  1043.  
  1044.     local function squareModP(a)
  1045.         -- Only works with a in Montgomery form
  1046.         return REDC(square(a))
  1047.     end
  1048.  
  1049.     local function montgomeryModP(a)
  1050.         return multModP(a, r2)
  1051.     end
  1052.  
  1053.     local function inverseMontgomeryModP(a)
  1054.         a = {unpack(a)}
  1055.  
  1056.         for i = 8, 14 do
  1057.             a[i] = 0
  1058.         end
  1059.  
  1060.         return REDC(a)
  1061.     end
  1062.  
  1063.     local ONE = montgomeryModP({1, 0, 0, 0, 0, 0, 0})
  1064.  
  1065.     local function expModP(base, exponentBinary)
  1066.         base = {unpack(base)}
  1067.         local result = {unpack(ONE)}
  1068.  
  1069.         for i = 1, 168 do
  1070.             if exponentBinary[i] == 1 then
  1071.                 result = multModP(result, base)
  1072.             end
  1073.             base = squareModP(base)
  1074.         end
  1075.  
  1076.         return result
  1077.     end
  1078.  
  1079.     return {
  1080.         addModP = addModP,
  1081.         subModP = subModP,
  1082.         multModP = multModP,
  1083.         squareModP = squareModP,
  1084.         montgomeryModP = montgomeryModP,
  1085.         inverseMontgomeryModP = inverseMontgomeryModP,
  1086.         expModP = expModP
  1087.     }
  1088. end)()
  1089.  
  1090. -- Arithmetic on the Finite Field of Integers modulo q
  1091. -- Where q is the generator's subgroup order.
  1092. local modq = (function()
  1093.     local isEqual = arith.isEqual
  1094.     local compare = arith.compare
  1095.     local add = arith.add
  1096.     local sub = arith.sub
  1097.     local addDouble = arith.addDouble
  1098.     local mult = arith.mult
  1099.     local square = arith.square
  1100.     local encodeInt = arith.encodeInt
  1101.     local decodeInt = arith.decodeInt
  1102.  
  1103.     local modQMT
  1104.  
  1105.     local q = {9622359, 6699217, 13940450, 16775734, 16777215, 16777215, 3940351}
  1106.     local qMinusTwoBinary = {1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1}
  1107.  
  1108.     -- We're using the Montgomery Reduction for fast modular multiplication.
  1109.     -- https://en.wikipedia.org/wiki/Montgomery_modular_multiplication
  1110.     -- r = 2^168
  1111.     -- q * qInverse = -1 (mod r)
  1112.     -- r2 = r * r (mod q)
  1113.     local qInverse = {15218585, 5740955, 3271338, 9903997, 9067368, 7173545, 6988392}
  1114.     local r2 = {1336213, 11071705, 9716828, 11083885, 9188643, 1494868, 3306114}
  1115.  
  1116.     -- Reduces a number from [0, 2q - 1] to [0, q - 1]
  1117.     local function reduceModQ(a)
  1118.         local result = {unpack(a)}
  1119.  
  1120.         if compare(result, q) >= 0 then
  1121.             result = sub(result, q)
  1122.         end
  1123.  
  1124.         return setmetatable(result, modQMT)
  1125.     end
  1126.  
  1127.     local function addModQ(a, b)
  1128.         return reduceModQ(add(a, b))
  1129.     end
  1130.  
  1131.     local function subModQ(a, b)
  1132.         local result = sub(a, b)
  1133.  
  1134.         if result[7] < 0 then
  1135.             result = add(result, q)
  1136.         end
  1137.  
  1138.         return setmetatable(result, modQMT)
  1139.     end
  1140.  
  1141.     -- Montgomery REDC algorithn
  1142.     -- Reduces a number from [0, q^2 - 1] to [0, q - 1]
  1143.     local function REDC(T)
  1144.         local m = {unpack(mult({unpack(T, 1, 7)}, qInverse, true), 1, 7)}
  1145.         local t = {unpack(addDouble(T, mult(m, q)), 8, 14)}
  1146.  
  1147.         return reduceModQ(t)
  1148.     end
  1149.  
  1150.     local function multModQ(a, b)
  1151.         -- Only works with a, b in Montgomery form
  1152.         return REDC(mult(a, b))
  1153.     end
  1154.  
  1155.     local function squareModQ(a)
  1156.         -- Only works with a in Montgomery form
  1157.         return REDC(square(a))
  1158.     end
  1159.  
  1160.     local function montgomeryModQ(a)
  1161.         return multModQ(a, r2)
  1162.     end
  1163.  
  1164.     local function inverseMontgomeryModQ(a)
  1165.         local a = {unpack(a)}
  1166.  
  1167.         for i = 8, 14 do
  1168.             a[i] = 0
  1169.         end
  1170.  
  1171.         return REDC(a)
  1172.     end
  1173.  
  1174.     local ONE = montgomeryModQ({1, 0, 0, 0, 0, 0, 0})
  1175.  
  1176.     local function expModQ(base, exponentBinary)
  1177.         local base = {unpack(base)}
  1178.         local result = {unpack(ONE)}
  1179.  
  1180.         for i = 1, 168 do
  1181.             if exponentBinary[i] == 1 then
  1182.                 result = multModQ(result, base)
  1183.             end
  1184.             base = squareModQ(base)
  1185.         end
  1186.  
  1187.         return result
  1188.     end
  1189.  
  1190.     local function intExpModQ(base, exponent)
  1191.         local base = {unpack(base)}
  1192.         local result = setmetatable({unpack(ONE)}, modQMT)
  1193.  
  1194.         if exponent < 0 then
  1195.             base = expModQ(base, qMinusTwoBinary)
  1196.             exponent = -exponent
  1197.         end
  1198.  
  1199.         while exponent > 0 do
  1200.             if exponent % 2 == 1 then
  1201.                 result = multModQ(result, base)
  1202.             end
  1203.             base = squareModQ(base)
  1204.             exponent = exponent / 2
  1205.             exponent = exponent - exponent % 1
  1206.         end
  1207.  
  1208.         return result
  1209.     end
  1210.  
  1211.     local function encodeModQ(a)
  1212.         local result = encodeInt(a)
  1213.  
  1214.         return setmetatable(result, byteTableMT)
  1215.     end
  1216.  
  1217.     local function decodeModQ(s)
  1218.         local result = decodeInt(strToByteArr(mapToStr(s):sub(1, 21)))
  1219.         result[7] = result[7] % q[7]
  1220.  
  1221.         return setmetatable(result, modQMT)
  1222.     end
  1223.  
  1224.     local function randomModQ()
  1225.         while true do
  1226.             local s = {unpack(random.random(), 1, 21)}
  1227.             local result = decodeInt(s)
  1228.             if result[7] < q[7] then
  1229.                 return setmetatable(result, modQMT)
  1230.             end
  1231.         end
  1232.     end
  1233.  
  1234.     local function hashModQ(data)
  1235.         return decodeModQ(sha256.digest(data))
  1236.     end
  1237.  
  1238.     modQMT = {
  1239.         __index = {
  1240.             encode = function(self)
  1241.                 return encodeModQ(self)
  1242.             end
  1243.         },
  1244.  
  1245.         __tostring = function(self)
  1246.             return self:encode():toHex()
  1247.         end,
  1248.  
  1249.         __add = function(self, other)
  1250.             if type(self) == "number" then
  1251.                 return other + self
  1252.             end
  1253.  
  1254.             if type(other) == "number" then
  1255.                 assert(other < 2^24, "number operand too big")
  1256.                 other = montgomeryModQ({other, 0, 0, 0, 0, 0, 0})
  1257.             end
  1258.  
  1259.             return addModQ(self, other)
  1260.         end,
  1261.  
  1262.         __sub = function(a, b)
  1263.             if type(a) == "number" then
  1264.                 assert(a < 2^24, "number operand too big")
  1265.                 a = montgomeryModQ({a, 0, 0, 0, 0, 0, 0})
  1266.             end
  1267.  
  1268.             if type(b) == "number" then
  1269.                 assert(b < 2^24, "number operand too big")
  1270.                 b = montgomeryModQ({b, 0, 0, 0, 0, 0, 0})
  1271.             end
  1272.  
  1273.             return subModQ(a, b)
  1274.         end,
  1275.  
  1276.         __unm = function(self)
  1277.             return subModQ(q, self)
  1278.         end,
  1279.  
  1280.         __eq = function(self, other)
  1281.             return isEqual(self, other)
  1282.         end,
  1283.  
  1284.         __mul = function(self, other)
  1285.             if type(self) == "number" then
  1286.                 return other * self
  1287.             end
  1288.  
  1289.             -- EC point
  1290.             -- Use the point's metatable to handle multiplication
  1291.             if type(other) == "table" and type(other[1]) == "table" then
  1292.                 return other * self
  1293.             end
  1294.  
  1295.             if type(other) == "number" then
  1296.                 assert(other < 2^24, "number operand too big")
  1297.                 other = montgomeryModQ({other, 0, 0, 0, 0, 0, 0})
  1298.             end
  1299.  
  1300.             return multModQ(self, other)
  1301.         end,
  1302.  
  1303.         __div = function(a, b)
  1304.             if type(a) == "number" then
  1305.                 assert(a < 2^24, "number operand too big")
  1306.                 a = montgomeryModQ({a, 0, 0, 0, 0, 0, 0})
  1307.             end
  1308.  
  1309.             if type(b) == "number" then
  1310.                 assert(b < 2^24, "number operand too big")
  1311.                 b = montgomeryModQ({b, 0, 0, 0, 0, 0, 0})
  1312.             end
  1313.  
  1314.             local bInv = expModQ(b, qMinusTwoBinary)
  1315.  
  1316.             return multModQ(a, bInv)
  1317.         end,
  1318.  
  1319.         __pow = function(self, other)
  1320.             return intExpModQ(self, other)
  1321.         end
  1322.     }
  1323.  
  1324.     return {
  1325.         hashModQ = hashModQ,
  1326.         randomModQ = randomModQ,
  1327.         decodeModQ = decodeModQ,
  1328.         inverseMontgomeryModQ = inverseMontgomeryModQ
  1329.     }
  1330. end)()
  1331.  
  1332. -- Elliptic curve arithmetic
  1333. local curve = (function()
  1334.     ---- About the Curve Itself
  1335.     -- Field Size: 168 bits
  1336.     -- Field Modulus (p): 481 * 2^159 + 3
  1337.     -- Equation: x^2 + y^2 = 1 + 122 * x^2 * y^2
  1338.     -- Parameters: Edwards Curve with d = 122
  1339.     -- Curve Order (n): 351491143778082151827986174289773107581916088585564
  1340.     -- Cofactor (h): 4
  1341.     -- Generator Order (q): 87872785944520537956996543572443276895479022146391
  1342.     ---- About the Curve's Security
  1343.     -- Current best attack security: 81.777 bits (Small Subgroup + Rho)
  1344.     -- Rho Security: log2(0.884 * sqrt(q)) = 82.777 bits
  1345.     -- Transfer Security? Yes: p ~= q; k > 20
  1346.     -- Field Discriminant Security? Yes:
  1347.     --    t = 27978492958645335688000168
  1348.     --    s = 10
  1349.     --    |D| = 6231685068753619775430107799412237267322159383147 > 2^100
  1350.     -- Rigidity? No, not at all.
  1351.     -- XZ/YZ Ladder Security? No: Single coordinate ladders are insecure.
  1352.     -- Small Subgroup Security? No.
  1353.     -- Invalid Curve Security? Yes: Points are checked before every operation.
  1354.     -- Invalid Curve Twist Security? No: Don't use single coordinate ladders.
  1355.     -- Completeness? Yes: The curve is complete.
  1356.     -- Indistinguishability? Yes (Elligator 2), but not implemented.
  1357.  
  1358.     local isEqual = arith.isEqual
  1359.     local NAF = arith.NAF
  1360.     local encodeInt = arith.encodeInt
  1361.     local decodeInt = arith.decodeInt
  1362.     local multModP = modp.multModP
  1363.     local squareModP = modp.squareModP
  1364.     local addModP = modp.addModP
  1365.     local subModP = modp.subModP
  1366.     local montgomeryModP = modp.montgomeryModP
  1367.     local expModP = modp.expModP
  1368.     local inverseMontgomeryModQ = modq.inverseMontgomeryModQ
  1369.  
  1370.     local pointMT
  1371.     local ZERO = {0, 0, 0, 0, 0, 0, 0}
  1372.     local ONE = montgomeryModP({1, 0, 0, 0, 0, 0, 0})
  1373.  
  1374.     -- Curve Parameters
  1375.     local d = montgomeryModP({122, 0, 0, 0, 0, 0, 0})
  1376.     local p = {3, 0, 0, 0, 0, 0, 15761408}
  1377.     local pMinusTwoBinary = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1}
  1378.     local pMinusThreeOverFourBinary = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1}
  1379.     local G = {
  1380.         {6636044, 10381432, 15741790, 2914241, 5785600, 264923, 4550291},
  1381.         {13512827, 8449886, 5647959, 1135556, 5489843, 7177356, 8002203},
  1382.         {unpack(ONE)}
  1383.     }
  1384.     local O = {
  1385.         {unpack(ZERO)},
  1386.         {unpack(ONE)},
  1387.         {unpack(ONE)}
  1388.     }
  1389.  
  1390.     -- Projective Coordinates for Edwards curves for point addition/doubling.
  1391.     -- Points are represented as: (X:Y:Z) where x = X/Z and y = Y/Z
  1392.     -- The identity element is represented by (0:1:1)
  1393.     -- Point operation formulas are available on the EFD:
  1394.     -- https://www.hyperelliptic.org/EFD/g1p/auto-edwards-projective.html
  1395.     local function pointDouble(P1)
  1396.         -- 3M + 4S
  1397.         local X1, Y1, Z1 = unpack(P1)
  1398.  
  1399.         local b = addModP(X1, Y1)
  1400.         local B = squareModP(b)
  1401.         local C = squareModP(X1)
  1402.         local D = squareModP(Y1)
  1403.         local E = addModP(C, D)
  1404.         local H = squareModP(Z1)
  1405.         local J = subModP(E, addModP(H, H))
  1406.         local X3 = multModP(subModP(B, E), J)
  1407.         local Y3 = multModP(E, subModP(C, D))
  1408.         local Z3 = multModP(E, J)
  1409.         local P3 = {X3, Y3, Z3}
  1410.  
  1411.         return setmetatable(P3, pointMT)
  1412.     end
  1413.  
  1414.     local function pointAdd(P1, P2)
  1415.         -- 10M + 1S
  1416.         local X1, Y1, Z1 = unpack(P1)
  1417.         local X2, Y2, Z2 = unpack(P2)
  1418.  
  1419.         local A = multModP(Z1, Z2)
  1420.         local B = squareModP(A)
  1421.         local C = multModP(X1, X2)
  1422.         local D = multModP(Y1, Y2)
  1423.         local E = multModP(d, multModP(C, D))
  1424.         local F = subModP(B, E)
  1425.         local G = addModP(B, E)
  1426.         local X3 = multModP(A, multModP(F, subModP(multModP(addModP(X1, Y1), addModP(X2, Y2)), addModP(C, D))))
  1427.         local Y3 = multModP(A, multModP(G, subModP(D, C)))
  1428.         local Z3 = multModP(F, G)
  1429.         local P3 = {X3, Y3, Z3}
  1430.  
  1431.         return setmetatable(P3, pointMT)
  1432.     end
  1433.  
  1434.     local function pointNeg(P1)
  1435.         local X1, Y1, Z1 = unpack(P1)
  1436.  
  1437.         local X3 = subModP(ZERO, X1)
  1438.         local Y3 = {unpack(Y1)}
  1439.         local Z3 = {unpack(Z1)}
  1440.         local P3 = {X3, Y3, Z3}
  1441.  
  1442.         return setmetatable(P3, pointMT)
  1443.     end
  1444.  
  1445.     local function pointSub(P1, P2)
  1446.         return pointAdd(P1, pointNeg(P2))
  1447.     end
  1448.  
  1449.     -- Converts (X:Y:Z) into (X:Y:1) = (x:y:1)
  1450.     local function pointScale(P1)
  1451.         local X1, Y1, Z1 = unpack(P1)
  1452.  
  1453.         local A = expModP(Z1, pMinusTwoBinary)
  1454.         local X3 = multModP(X1, A)
  1455.         local Y3 = multModP(Y1, A)
  1456.         local Z3 = {unpack(ONE)}
  1457.         local P3 = {X3, Y3, Z3}
  1458.  
  1459.         return setmetatable(P3, pointMT)
  1460.     end
  1461.  
  1462.     local function pointIsEqual(P1, P2)
  1463.         local X1, Y1, Z1 = unpack(P1)
  1464.         local X2, Y2, Z2 = unpack(P2)
  1465.  
  1466.         local A1 = multModP(X1, Z2)
  1467.         local B1 = multModP(Y1, Z2)
  1468.         local A2 = multModP(X2, Z1)
  1469.         local B2 = multModP(Y2, Z1)
  1470.  
  1471.         return isEqual(A1, A2) and isEqual(B1, B2)
  1472.     end
  1473.  
  1474.     -- Checks if a projective point satisfies the curve equation
  1475.     local function pointIsOnCurve(P1)
  1476.         local X1, Y1, Z1 = unpack(P1)
  1477.  
  1478.         local X12 = squareModP(X1)
  1479.         local Y12 = squareModP(Y1)
  1480.         local Z12 = squareModP(Z1)
  1481.         local Z14 = squareModP(Z12)
  1482.         local a = addModP(X12, Y12)
  1483.         a = multModP(a, Z12)
  1484.         local b = multModP(d, multModP(X12, Y12))
  1485.         b = addModP(Z14, b)
  1486.  
  1487.         return isEqual(a, b)
  1488.     end
  1489.  
  1490.     local function pointIsInf(P1)
  1491.         return isEqual(P1[1], ZERO)
  1492.     end
  1493.  
  1494.     -- W-ary Non-Adjacent Form (wNAF) method for scalar multiplication:
  1495.     -- https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#w-ary_non-adjacent_form_(wNAF)_method
  1496.     local function scalarMult(multiplier, P1)
  1497.         -- w = 5
  1498.         local naf = NAF(multiplier, 5)
  1499.         local PTable = {P1}
  1500.         local P2 = pointDouble(P1)
  1501.         local Q = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}}
  1502.  
  1503.         for i = 3, 31, 2 do
  1504.             PTable[i] = pointAdd(PTable[i - 2], P2)
  1505.         end
  1506.  
  1507.         for i = #naf, 1, -1 do
  1508.             Q = pointDouble(Q)
  1509.             if naf[i] > 0 then
  1510.                 Q = pointAdd(Q, PTable[naf[i]])
  1511.             elseif naf[i] < 0 then
  1512.                 Q = pointSub(Q, PTable[-naf[i]])
  1513.             end
  1514.         end
  1515.  
  1516.         return setmetatable(Q, pointMT)
  1517.     end
  1518.  
  1519.     -- Lookup table 4-ary NAF method for scalar multiplication by G.
  1520.     -- Precomputations for the regular NAF method are done before the multiplication.
  1521.     local GTable = {G}
  1522.     for i = 2, 168 do
  1523.         GTable[i] = pointDouble(GTable[i - 1])
  1524.     end
  1525.  
  1526.     local function scalarMultG(multiplier)
  1527.         local naf = NAF(multiplier, 2)
  1528.         local Q = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}}
  1529.  
  1530.         for i = 1, 168 do
  1531.             if naf[i] == 1 then
  1532.                 Q = pointAdd(Q, GTable[i])
  1533.             elseif naf[i] == -1 then
  1534.                 Q = pointSub(Q, GTable[i])
  1535.             end
  1536.         end
  1537.  
  1538.         return setmetatable(Q, pointMT)
  1539.     end
  1540.  
  1541.     -- Point compression and encoding.
  1542.     -- Compresses curve points to 22 bytes.
  1543.     local function pointEncode(P1)
  1544.         P1 = pointScale(P1)
  1545.         local result = {}
  1546.         local x, y = unpack(P1)
  1547.  
  1548.         -- Encode y
  1549.         result = encodeInt(y)
  1550.         -- Encode one bit from x
  1551.         result[22] = x[1] % 2
  1552.  
  1553.         return setmetatable(result, byteTableMT)
  1554.     end
  1555.  
  1556.     local function pointDecode(enc)
  1557.         enc = strToByteArr(mapToStr(enc):sub(1, 22))
  1558.         -- Decode y
  1559.         local y = decodeInt(enc)
  1560.         y[7] = y[7] % p[7]
  1561.         -- Find {x, -x} using curve equation
  1562.         local y2 = squareModP(y)
  1563.         local u = subModP(y2, ONE)
  1564.         local v = subModP(multModP(d, y2), ONE)
  1565.         local u2 = squareModP(u)
  1566.         local u3 = multModP(u, u2)
  1567.         local u5 = multModP(u3, u2)
  1568.         local v3 = multModP(v, squareModP(v))
  1569.         local w = multModP(u5, v3)
  1570.         local x = multModP(u3, multModP(v, expModP(w, pMinusThreeOverFourBinary)))
  1571.         -- Use enc[22] to find x from {x, -x}
  1572.         if x[1] % 2 ~= enc[22] then
  1573.             x = subModP(ZERO, x)
  1574.         end
  1575.         local P3 = {x, y, {unpack(ONE)}}
  1576.  
  1577.         return setmetatable(P3, pointMT)
  1578.     end
  1579.  
  1580.     pointMT = {
  1581.         __index = {
  1582.             isOnCurve = function(self)
  1583.                 return pointIsOnCurve(self)
  1584.             end,
  1585.  
  1586.             isInf = function(self)
  1587.                 return self:isOnCurve() and pointIsInf(self)
  1588.             end,
  1589.  
  1590.             encode = function(self)
  1591.                 return pointEncode(self)
  1592.             end
  1593.         },
  1594.  
  1595.         __tostring = function(self)
  1596.             return self:encode():toHex()
  1597.         end,
  1598.  
  1599.         __add = function(P1, P2)
  1600.             assert(P1:isOnCurve(), "invalid point")
  1601.             assert(P2:isOnCurve(), "invalid point")
  1602.  
  1603.             return pointAdd(P1, P2)
  1604.         end,
  1605.  
  1606.         __sub = function(P1, P2)
  1607.             assert(P1:isOnCurve(), "invalid point")
  1608.             assert(P2:isOnCurve(), "invalid point")
  1609.  
  1610.             return pointSub(P1, P2)
  1611.         end,
  1612.  
  1613.         __unm = function(self)
  1614.             assert(self:isOnCurve(), "invalid point")
  1615.  
  1616.             return pointNeg(self)
  1617.         end,
  1618.  
  1619.         __eq = function(P1, P2)
  1620.             assert(P1:isOnCurve(), "invalid point")
  1621.             assert(P2:isOnCurve(), "invalid point")
  1622.  
  1623.             return pointIsEqual(P1, P2)
  1624.         end,
  1625.  
  1626.         __mul = function(P1, s)
  1627.             if type(P1) == "number" then
  1628.                 return s * P1
  1629.             end
  1630.  
  1631.             if type(s) == "number" then
  1632.                 assert(s < 2^24, "number multiplier too big")
  1633.                 s = {s, 0, 0, 0, 0, 0, 0}
  1634.             else
  1635.                 s = inverseMontgomeryModQ(s)
  1636.             end
  1637.  
  1638.             if P1 == G then
  1639.                 return scalarMultG(s)
  1640.             else
  1641.                 return scalarMult(s, P1)
  1642.             end
  1643.         end
  1644.     }
  1645.  
  1646.     G = setmetatable(G, pointMT)
  1647.     O = setmetatable(O, pointMT)
  1648.  
  1649.     return {
  1650.         G = G,
  1651.         O = O,
  1652.         pointDecode = pointDecode
  1653.     }
  1654. end)()
  1655.  
  1656. local function getNonceFromEpoch()
  1657.     local nonce = {}
  1658.     local epoch = os.epoch("utc")
  1659.     for _ = 1, 12 do
  1660.         nonce[#nonce + 1] = epoch % 256
  1661.         epoch = epoch / 256
  1662.         epoch = epoch - epoch % 1
  1663.     end
  1664.  
  1665.     return nonce
  1666. end
  1667.  
  1668. local function encrypt(data, key)
  1669.     key = mapToStr(key)
  1670.     local encKey = sha256.hmac("encKey", key)
  1671.     local macKey = sha256.hmac("macKey", key)
  1672.     local nonce = getNonceFromEpoch()
  1673.     local ciphertext = chacha20.crypt(mapToStr(data), encKey, nonce)
  1674.     local result = nonce
  1675.     for i = 1, #ciphertext do
  1676.         result[#result + 1] = ciphertext[i]
  1677.     end
  1678.     local mac = sha256.hmac(result, macKey)
  1679.     for i = 1, #mac do
  1680.         result[#result + 1] = mac[i]
  1681.     end
  1682.  
  1683.     return setmetatable(result, byteTableMT)
  1684. end
  1685.  
  1686. local function decrypt(data, key)
  1687.     data = mapToStr(data)
  1688.     key = mapToStr(key)
  1689.     local encKey = sha256.hmac("encKey", key)
  1690.     local macKey = sha256.hmac("macKey", key)
  1691.     local mac = sha256.hmac(data:sub(1, -33), macKey)
  1692.     assert(mac:isEqual(strToByteArr(data:sub(-32))), "invalid mac")
  1693.     local result = chacha20.crypt(data:sub(13, -33), encKey, data:sub(1, 12))
  1694.  
  1695.     return setmetatable(result, byteTableMT)
  1696. end
  1697.  
  1698. local function keypair(seed)
  1699.     local x
  1700.     if seed then
  1701.         x = modq.hashModQ(mapToStr(seed))
  1702.     else
  1703.         x = modq.randomModQ()
  1704.     end
  1705.     local Y = curve.G * x
  1706.  
  1707.     local privateKey = x:encode()
  1708.     local publicKey = Y:encode()
  1709.  
  1710.     return privateKey, publicKey
  1711. end
  1712.  
  1713. local function exchange(privateKey, publicKey)
  1714.     local x = modq.decodeModQ(mapToStr(privateKey))
  1715.     local Y = curve.pointDecode(mapToStr(publicKey))
  1716.  
  1717.     local Z = Y * x
  1718.  
  1719.     local sharedSecret = sha256.digest(Z:encode())
  1720.  
  1721.     return sharedSecret
  1722. end
  1723.  
  1724. local function sign(privateKey, message)
  1725.     local x = modq.decodeModQ(mapToStr(privateKey))
  1726.     local k = modq.randomModQ()
  1727.     local R = curve.G * k
  1728.     local e = modq.hashModQ(mapToStr(message) .. tostring(R))
  1729.     local s = k - x * e
  1730.  
  1731.     e = e:encode()
  1732.     s = s:encode()
  1733.  
  1734.     local result = e
  1735.     for i = 1, #s do
  1736.         result[#result + 1] = s[i]
  1737.     end
  1738.  
  1739.     return setmetatable(result, byteTableMT)
  1740. end
  1741.  
  1742. local function verify(publicKey, message, signature)
  1743.     signature = mapToStr(signature)
  1744.     local Y = curve.pointDecode(mapToStr(publicKey))
  1745.     local e = modq.decodeModQ(signature:sub(1, 21))
  1746.     local s = modq.decodeModQ(signature:sub(22))
  1747.     local Rv = curve.G * s + Y * e
  1748.     local ev = modq.hashModQ(mapToStr(message) .. tostring(Rv))
  1749.  
  1750.     return ev == e
  1751. end
  1752.  
  1753. return {
  1754.     chacha20 = chacha20,
  1755.     sha256 = sha256,
  1756.     random = random,
  1757.     encrypt = encrypt,
  1758.     decrypt = decrypt,
  1759.     keypair = keypair,
  1760.     exchange = exchange,
  1761.     sign = sign,
  1762.     verify = verify
  1763. }
  1764.  
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement