-- Elliptic curve cryptography library. This should probably be minified? Why does it have its own `irequire`?

local preload = _G.package.preload

local irequire = _G.require
if type(irequire) ~= "function" then
	local loading = {}
	local loaded = {}
	irequire = function(name)
		local result = loaded[name]

		if result ~= nil then
			if result == loading then
				error("loop or previous error loading module '" .. name .. "'", 2)
			end

			return result
		end

		loaded[name] = loading
		local contents = preload[name]
		if contents then
			result = contents(name)
		else
			error("cannot load '" .. name .. "'", 2)
		end

		if result == nil then result = true end
		loaded[name] = result
		return result
	end
end
preload["fq"] = function(...)
-- Fq Integer Arithmetic

local bxor = bit32.bxor or bit.bxor
local n = 0xffff
local m = 0x10000

local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532}
local qn = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

local mt = {
	__tostring = function(a) return string.char(unpack(a)) end,
	__index = {
		toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end,
		isEqual = function(self, t)
			if type(t) ~= "table" then return false end
			if #self ~= #t then return false end
			local ret = 0
			for i = 1, #self do
				ret = bit32.bor(ret, bxor(self[i], t[i]))
			end
			return ret == 0
		end
	}
}

local function eq(a, b)
	for i = 1, 12 do
		if a[i] ~= b[i] then
			return false
		end
	end

	return true
end

local function cmp(a, b)
	for i = 12, 1, -1 do
		if a[i] > b[i] then
			return 1
		elseif a[i] < b[i] then
			return -1
		end
	end

	return 0
end

local function cmp384(a, b)
	for i = 24, 1, -1 do
		if a[i] > b[i] then
			return 1
		elseif a[i] < b[i] then
			return -1
		end
	end

	return 0
end

local function bytes(x)
	local result = {}

	for i = 0, 11 do
		local m = x[i + 1] % 256
		result[2 * i + 1] = m
		result[2 * i + 2] = (x[i + 1] - m) / 256
	end

	return setmetatable(result, mt)
end

local function fromBytes(enc)
	local result = {}

	for i = 0, 11 do
		result[i + 1] = enc[2 * i + 1] % 256
		result[i + 1] = result[i + 1] + enc[2 * i + 2] * 256
	end

	return result
end

local function sub192(a, b)
	local r1 = a[1] - b[1]
	local r2 = a[2] - b[2]
	local r3 = a[3] - b[3]
	local r4 = a[4] - b[4]
	local r5 = a[5] - b[5]
	local r6 = a[6] - b[6]
	local r7 = a[7] - b[7]
	local r8 = a[8] - b[8]
	local r9 = a[9] - b[9]
	local r10 = a[10] - b[10]
	local r11 = a[11] - b[11]
	local r12 = a[12] - b[12]

	if r1 < 0 then
		r2 = r2 - 1
		r1 = r1 + m
	end
	if r2 < 0 then
		r3 = r3 - 1
		r2 = r2 + m
	end
	if r3 < 0 then
		r4 = r4 - 1
		r3 = r3 + m
	end
	if r4 < 0 then
		r5 = r5 - 1
		r4 = r4 + m
	end
	if r5 < 0 then
		r6 = r6 - 1
		r5 = r5 + m
	end
	if r6 < 0 then
		r7 = r7 - 1
		r6 = r6 + m
	end
	if r7 < 0 then
		r8 = r8 - 1
		r7 = r7 + m
	end
	if r8 < 0 then
		r9 = r9 - 1
		r8 = r8 + m
	end
	if r9 < 0 then
		r10 = r10 - 1
		r9 = r9 + m
	end
	if r10 < 0 then
		r11 = r11 - 1
		r10 = r10 + m
	end
	if r11 < 0 then
		r12 = r12 - 1
		r11 = r11 + m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}

	return result
end

local function reduce(a)
	local result = {unpack(a)}

	if cmp(result, q) >= 0 then
		result = sub192(result, q)
	end

	return result
end

local function add(a, b)
	local r1 = a[1] + b[1]
	local r2 = a[2] + b[2]
	local r3 = a[3] + b[3]
	local r4 = a[4] + b[4]
	local r5 = a[5] + b[5]
	local r6 = a[6] + b[6]
	local r7 = a[7] + b[7]
	local r8 = a[8] + b[8]
	local r9 = a[9] + b[9]
	local r10 = a[10] + b[10]
	local r11 = a[11] + b[11]
	local r12 = a[12] + b[12]

	if r1 > n then
		r2 = r2 + 1
		r1 = r1 - m
	end
	if r2 > n then
		r3 = r3 + 1
		r2 = r2 - m
	end
	if r3 > n then
		r4 = r4 + 1
		r3 = r3 - m
	end
	if r4 > n then
		r5 = r5 + 1
		r4 = r4 - m
	end
	if r5 > n then
		r6 = r6 + 1
		r5 = r5 - m
	end
	if r6 > n then
		r7 = r7 + 1
		r6 = r6 - m
	end
	if r7 > n then
		r8 = r8 + 1
		r7 = r7 - m
	end
	if r8 > n then
		r9 = r9 + 1
		r8 = r8 - m
	end
	if r9 > n then
		r10 = r10 + 1
		r9 = r9 - m
	end
	if r10 > n then
		r11 = r11 + 1
		r10 = r10 - m
	end
	if r11 > n then
		r12 = r12 + 1
		r11 = r11 - m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}
	
	return reduce(result)
end

local function sub(a, b)
	local result = sub192(a, b)

	if result[12] < 0 then
		result = add(result, q)
	end
	
	return result
end

local function add384(a, b)
	local r1 = a[1] + b[1]
	local r2 = a[2] + b[2]
	local r3 = a[3] + b[3]
	local r4 = a[4] + b[4]
	local r5 = a[5] + b[5]
	local r6 = a[6] + b[6]
	local r7 = a[7] + b[7]
	local r8 = a[8] + b[8]
	local r9 = a[9] + b[9]
	local r10 = a[10] + b[10]
	local r11 = a[11] + b[11]
	local r12 = a[12] + b[12]
	local r13 = a[13] + b[13]
	local r14 = a[14] + b[14]
	local r15 = a[15] + b[15]
	local r16 = a[16] + b[16]
	local r17 = a[17] + b[17]
	local r18 = a[18] + b[18]
	local r19 = a[19] + b[19]
	local r20 = a[20] + b[20]
	local r21 = a[21] + b[21]
	local r22 = a[22] + b[22]
	local r23 = a[23] + b[23]
	local r24 = a[24] + b[24]

	if r1 > n then
		r2 = r2 + 1
		r1 = r1 - m
	end
	if r2 > n then
		r3 = r3 + 1
		r2 = r2 - m
	end
	if r3 > n then
		r4 = r4 + 1
		r3 = r3 - m
	end
	if r4 > n then
		r5 = r5 + 1
		r4 = r4 - m
	end
	if r5 > n then
		r6 = r6 + 1
		r5 = r5 - m
	end
	if r6 > n then
		r7 = r7 + 1
		r6 = r6 - m
	end
	if r7 > n then
		r8 = r8 + 1
		r7 = r7 - m
	end
	if r8 > n then
		r9 = r9 + 1
		r8 = r8 - m
	end
	if r9 > n then
		r10 = r10 + 1
		r9 = r9 - m
	end
	if r10 > n then
		r11 = r11 + 1
		r10 = r10 - m
	end
	if r11 > n then
		r12 = r12 + 1
		r11 = r11 - m
	end
	if r12 > n then
		r13 = r13 + 1
		r12 = r12 - m
	end
	if r13 > n then
		r14 = r14 + 1
		r13 = r13 - m
	end
	if r14 > n then
		r15 = r15 + 1
		r14 = r14 - m
	end
	if r15 > n then
		r16 = r16 + 1
		r15 = r15 - m
	end
	if r16 > n then
		r17 = r17 + 1
		r16 = r16 - m
	end
	if r17 > n then
		r18 = r18 + 1
		r17 = r17 - m
	end
	if r18 > n then
		r19 = r19 + 1
		r18 = r18 - m
	end
	if r19 > n then
		r20 = r20 + 1
		r19 = r19 - m
	end
	if r20 > n then
		r21 = r21 + 1
		r20 = r20 - m
	end
	if r21 > n then
		r22 = r22 + 1
		r21 = r21 - m
	end
	if r22 > n then
		r23 = r23 + 1
		r22 = r22 - m
	end
	if r23 > n then
		r24 = r24 + 1
		r23 = r23 - m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24}

	return result
