Current section
Files
Jump to
Current section
Files
lib/curves/math.ex
defmodule CA.Jacobian do
require CA.Integer
require CA.Point
@moduledoc false
def toJacobian(p), do: %CA.Point{x: p.x, y: p.y, z: 1}
def fromJacobian(p, cP) do
z = inv(p.z, cP)
%CA.Point{
x: CA.Integer.modulo(p.x * CA.Integer.ipow(z, 2), cP),
y: CA.Integer.modulo(p.y * CA.Integer.ipow(z, 3), cP)
}
end
def multiply(p, n, cN, cA, cP), do:
p |> toJacobian()
|> jacobianMultiply(n, cN, cA, cP)
|> fromJacobian(cP)
def add(p, q, cA, cP), do:
jacobianAdd(toJacobian(p), toJacobian(q), cA, cP)
|> fromJacobian(cP)
def inv(x, _) when x == 0, do: 0
def inv(x, n), do:
invOperator(1, 0, CA.Integer.modulo(x, n), n)
|> CA.Integer.modulo(n)
def invOperator(lm, hm, low, high) when low > 1 do
r = div(high, low)
invOperator(hm - lm * r, lm, high - low * r, low) end
def invOperator(lm, _, _, _), do: lm
def jacobianDouble(p, cA, cP) do
if p.y == 0 do
%CA.Point{x: 0, y: 0, z: 0}
else
ysq = CA.Integer.ipow(p.y, 2) |> CA.Integer.modulo(cP)
s = (4 * p.x * ysq) |> CA.Integer.modulo(cP)
m = (3 * CA.Integer.ipow(p.x, 2) + cA * CA.Integer.ipow(p.z, 4)) |> CA.Integer.modulo(cP)
nx = (CA.Integer.ipow(m, 2) - 2 * s) |> CA.Integer.modulo(cP)
ny = (m * (s - nx) - 8 * CA.Integer.ipow(ysq, 2)) |> CA.Integer.modulo(cP)
nz = (2 * p.y * p.z) |> CA.Integer.modulo(cP)
%CA.Point{x: nx, y: ny, z: nz}
end
end
def jacobianAdd(p, q, cA, cP) do
if p.y == 0 do
q
else
if q.y == 0 do
p
else
u1 = (p.x * CA.Integer.ipow(q.z, 2)) |> CA.Integer.modulo(cP)
u2 = (q.x * CA.Integer.ipow(p.z, 2)) |> CA.Integer.modulo(cP)
s1 = (p.y * CA.Integer.ipow(q.z, 3)) |> CA.Integer.modulo(cP)
s2 = (q.y * CA.Integer.ipow(p.z, 3)) |> CA.Integer.modulo(cP)
if u1 == u2 do
if s1 != s2 do
%CA.Point{x: 0, y: 0, z: 1}
else
jacobianDouble(p, cA, cP)
end
else
h = u2 - u1
r = s2 - s1
h2 = (h * h) |> CA.Integer.modulo(cP)
h3 = (h * h2) |> CA.Integer.modulo(cP)
u1h2 = (u1 * h2) |> CA.Integer.modulo(cP)
nx = (CA.Integer.ipow(r, 2) - h3 - 2 * u1h2) |> CA.Integer.modulo(cP)
ny = (r * (u1h2 - nx) - s1 * h3) |> CA.Integer.modulo(cP)
nz = (h * p.z * q.z) |> CA.Integer.modulo(cP)
%CA.Point{x: nx, y: ny, z: nz}
end
end
end
end
def jacobianMultiply(_p, n, _cN, _cA, _cP) when n == 0, do: %CA.Point{x: 0, y: 0, z: 1}
def jacobianMultiply(p, n, _cN, _cA, _cP) when n == 1 do
case p.y do
0 -> %CA.Point{x: 0, y: 0, z: 1}
_ -> p
end
end
def jacobianMultiply(p, n, cN, cA, cP) when n < 0 or n >= cN do
case p.y do
0 -> %CA.Point{x: 0, y: 0, z: 1}
_ -> jacobianMultiply(p, CA.Integer.modulo(n, cN), cN, cA, cP)
end
end
def jacobianMultiply(p, _n, _cN, _cA, _cP) when p.y == 0, do: %CA.Point{x: 0, y: 0, z: 1}
def jacobianMultiply(p, n, cN, cA, cP) when rem(n, 2) == 0 do
jacobianMultiply(p, div(n, 2), cN, cA, cP) |> jacobianDouble(cA, cP)
end
def jacobianMultiply(p, n, cN, cA, cP) do
jacobianMultiply(p, div(n, 2), cN, cA, cP) |> jacobianDouble(cA, cP) |> jacobianAdd(p, cA, cP)
end
end