mirror of https://github.com/kepler155c/opus
301 lines
7.4 KiB
Lua
301 lines
7.4 KiB
Lua
---- 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.
|
|
|
|
local fp = require('opus.crypto.ecc.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 function generator()
|
|
return G
|
|
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 isOnCurve(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 result
|
|
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 {
|
|
generator = generator,
|
|
pointDouble = pointDouble,
|
|
pointAdd = pointAdd,
|
|
pointNeg = pointNeg,
|
|
pointSub = pointSub,
|
|
pointScale = pointScale,
|
|
pointEq = pointEq,
|
|
isOnCurve = isOnCurve,
|
|
scalarMul = scalarMul,
|
|
scalarMulG = scalarMulG,
|
|
pointEncode = pointEncode,
|
|
pointDecode = pointDecode,
|
|
}
|