end

local function sub384(a, b)
	local r1 = a[1] - b[1]
	local r2 = a[2] - b[2]
	local r3 = a[3] - b[3]
	local r4 = a[4] - b[4]
	local r5 = a[5] - b[5]
	local r6 = a[6] - b[6]
	local r7 = a[7] - b[7]
	local r8 = a[8] - b[8]
	local r9 = a[9] - b[9]
	local r10 = a[10] - b[10]
	local r11 = a[11] - b[11]
	local r12 = a[12] - b[12]
	local r13 = a[13] - b[13]
	local r14 = a[14] - b[14]
	local r15 = a[15] - b[15]
	local r16 = a[16] - b[16]
	local r17 = a[17] - b[17]
	local r18 = a[18] - b[18]
	local r19 = a[19] - b[19]
	local r20 = a[20] - b[20]
	local r21 = a[21] - b[21]
	local r22 = a[22] - b[22]
	local r23 = a[23] - b[23]
	local r24 = a[24] - b[24]

	if r1 < 0 then
		r2 = r2 - 1
		r1 = r1 + m
	end
	if r2 < 0 then
		r3 = r3 - 1
		r2 = r2 + m
	end
	if r3 < 0 then
		r4 = r4 - 1
		r3 = r3 + m
	end
	if r4 < 0 then
		r5 = r5 - 1
		r4 = r4 + m
	end
	if r5 < 0 then
		r6 = r6 - 1
		r5 = r5 + m
	end
	if r6 < 0 then
		r7 = r7 - 1
		r6 = r6 + m
	end
	if r7 < 0 then
		r8 = r8 - 1
		r7 = r7 + m
	end
	if r8 < 0 then
		r9 = r9 - 1
		r8 = r8 + m
	end
	if r9 < 0 then
		r10 = r10 - 1
		r9 = r9 + m
	end
	if r10 < 0 then
		r11 = r11 - 1
		r10 = r10 + m
	end
	if r11 < 0 then
		r12 = r12 - 1
		r11 = r11 + m
	end
	if r12 < 0 then
		r13 = r13 - 1
		r12 = r12 + m
	end
	if r13 < 0 then
		r14 = r14 - 1
		r13 = r13 + m
	end
	if r14 < 0 then
		r15 = r15 - 1
		r14 = r14 + m
	end
	if r15 < 0 then
		r16 = r16 - 1
		r15 = r15 + m
	end
	if r16 < 0 then
		r17 = r17 - 1
		r16 = r16 + m
	end
	if r17 < 0 then
		r18 = r18 - 1
		r17 = r17 + m
	end
	if r18 < 0 then
		r19 = r19 - 1
		r18 = r18 + m
	end
	if r19 < 0 then
		r20 = r20 - 1
		r19 = r19 + m
	end
	if r20 < 0 then
		r21 = r21 - 1
		r20 = r20 + m
	end
	if r21 < 0 then
		r22 = r22 - 1
		r21 = r21 + m
	end
	if r22 < 0 then
		r23 = r23 - 1
		r22 = r22 + m
	end
	if r23 < 0 then
		r24 = r24 - 1
		r23 = r23 + m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24}

	return result
end

