Advertisement
osmarks

Elliptic Curve Cryptography

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