local function mul384(a, b)
	local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 = unpack(a)
	local b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12 = unpack(b)
	
	local r1 = a1 * b1

	local r2 = a1 * b2
	r2 = r2 + a2 * b1

	local r3 = a1 * b3
	r3 = r3 + a2 * b2
	r3 = r3 + a3 * b1

	local r4 = a1 * b4
	r4 = r4 + a2 * b3
	r4 = r4 + a3 * b2
	r4 = r4 + a4 * b1

	local r5 = a1 * b5
	r5 = r5 + a2 * b4
	r5 = r5 + a3 * b3
	r5 = r5 + a4 * b2
	r5 = r5 + a5 * b1

	local r6 = a1 * b6
	r6 = r6 + a2 * b5
	r6 = r6 + a3 * b4
	r6 = r6 + a4 * b3
	r6 = r6 + a5 * b2
	r6 = r6 + a6 * b1

	local r7 = a1 * b7
	r7 = r7 + a2 * b6
	r7 = r7 + a3 * b5
	r7 = r7 + a4 * b4
	r7 = r7 + a5 * b3
	r7 = r7 + a6 * b2
	r7 = r7 + a7 * b1

	local r8 = a1 * b8
	r8 = r8 + a2 * b7
	r8 = r8 + a3 * b6
	r8 = r8 + a4 * b5
	r8 = r8 + a5 * b4
	r8 = r8 + a6 * b3
	r8 = r8 + a7 * b2
	r8 = r8 + a8 * b1

	local r9 = a1 * b9
	r9 = r9 + a2 * b8
	r9 = r9 + a3 * b7
	r9 = r9 + a4 * b6
	r9 = r9 + a5 * b5
	r9 = r9 + a6 * b4
	r9 = r9 + a7 * b3
	r9 = r9 + a8 * b2
	r9 = r9 + a9 * b1

	local r10 = a1 * b10
	r10 = r10 + a2 * b9
	r10 = r10 + a3 * b8
	r10 = r10 + a4 * b7
	r10 = r10 + a5 * b6
	r10 = r10 + a6 * b5
	r10 = r10 + a7 * b4
	r10 = r10 + a8 * b3
	r10 = r10 + a9 * b2
	r10 = r10 + a10 * b1

	local r11 = a1 * b11
	r11 = r11 + a2 * b10
	r11 = r11 + a3 * b9
	r11 = r11 + a4 * b8
	r11 = r11 + a5 * b7
	r11 = r11 + a6 * b6
	r11 = r11 + a7 * b5
	r11 = r11 + a8 * b4
	r11 = r11 + a9 * b3
	r11 = r11 + a10 * b2
	r11 = r11 + a11 * b1

	local r12 = a1 * b12
	r12 = r12 + a2 * b11
	r12 = r12 + a3 * b10
	r12 = r12 + a4 * b9
	r12 = r12 + a5 * b8
	r12 = r12 + a6 * b7
	r12 = r12 + a7 * b6
	r12 = r12 + a8 * b5
	r12 = r12 + a9 * b4
	r12 = r12 + a10 * b3
	r12 = r12 + a11 * b2
	r12 = r12 + a12 * b1

	local r13 = a2 * b12
	r13 = r13 + a3 * b11
	r13 = r13 + a4 * b10
	r13 = r13 + a5 * b9
	r13 = r13 + a6 * b8
	r13 = r13 + a7 * b7
	r13 = r13 + a8 * b6
	r13 = r13 + a9 * b5
	r13 = r13 + a10 * b4
	r13 = r13 + a11 * b3
	r13 = r13 + a12 * b2

	local r14 = a3 * b12
	r14 = r14 + a4 * b11
	r14 = r14 + a5 * b10
	r14 = r14 + a6 * b9
	r14 = r14 + a7 * b8
	r14 = r14 + a8 * b7
	r14 = r14 + a9 * b6
	r14 = r14 + a10 * b5
	r14 = r14 + a11 * b4
	r14 = r14 + a12 * b3

	local r15 = a4 * b12
	r15 = r15 + a5 * b11
	r15 = r15 + a6 * b10
	r15 = r15 + a7 * b9
	r15 = r15 + a8 * b8
	r15 = r15 + a9 * b7
	r15 = r15 + a10 * b6
	r15 = r15 + a11 * b5
	r15 = r15 + a12 * b4

	local r16 = a5 * b12
	r16 = r16 + a6 * b11
	r16 = r16 + a7 * b10
	r16 = r16 + a8 * b9
	r16 = r16 + a9 * b8
	r16 = r16 + a10 * b7
	r16 = r16 + a11 * b6
	r16 = r16 + a12 * b5

	local r17 = a6 * b12
	r17 = r17 + a7 * b11
	r17 = r17 + a8 * b10
	r17 = r17 + a9 * b9
	r17 = r17 + a10 * b8
	r17 = r17 + a11 * b7
	r17 = r17 + a12 * b6

	local r18 = a7 * b12
	r18 = r18 + a8 * b11
	r18 = r18 + a9 * b10
	r18 = r18 + a10 * b9
	r18 = r18 + a11 * b8
	r18 = r18 + a12 * b7

	local r19 = a8 * b12
	r19 = r19 + a9 * b11
	r19 = r19 + a10 * b10
	r19 = r19 + a11 * b9
	r19 = r19 + a12 * b8

	local r20 = a9 * b12
	r20 = r20 + a10 * b11
	r20 = r20 + a11 * b10
	r20 = r20 + a12 * b9

	local r21 = a10 * b12
	r21 = r21 + a11 * b11
	r21 = r21 + a12 * b10

	local r22 = a11 * b12
	r22 = r22 + a12 * b11

	local r23 = a12 * b12

	local r24 = 0

	r2 = r2 + (r1 / m)
	r2 = r2 - r2 % 1
	r1 = r1 % m
	r3 = r3 + (r2 / m)
	r3 = r3 - r3 % 1
	r2 = r2 % m
	r4 = r4 + (r3 / m)
	r4 = r4 - r4 % 1
	r3 = r3 % m
	r5 = r5 + (r4 / m)
	r5 = r5 - r5 % 1
	r4 = r4 % m
	r6 = r6 + (r5 / m)
	r6 = r6 - r6 % 1
	r5 = r5 % m
	r7 = r7 + (r6 / m)
	r7 = r7 - r7 % 1
	r6 = r6 % m
	r8 = r8 + (r7 / m)
	r8 = r8 - r8 % 1
	r7 = r7 % m
	r9 = r9 + (r8 / m)
	r9 = r9 - r9 % 1
	r8 = r8 % m
	r10 = r10 + (r9 / m)
	r10 = r10 - r10 % 1
	r9 = r9 % m
	r11 = r11 + (r10 / m)
	r11 = r11 - r11 % 1
	r10 = r10 % m
	r12 = r12 + (r11 / m)
	r12 = r12 - r12 % 1
	r11 = r11 % m
	r13 = r13 + (r12 / m)
	r13 = r13 - r13 % 1
	r12 = r12 % m
	r14 = r14 + (r13 / m)
	r14 = r14 - r14 % 1
	r13 = r13 % m
	r15 = r15 + (r14 / m)
	r15 = r15 - r15 % 1
	r14 = r14 % m
	r16 = r16 + (r15 / m)
	r16 = r16 - r16 % 1
	r15 = r15 % m
	r17 = r17 + (r16 / m)
	r17 = r17 - r17 % 1
	r16 = r16 % m
	r18 = r18 + (r17 / m)
	r18 = r18 - r18 % 1
	r17 = r17 % m
	r19 = r19 + (r18 / m)
	r19 = r19 - r19 % 1
	r18 = r18 % m
	r20 = r20 + (r19 / m)
	r20 = r20 - r20 % 1
	r19 = r19 % m
	r21 = r21 + (r20 / m)
	r21 = r21 - r21 % 1
	r20 = r20 % m
	r22 = r22 + (r21 / m)
	r22 = r22 - r22 % 1
	r21 = r21 % m
	r23 = r23 + (r22 / m)
	r23 = r23 - r23 % 1
	r22 = r22 % m
	r24 = r24 + (r23 / m)
	r24 = r24 - r24 % 1
	r23 = r23 % m

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24}

	return result
end

local function reduce384(a)
	local result = {unpack(a)}

	while cmp384(result, qn) >= 0 do
		local qn = {unpack(qn)}
		local qn2 = add384(qn, qn)
		while cmp384(result, qn2) > 0 do
			qn = qn2
			qn2 = add384(qn2, qn2)
		end
		result = sub384(result, qn)
	end

	result = {unpack(result, 1, 12)}

	return result
end

local function mul(a, b)
	return reduce384(mul384(a, b))
end

return {
	fromBytes = fromBytes,
	bytes = bytes,
	sub = sub,
	mul = mul,
	eq = eq,
	cmp = cmp,
}
end
preload["fp"] = function(...)
-- Fp Integer Arithmetic

local n = 0xffff
local m = 0x10000

local p = {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65533}
local p2 = {21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 43690}
local r2 = {44014, 58358, 19452, 6484, 45852, 58974, 63348, 64806, 65292, 65454, 65508, 21512}

local function eq(a, b)
	for i = 1, 12 do
		if a[i] ~= b[i] then
			return false
		end
	end

	return true
end

local function reduce(a)
	local r1 = a[1]
	local r2 = a[2]
	local r3 = a[3]
	local r4 = a[4]
	local r5 = a[5]
	local r6 = a[6]
	local r7 = a[7]
	local r8 = a[8]
	local r9 = a[9]
	local r10 = a[10]
	local r11 = a[11]
	local r12 = a[12]

	if r12 < 65533 or r12 == 65533 and r1 < 3 then
		return {unpack(a)}
	end

	r1 = r1 - 3
	r12 = r12 - 65533

	if r1 < 0 then
		r2 = r2 - 1
		r1 = r1 + m
	end
	if r2 < 0 then
		r3 = r3 - 1
		r2 = r2 + m
	end
	if r3 < 0 then
		r4 = r4 - 1
		r3 = r3 + m
	end
	if r4 < 0 then
		r5 = r5 - 1
		r4 = r4 + m
	end
	if r5 < 0 then
		r6 = r6 - 1
		r5 = r5 + m
	end
	if r6 < 0 then
		r7 = r7 - 1
		r6 = r6 + m
	end
	if r7 < 0 then
		r8 = r8 - 1
		r7 = r7 + m
	end
	if r8 < 0 then
		r9 = r9 - 1
		r8 = r8 + m
	end
	if r9 < 0 then
		r10 = r10 - 1
		r9 = r9 + m
	end
	if r10 < 0 then
		r11 = r11 - 1
		r10 = r10 + m
	end
	if r11 < 0 then
		r12 = r12 - 1
		r11 = r11 + m
	end

	return {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}
end

local function add(a, b)
	local r1 = a[1] + b[1]
	local r2 = a[2] + b[2]
	local r3 = a[3] + b[3]
	local r4 = a[4] + b[4]
	local r5 = a[5] + b[5]
	local r6 = a[6] + b[6]
	local r7 = a[7] + b[7]
	local r8 = a[8] + b[8]
	local r9 = a[9] + b[9]
	local r10 = a[10] + b[10]
	local r11 = a[11] + b[11]
	local r12 = a[12] + b[12]

	if r1 > n then
		r2 = r2 + 1
		r1 = r1 - m
	end
	if r2 > n then
		r3 = r3 + 1
		r2 = r2 - m
	end
	if r3 > n then
		r4 = r4 + 1
		r3 = r3 - m
	end
	if r4 > n then
		r5 = r5 + 1
		r4 = r4 - m
	end
	if r5 > n then
		r6 = r6 + 1
		r5 = r5 - m
	end
	if r6 > n then
		r7 = r7 + 1
		r6 = r6 - m
	end
	if r7 > n then
		r8 = r8 + 1
		r7 = r7 - m
	end
	if r8 > n then
		r9 = r9 + 1
		r8 = r8 - m
	end
	if r9 > n then
		r10 = r10 + 1
		r9 = r9 - m
	end
	if r10 > n then
		r11 = r11 + 1
		r10 = r10 - m
	end
	if r11 > n then
		r12 = r12 + 1
		r11 = r11 - m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}
	
	return reduce(result)
end

local function shr(a)
	local r1 = a[1]
	local r2 = a[2]
	local r3 = a[3]
	local r4 = a[4]
	local r5 = a[5]
	local r6 = a[6]
	local r7 = a[7]
	local r8 = a[8]
	local r9 = a[9]
	local r10 = a[10]
	local r11 = a[11]
	local r12 = a[12]

	r1 = r1 / 2
	r1 = r1 - r1 % 1
	r1 = r1 + (r2 % 2) * 0x8000
	r2 = r2 / 2
	r2 = r2 - r2 % 1
	r2 = r2 + (r3 % 2) * 0x8000
	r3 = r3 / 2
	r3 = r3 - r3 % 1
	r3 = r3 + (r4 % 2) * 0x8000
	r4 = r4 / 2
	r4 = r4 - r4 % 1
	r4 = r4 + (r5 % 2) * 0x8000
	r5 = r5 / 2
	r5 = r5 - r5 % 1
	r5 = r5 + (r6 % 2) * 0x8000
	r6 = r6 / 2
	r6 = r6 - r6 % 1
	r6 = r6 + (r7 % 2) * 0x8000
	r7 = r7 / 2
	r7 = r7 - r7 % 1
	r7 = r7 + (r8 % 2) * 0x8000
	r8 = r8 / 2
	r8 = r8 - r8 % 1
	r8 = r8 + (r9 % 2) * 0x8000
	r9 = r9 / 2
	r9 = r9 - r9 % 1
	r9 = r9 + (r10 % 2) * 0x8000
	r10 = r10 / 2
	r10 = r10 - r10 % 1
	r10 = r10 + (r11 % 2) * 0x8000
	r11 = r11 / 2
	r11 = r11 - r11 % 1
	r11 = r11 + (r12 % 2) * 0x8000
	r12 = r12 / 2
	r12 = r12 - r12 % 1

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}

	return result
end

local function sub192(a, b)
	local r1 = a[1] - b[1]
	local r2 = a[2] - b[2]
	local r3 = a[3] - b[3]
	local r4 = a[4] - b[4]
	local r5 = a[5] - b[5]
	local r6 = a[6] - b[6]
	local r7 = a[7] - b[7]
	local r8 = a[8] - b[8]
	local r9 = a[9] - b[9]
	local r10 = a[10] - b[10]
	local r11 = a[11] - b[11]
	local r12 = a[12] - b[12]

	if r1 < 0 then
		r2 = r2 - 1
		r1 = r1 + m
	end
	if r2 < 0 then
		r3 = r3 - 1
		r2 = r2 + m
	end
	if r3 < 0 then
		r4 = r4 - 1
		r3 = r3 + m
	end
	if r4 < 0 then
		r5 = r5 - 1
		r4 = r4 + m
	end
	if r5 < 0 then
		r6 = r6 - 1
		r5 = r5 + m
	end
	if r6 < 0 then
		r7 = r7 - 1
		r6 = r6 + m
	end
	if r7 < 0 then
		r8 = r8 - 1
		r7 = r7 + m
	end
	if r8 < 0 then
		r9 = r9 - 1
		r8 = r8 + m
	end
	if r9 < 0 then
		r10 = r10 - 1
		r9 = r9 + m
	end
	if r10 < 0 then
		r11 = r11 - 1
		r10 = r10 + m
	end
	if r11 < 0 then
		r12 = r12 - 1
		r11 = r11 + m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}
	
	return result
end

local function sub(a, b)
	local r1 = a[1] - b[1]
	local r2 = a[2] - b[2]
	local r3 = a[3] - b[3]
	local r4 = a[4] - b[4]
	local r5 = a[5] - b[5]
	local r6 = a[6] - b[6]
	local r7 = a[7] - b[7]
	local r8 = a[8] - b[8]
	local r9 = a[9] - b[9]
	local r10 = a[10] - b[10]
	local r11 = a[11] - b[11]
	local r12 = a[12] - b[12]

	if r1 < 0 then
		r2 = r2 - 1
		r1 = r1 + m
	end
	if r2 < 0 then
		r3 = r3 - 1
		r2 = r2 + m
	end
	if r3 < 0 then
		r4 = r4 - 1
		r3 = r3 + m
	end
	if r4 < 0 then
		r5 = r5 - 1
		r4 = r4 + m
	end
	if r5 < 0 then
		r6 = r6 - 1
		r5 = r5 + m
	end
	if r6 < 0 then
		r7 = r7 - 1
		r6 = r6 + m
	end
	if r7 < 0 then
		r8 = r8 - 1
		r7 = r7 + m
	end
	if r8 < 0 then
		r9 = r9 - 1
		r8 = r8 + m
	end
	if r9 < 0 then
		r10 = r10 - 1
		r9 = r9 + m
	end
	if r10 < 0 then
		r11 = r11 - 1
		r10 = r10 + m
	end
	if r11 < 0 then
		r12 = r12 - 1
		r11 = r11 + m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}

	if r12 < 0 then
		result = add(result, p)
	end
	
	return result
end

local function add384(a, b)
	local r1 = a[1] + b[1]
	local r2 = a[2] + b[2]
	local r3 = a[3] + b[3]
	local r4 = a[4] + b[4]
	local r5 = a[5] + b[5]
	local r6 = a[6] + b[6]
	local r7 = a[7] + b[7]
	local r8 = a[8] + b[8]
	local r9 = a[9] + b[9]
	local r10 = a[10] + b[10]
	local r11 = a[11] + b[11]
	local r12 = a[12] + b[12]
	local r13 = a[13] + b[13]
	local r14 = a[14] + b[14]
	local r15 = a[15] + b[15]
	local r16 = a[16] + b[16]
	local r17 = a[17] + b[17]
	local r18 = a[18] + b[18]
	local r19 = a[19] + b[19]
	local r20 = a[20] + b[20]
	local r21 = a[21] + b[21]
	local r22 = a[22] + b[22]
	local r23 = a[23] + b[23]
	local r24 = a[24] + b[24]

	if r1 > n then
		r2 = r2 + 1
		r1 = r1 - m
	end
	if r2 > n then
		r3 = r3 + 1
		r2 = r2 - m
	end
	if r3 > n then
		r4 = r4 + 1
		r3 = r3 - m
	end
	if r4 > n then
		r5 = r5 + 1
		r4 = r4 - m
	end
	if r5 > n then
		r6 = r6 + 1
		r5 = r5 - m
	end
	if r6 > n then
		r7 = r7 + 1
		r6 = r6 - m
	end
	if r7 > n then
		r8 = r8 + 1
		r7 = r7 - m
	end
	if r8 > n then
		r9 = r9 + 1
		r8 = r8 - m
	end
	if r9 > n then
		r10 = r10 + 1
		r9 = r9 - m
	end
	if r10 > n then
		r11 = r11 + 1
		r10 = r10 - m
	end
	if r11 > n then
		r12 = r12 + 1
		r11 = r11 - m
	end
	if r12 > n then
		r13 = r13 + 1
		r12 = r12 - m
	end
	if r13 > n then
		r14 = r14 + 1
		r13 = r13 - m
	end
	if r14 > n then
		r15 = r15 + 1
		r14 = r14 - m
	end
	if r15 > n then
		r16 = r16 + 1
		r15 = r15 - m
	end
	if r16 > n then
		r17 = r17 + 1
		r16 = r16 - m
	end
	if r17 > n then
		r18 = r18 + 1
		r17 = r17 - m
	end
	if r18 > n then
		r19 = r19 + 1
		r18 = r18 - m
	end
	if r19 > n then
		r20 = r20 + 1
		r19 = r19 - m
	end
	if r20 > n then
		r21 = r21 + 1
		r20 = r20 - m
	end
	if r21 > n then
		r22 = r22 + 1
		r21 = r21 - m
	end
	if r22 > n then
		r23 = r23 + 1
		r22 = r22 - m
	end
	if r23 > n then
		r24 = r24 + 1
		r23 = r23 - m
	end

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24}

	return result
end

local function mul384(a, b)
	local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 = unpack(a)
	local b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12 = unpack(b)
	
	local r1 = a1 * b1

	local r2 = a1 * b2
	r2 = r2 + a2 * b1

	local r3 = a1 * b3
	r3 = r3 + a2 * b2
	r3 = r3 + a3 * b1

	local r4 = a1 * b4
	r4 = r4 + a2 * b3
	r4 = r4 + a3 * b2
	r4 = r4 + a4 * b1

	local r5 = a1 * b5
	r5 = r5 + a2 * b4
	r5 = r5 + a3 * b3
	r5 = r5 + a4 * b2
	r5 = r5 + a5 * b1

	local r6 = a1 * b6
	r6 = r6 + a2 * b5
	r6 = r6 + a3 * b4
	r6 = r6 + a4 * b3
	r6 = r6 + a5 * b2
	r6 = r6 + a6 * b1

	local r7 = a1 * b7
	r7 = r7 + a2 * b6
	r7 = r7 + a3 * b5
	r7 = r7 + a4 * b4
	r7 = r7 + a5 * b3
	r7 = r7 + a6 * b2
	r7 = r7 + a7 * b1

	local r8 = a1 * b8
	r8 = r8 + a2 * b7
	r8 = r8 + a3 * b6
	r8 = r8 + a4 * b5
	r8 = r8 + a5 * b4
	r8 = r8 + a6 * b3
	r8 = r8 + a7 * b2
	r8 = r8 + a8 * b1

	local r9 = a1 * b9
	r9 = r9 + a2 * b8
	r9 = r9 + a3 * b7
	r9 = r9 + a4 * b6
	r9 = r9 + a5 * b5
	r9 = r9 + a6 * b4
	r9 = r9 + a7 * b3
	r9 = r9 + a8 * b2
	r9 = r9 + a9 * b1

	local r10 = a1 * b10
	r10 = r10 + a2 * b9
	r10 = r10 + a3 * b8
	r10 = r10 + a4 * b7
	r10 = r10 + a5 * b6
	r10 = r10 + a6 * b5
	r10 = r10 + a7 * b4
	r10 = r10 + a8 * b3
	r10 = r10 + a9 * b2
	r10 = r10 + a10 * b1

	local r11 = a1 * b11
	r11 = r11 + a2 * b10
	r11 = r11 + a3 * b9
	r11 = r11 + a4 * b8
	r11 = r11 + a5 * b7
	r11 = r11 + a6 * b6
	r11 = r11 + a7 * b5
	r11 = r11 + a8 * b4
	r11 = r11 + a9 * b3
	r11 = r11 + a10 * b2
	r11 = r11 + a11 * b1

	local r12 = a1 * b12
	r12 = r12 + a2 * b11
	r12 = r12 + a3 * b10
	r12 = r12 + a4 * b9
	r12 = r12 + a5 * b8
	r12 = r12 + a6 * b7
	r12 = r12 + a7 * b6
	r12 = r12 + a8 * b5
	r12 = r12 + a9 * b4
	r12 = r12 + a10 * b3
	r12 = r12 + a11 * b2
	r12 = r12 + a12 * b1

	local r13 = a2 * b12
	r13 = r13 + a3 * b11
	r13 = r13 + a4 * b10
	r13 = r13 + a5 * b9
	r13 = r13 + a6 * b8
	r13 = r13 + a7 * b7
	r13 = r13 + a8 * b6
	r13 = r13 + a9 * b5
	r13 = r13 + a10 * b4
	r13 = r13 + a11 * b3
	r13 = r13 + a12 * b2

	local r14 = a3 * b12
	r14 = r14 + a4 * b11
	r14 = r14 + a5 * b10
	r14 = r14 + a6 * b9
	r14 = r14 + a7 * b8
	r14 = r14 + a8 * b7
	r14 = r14 + a9 * b6
	r14 = r14 + a10 * b5
	r14 = r14 + a11 * b4
	r14 = r14 + a12 * b3

	local r15 = a4 * b12
	r15 = r15 + a5 * b11
	r15 = r15 + a6 * b10
	r15 = r15 + a7 * b9
	r15 = r15 + a8 * b8
	r15 = r15 + a9 * b7
	r15 = r15 + a10 * b6
	r15 = r15 + a11 * b5
	r15 = r15 + a12 * b4

	local r16 = a5 * b12
	r16 = r16 + a6 * b11
	r16 = r16 + a7 * b10
	r16 = r16 + a8 * b9
	r16 = r16 + a9 * b8
	r16 = r16 + a10 * b7
	r16 = r16 + a11 * b6
	r16 = r16 + a12 * b5

	local r17 = a6 * b12
	r17 = r17 + a7 * b11
	r17 = r17 + a8 * b10
	r17 = r17 + a9 * b9
	r17 = r17 + a10 * b8
	r17 = r17 + a11 * b7
	r17 = r17 + a12 * b6

	local r18 = a7 * b12
	r18 = r18 + a8 * b11
	r18 = r18 + a9 * b10
	r18 = r18 + a10 * b9
	r18 = r18 + a11 * b8
	r18 = r18 + a12 * b7

	local r19 = a8 * b12
	r19 = r19 + a9 * b11
	r19 = r19 + a10 * b10
	r19 = r19 + a11 * b9
	r19 = r19 + a12 * b8

	local r20 = a9 * b12
	r20 = r20 + a10 * b11
	r20 = r20 + a11 * b10
	r20 = r20 + a12 * b9

	local r21 = a10 * b12
	r21 = r21 + a11 * b11
	r21 = r21 + a12 * b10

	local r22 = a11 * b12
	r22 = r22 + a12 * b11

	local r23 = a12 * b12

	local r24 = 0

	r2 = r2 + (r1 / m)
	r2 = r2 - r2 % 1
	r1 = r1 % m
	r3 = r3 + (r2 / m)
	r3 = r3 - r3 % 1
	r2 = r2 % m
	r4 = r4 + (r3 / m)
	r4 = r4 - r4 % 1
	r3 = r3 % m
	r5 = r5 + (r4 / m)
	r5 = r5 - r5 % 1
	r4 = r4 % m
	r6 = r6 + (r5 / m)
	r6 = r6 - r6 % 1
	r5 = r5 % m
	r7 = r7 + (r6 / m)
	r7 = r7 - r7 % 1
	r6 = r6 % m
	r8 = r8 + (r7 / m)
	r8 = r8 - r8 % 1
	r7 = r7 % m
	r9 = r9 + (r8 / m)
	r9 = r9 - r9 % 1
	r8 = r8 % m
	r10 = r10 + (r9 / m)
	r10 = r10 - r10 % 1
	r9 = r9 % m
	r11 = r11 + (r10 / m)
	r11 = r11 - r11 % 1
	r10 = r10 % m
	r12 = r12 + (r11 / m)
	r12 = r12 - r12 % 1
	r11 = r11 % m
	r13 = r13 + (r12 / m)
	r13 = r13 - r13 % 1
	r12 = r12 % m
	r14 = r14 + (r13 / m)
	r14 = r14 - r14 % 1
	r13 = r13 % m
	r15 = r15 + (r14 / m)
	r15 = r15 - r15 % 1
	r14 = r14 % m
	r16 = r16 + (r15 / m)
	r16 = r16 - r16 % 1
	r15 = r15 % m
	r17 = r17 + (r16 / m)
	r17 = r17 - r17 % 1
	r16 = r16 % m
	r18 = r18 + (r17 / m)
	r18 = r18 - r18 % 1
	r17 = r17 % m
	r19 = r19 + (r18 / m)
	r19 = r19 - r19 % 1
	r18 = r18 % m
	r20 = r20 + (r19 / m)
	r20 = r20 - r20 % 1
	r19 = r19 % m
	r21 = r21 + (r20 / m)
	r21 = r21 - r21 % 1
	r20 = r20 % m
	r22 = r22 + (r21 / m)
	r22 = r22 - r22 % 1
	r21 = r21 % m
	r23 = r23 + (r22 / m)
	r23 = r23 - r23 % 1
	r22 = r22 % m
	r24 = r24 + (r23 / m)
	r24 = r24 - r24 % 1
	r23 = r23 % m

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24}

	return result
end

local function REDC(T)
	local m = {unpack(mul384({unpack(T, 1, 12)}, p2), 1, 12)}
	local t = {unpack(add384(T, mul384(m, p)), 13, 24)}

	return reduce(t)
end

local function mul(a, b)
	return REDC(mul384(a, b))
end

local function sqr(a)
	local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 = unpack(a)
	
	local r1 = a1 * a1

	local r2 = a1 * a2 * 2

	local r3 = a1 * a3 * 2
	r3 = r3 + a2 * a2

	local r4 = a1 * a4 * 2
	r4 = r4 + a2 * a3 * 2

	local r5 = a1 * a5 * 2
	r5 = r5 + a2 * a4 * 2
	r5 = r5 + a3 * a3

	local r6 = a1 * a6 * 2
	r6 = r6 + a2 * a5 * 2
	r6 = r6 + a3 * a4 * 2

	local r7 = a1 * a7 * 2
	r7 = r7 + a2 * a6 * 2
	r7 = r7 + a3 * a5 * 2
	r7 = r7 + a4 * a4

	local r8 = a1 * a8 * 2
	r8 = r8 + a2 * a7 * 2
	r8 = r8 + a3 * a6 * 2
	r8 = r8 + a4 * a5 * 2

	local r9 = a1 * a9 * 2
	r9 = r9 + a2 * a8 * 2
	r9 = r9 + a3 * a7 * 2
	r9 = r9 + a4 * a6 * 2
	r9 = r9 + a5 * a5

	local r10 = a1 * a10 * 2
	r10 = r10 + a2 * a9 * 2
	r10 = r10 + a3 * a8 * 2
	r10 = r10 + a4 * a7 * 2
	r10 = r10 + a5 * a6 * 2

	local r11 = a1 * a11 * 2
	r11 = r11 + a2 * a10 * 2
	r11 = r11 + a3 * a9 * 2
	r11 = r11 + a4 * a8 * 2
	r11 = r11 + a5 * a7 * 2
	r11 = r11 + a6 * a6

	local r12 = a1 * a12 * 2
	r12 = r12 + a2 * a11 * 2
	r12 = r12 + a3 * a10 * 2
	r12 = r12 + a4 * a9 * 2
	r12 = r12 + a5 * a8 * 2
	r12 = r12 + a6 * a7 * 2

	local r13 = a2 * a12 * 2
	r13 = r13 + a3 * a11 * 2
	r13 = r13 + a4 * a10 * 2
	r13 = r13 + a5 * a9 * 2
	r13 = r13 + a6 * a8 * 2
	r13 = r13 + a7 * a7

	local r14 = a3 * a12 * 2
	r14 = r14 + a4 * a11 * 2
	r14 = r14 + a5 * a10 * 2
	r14 = r14 + a6 * a9 * 2
	r14 = r14 + a7 * a8 * 2

	local r15 = a4 * a12 * 2
	r15 = r15 + a5 * a11 * 2
	r15 = r15 + a6 * a10 * 2
	r15 = r15 + a7 * a9 * 2
	r15 = r15 + a8 * a8

	local r16 = a5 * a12 * 2
	r16 = r16 + a6 * a11 * 2
	r16 = r16 + a7 * a10 * 2
	r16 = r16 + a8 * a9 * 2

	local r17 = a6 * a12 * 2
	r17 = r17 + a7 * a11 * 2
	r17 = r17 + a8 * a10 * 2
	r17 = r17 + a9 * a9

	local r18 = a7 * a12 * 2
	r18 = r18 + a8 * a11 * 2
	r18 = r18 + a9 * a10 * 2

	local r19 = a8 * a12 * 2
	r19 = r19 + a9 * a11 * 2
	r19 = r19 + a10 * a10

	local r20 = a9 * a12 * 2
	r20 = r20 + a10 * a11 * 2

	local r21 = a10 * a12 * 2
	r21 = r21 + a11 * a11

	local r22 = a11 * a12 * 2

	local r23 = a12 * a12

	local r24 = 0

	r2 = r2 + (r1 / m)
	r2 = r2 - r2 % 1
	r1 = r1 % m
	r3 = r3 + (r2 / m)
	r3 = r3 - r3 % 1
	r2 = r2 % m
	r4 = r4 + (r3 / m)
	r4 = r4 - r4 % 1
	r3 = r3 % m
	r5 = r5 + (r4 / m)
	r5 = r5 - r5 % 1
	r4 = r4 % m
	r6 = r6 + (r5 / m)
	r6 = r6 - r6 % 1
	r5 = r5 % m
	r7 = r7 + (r6 / m)
	r7 = r7 - r7 % 1
	r6 = r6 % m
	r8 = r8 + (r7 / m)
	r8 = r8 - r8 % 1
	r7 = r7 % m
	r9 = r9 + (r8 / m)
	r9 = r9 - r9 % 1
	r8 = r8 % m
	r10 = r10 + (r9 / m)
	r10 = r10 - r10 % 1
	r9 = r9 % m
	r11 = r11 + (r10 / m)
	r11 = r11 - r11 % 1
	r10 = r10 % m
	r12 = r12 + (r11 / m)
	r12 = r12 - r12 % 1
	r11 = r11 % m
	r13 = r13 + (r12 / m)
	r13 = r13 - r13 % 1
	r12 = r12 % m
	r14 = r14 + (r13 / m)
	r14 = r14 - r14 % 1
	r13 = r13 % m
	r15 = r15 + (r14 / m)
	r15 = r15 - r15 % 1
	r14 = r14 % m
	r16 = r16 + (r15 / m)
	r16 = r16 - r16 % 1
	r15 = r15 % m
	r17 = r17 + (r16 / m)
	r17 = r17 - r17 % 1
	r16 = r16 % m
	r18 = r18 + (r17 / m)
	r18 = r18 - r18 % 1
	r17 = r17 % m
	r19 = r19 + (r18 / m)
	r19 = r19 - r19 % 1
	r18 = r18 % m
	r20 = r20 + (r19 / m)
	r20 = r20 - r20 % 1
	r19 = r19 % m
	r21 = r21 + (r20 / m)
	r21 = r21 - r21 % 1
	r20 = r20 % m
	r22 = r22 + (r21 / m)
	r22 = r22 - r22 % 1
	r21 = r21 % m
	r23 = r23 + (r22 / m)
	r23 = r23 - r23 % 1
	r22 = r22 % m
	r24 = r24 + (r23 / m)
	r24 = r24 - r24 % 1
	r23 = r23 % m

	local result = {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24}

	return REDC(result)
end

local function mont(a)
	return mul(a, r2)
end

local function invMont(a)
	local a = {unpack(a)}

	for i = 13, 24 do
		a[i] = 0
	end

	return REDC(a)
end

return {
	eq = eq,
	mul = mul,
	sqr = sqr,
	add = add,
	sub = sub,
	shr = shr,
	mont = mont,
	invMont = invMont,
	sub192 = sub192
}
end
preload["empty"] = function(...)

end
preload["elliptic"] = function(...)
---- Elliptic Curve Arithmetic

---- About the Curve Itself
-- Field Size: 192 bits
-- Field Modulus (p): 65533 * 2^176 + 3
-- Equation: x^2 + y^2 = 1 + 108 * x^2 * y^2
-- Parameters: Edwards Curve with c = 1, and d = 108
-- Curve Order (n): 4 * 1569203598118192102418711808268118358122924911136798015831
-- Cofactor (h): 4
-- Generator Order (q): 1569203598118192102418711808268118358122924911136798015831
---- About the Curve's Security
-- Current best attack security: 94.822 bits (Pollard's Rho)
-- Rho Security: log2(0.884 * sqrt(q)) = 94.822
-- Transfer Security? Yes: p ~= q; k > 20
-- Field Discriminant Security? Yes: t = 67602300638727286331433024168; s = 2^2; |D| = 5134296629560551493299993292204775496868940529592107064435 > 2^100
-- Rigidity? A little, the parameters are somewhat small.
-- XZ/YZ Ladder Security? No: Single coordinate ladders are insecure, so they can't be used.
-- Small Subgroup Security? Yes: Secret keys are calculated modulo 4q.
-- Invalid Curve Security? Yes: Any point to be multiplied is checked beforehand.
-- Invalid Curve Twist Security? No: The curve is not protected against single coordinate ladder attacks, so don't use them.
-- Completeness? Yes: The curve is an Edwards Curve with non-square d and square a, so the curve is complete.
-- Indistinguishability? No: The curve does not support indistinguishability maps.

fp = irequire("fp")

local eq = fp.eq
local mul = fp.mul
local sqr = fp.sqr
local add = fp.add
local sub = fp.sub
local shr = fp.shr
local mont = fp.mont
local invMont = fp.invMont
local sub192 = fp.sub192

local bits = 192
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}
local ZERO = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
local ONE = mont({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})

local p = mont({3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65533})
local G = {
	mont({30457, 58187, 5603, 63215, 8936, 58151, 26571, 7272, 26680, 23486, 32353, 59456}),
	mont({3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}),
	mont({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
}
local GTable = {G}

local d = mont({108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})

local bxor = bit32.bxor or bit.bxor
local mt = {
	__tostring = function(a) return string.char(unpack(a)) end,
	__index = {
		toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end,
		isEqual = function(self, t)
			if type(t) ~= "table" then return false end
			if #self ~= #t then return false end
			local ret = 0
			for i = 1, #self do
				ret = bit32.bor(ret, bxor(self[i], t[i]))
			end
			return ret == 0
		end
	}
}

local function expMod(a, t)
	local a = {unpack(a)}
	local result = {unpack(ONE)}

	for i = 1, bits do
		if t[i] == 1 then
			result = mul(result, a)
		end
		a = mul(a, a)
	end	

	return result
end

-- We're using Projective Coordinates
-- For Edwards curves
-- The identity element is represented by (0:1:1)
local function pointDouble(P1)
	local X1, Y1, Z1 = unpack(P1)

	local b = add(X1, Y1)
	local B = sqr(b)
	local C = sqr(X1)
	local D = sqr(Y1)
	local E = add(C, D)
	local H = sqr(Z1)
	local J = sub(E, add(H, H))
	local X3 = mul(sub(B, E), J)
	local Y3 = mul(E, sub(C, D))
	local Z3 = mul(E, J)

	local P3 = {X3, Y3, Z3}

	return P3
end

local function pointAdd(P1, P2)
	local X1, Y1, Z1 = unpack(P1)
	local X2, Y2, Z2 = unpack(P2)

	local A = mul(Z1, Z2)
	local B = sqr(A)
	local C = mul(X1, X2)
	local D = mul(Y1, Y2)
	local E = mul(d, mul(C, D))
	local F = sub(B, E)
	local G = add(B, E)
	local X3 = mul(A, mul(F, sub(mul(add(X1, Y1), add(X2, Y2)), add(C, D))))
	local Y3 = mul(A, mul(G, sub(D, C)))
	local Z3 = mul(F, G)

	local P3 = {X3, Y3, Z3}

	return P3
end

local function pointNeg(P1)
	local X1, Y1, Z1 = unpack(P1)

	local X3 = sub(p, X1)
	local Y3 = {unpack(Y1)}
	local Z3 = {unpack(Z1)}

	local P3 = {X3, Y3, Z3}

	return P3
end

local function pointSub(P1, P2)
	return pointAdd(P1, pointNeg(P2))
end

local function pointScale(P1)
	local X1, Y1, Z1 = unpack(P1)

	local A = expMod(Z1, pMinusTwoBinary)
	local X3 = mul(X1, A)
	local Y3 = mul(Y1, A)
	local Z3 = {unpack(ONE)}

	local P3 = {X3, Y3, Z3}

	return P3
end

local function pointEq(P1, P2)
	local X1, Y1, Z1 = unpack(P1)
	local X2, Y2, Z2 = unpack(P2)

	local A1 = mul(X1, Z2)
	local B1 = mul(Y1, Z2)
	local A2 = mul(X2, Z1)
	local B2 = mul(Y2, Z1)

	return eq(A1, A2) and eq(B1, B2)
end

local function pointIsOnCurve(P1)
	local X1, Y1, Z1 = unpack(P1)

	local X12 = sqr(X1)
	local Y12 = sqr(Y1)
	local Z12 = sqr(Z1)
	local Z14 = sqr(Z12)
	local a = add(X12, Y12)
	a = mul(a, Z12)
	local b = mul(d, mul(X12, Y12))
	b = add(Z14, b)

	return eq(a, b)
end

local function mods(d)
	-- w = 5
	local result = d[1] % 32

	if result >= 16 then
		result = result - 32
	end

	return result
end

local function NAF(d)
	local t = {}
	local d = {unpack(d)}

	while d[12] >= 0 and not eq(d, ZERO) do
		if d[1] % 2 == 1 then
			t[#t + 1] = mods(d)
			d = sub192(d, {t[#t], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
		else
			t[#t + 1] = 0
		end

		d = shr(d)
	end

	return t
end

local function scalarMul(s, P1)
	local naf = NAF(s)
	local PTable = {P1}
	local P2 = pointDouble(P1)

	for i = 3, 31, 2 do
		PTable[i] = pointAdd(PTable[i - 2], P2)
	end

	local Q = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}}
	for i = #naf, 1, -1 do
		Q = pointDouble(Q)
		if naf[i] > 0 then
			Q = pointAdd(Q, PTable[naf[i]])
		elseif naf[i] < 0 then
			Q = pointSub(Q, PTable[-naf[i]])
		end
	end

	return Q
end

for i = 2, 196 do
	GTable[i] = pointDouble(GTable[i - 1])
end

local function scalarMulG(s)
	local result = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}}
	local k = 1

	for i = 1, 12 do
		local w = s[i]

		for j = 1, 16 do
			if w % 2 == 1 then
				result = pointAdd(result, GTable[k])
			end

			k = k + 1

			w = w / 2
			w = w - w % 1
		end
	end

	return result
end

local function pointEncode(P1)
	P1 = pointScale(P1)

	local result = {}
	local x, y = unpack(P1)

	result[1] = x[1] % 2

	for i = 1, 12 do
		local m = y[i] % 256
		result[2 * i] = m
		result[2 * i + 1] = (y[i] - m) / 256
	end

	return setmetatable(result, mt)
end

local function pointDecode(enc)
	local y = {}
	for i = 1, 12 do
		y[i] = enc[2 * i]
		y[i] = y[i] + enc[2 * i + 1] * 256
	end

	local y2 = sqr(y)
	local u = sub(y2, ONE)
	local v = sub(mul(d, y2), ONE)
	local u2 = sqr(u)
	local u3 = mul(u, u2)
	local u5 = mul(u3, u2)
	local v3 = mul(v, sqr(v))
	local w = mul(u5, v3)
	local x = mul(u3, mul(v, expMod(w, pMinusThreeOverFourBinary)))

	if x[1] % 2 ~= enc[1] then
		x = sub(p, x)
	end

	local P3 = {x, y, {unpack(ONE)}}

	return P3
end

return {
	G = G,
	pointAdd = pointAdd,
	pointNeg = pointNeg,
	pointSub = pointSub,
	pointEq = pointEq,
	pointIsOnCurve = pointIsOnCurve,
	scalarMul = scalarMul,
	scalarMulG = scalarMulG,
	pointEncode = pointEncode,
	pointDecode = pointDecode
}
end
preload["ecc"] = function(...)
local fq = irequire("fq")
local elliptic = irequire("elliptic")
local sha256 = require("sha256")
require("urandom")

local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532}

local sLen = 24
local eLen = 24

local function hashModQ(sk)
	local hash = sha256.hmac({0x00}, sk)
	local x
	repeat
		hash = sha256.digest(hash)
		x = fq.fromBytes(hash)
	until fq.cmp(x, q) <= 0

	return x
end

local function publicKey(sk)
	local x = hashModQ(sk)

	local Y = elliptic.scalarMulG(x)
	local pk = elliptic.pointEncode(Y)

	return pk
end

local function keypair()
	local priv = os.urandom()
	local pub = publicKey(priv)
	return pub, priv
end

local function exchange(sk, pk)
	local Y = elliptic.pointDecode(pk)
	local x = hashModQ(sk)

	local Z = elliptic.scalarMul(x, Y)
	Z = elliptic.pointScale(Z)

	local ss = fq.bytes(Z[2])
	local ss = sha256.digest(ss)

	return ss
end

local function sign(sk, message)
	message = type(message) == "table" and string.char(unpack(message)) or message
	sk = type(sk) == "table" and string.char(unpack(sk)) or sk
	local epoch = tostring(os.epoch("utc"))
	local x = hashModQ(sk)
	local k = hashModQ(message .. epoch .. sk)
	
	local R = elliptic.scalarMulG(k)
	R = string.char(unpack(elliptic.pointEncode(R)))
	local e = hashModQ(R .. message)
	local s = fq.sub(k, fq.mul(x, e))

	e = fq.bytes(e)
	s = fq.bytes(s)

	local sig = e

	for i = 1, #s do
		sig[#sig + 1] = s[i]
	end

	return sig
end

local function verify(pk, message, sig)
	local Y = elliptic.pointDecode(pk)
	local e = {unpack(sig, 1, eLen)}
	local s = {unpack(sig, eLen + 1, eLen + sLen)}

	e = fq.fromBytes(e)
	s = fq.fromBytes(s)

	local R = elliptic.pointAdd(elliptic.scalarMulG(s), elliptic.scalarMul(e, Y))
	R = string.char(unpack(elliptic.pointEncode(R)))
	local e2 = hashModQ(R .. message)

	return fq.eq(e2, e)
end

return {
	publicKey = publicKey,
	exchange = exchange,
	sign = sign,
	verify = verify,
	keypair = keypair
}
end
return irequire