Handles point calculations
Returns a new point from big ints
Returns the affine of x
Returns the affine of y
Returns a point from affine parameters
Returns the negation of a point
Checks if two points are equal
Multiplies two points
Multiplies two points twice
Adds two points
module ECurve.Point exposing (new, affineX, affineY, fromAffine, negate, equal, multiply, twice, add)
{-| Handles point calculations
@docs new, affineX, affineY, fromAffine, negate, equal, multiply, twice, add
-}
import BigInt exposing (BigInt, mul, mod, sub, pow)
import ECurve.Util exposing (modInverse, signum, bitLength, testBit, square, zero, one, two, three, four, eight)
import ECurve.Models exposing (Point, Curve)
{-| Returns a new point from big ints
-}
new : BigInt -> BigInt -> BigInt -> BigInt -> BigInt -> Point
new p a x y z =
{ x = x
, y = y
, z = z
, p = p
, a = a
, zInv = modInverse z p
, compressed = True
}
{-| Returns the affine of x
-}
affineX : Point -> BigInt
affineX p =
mod (mul p.x p.zInv) p.p
{-| Returns the affine of y
-}
affineY : Point -> BigInt
affineY p =
mod (mul p.y p.zInv) p.p
{-| Returns a point from affine parameters
-}
fromAffine : BigInt -> BigInt -> BigInt -> BigInt -> Point
fromAffine p a x y =
new p a x y one
{-| Returns the negation of a point
-}
negate : Point -> Point
negate p =
let
y =
sub p.p p.y
in
new p.p p.a p.x y p.z
{-| Checks if two points are equal
-}
equal : Point -> Point -> Bool
equal p1 p2 =
if p1 == p2 then
True
else
let
u =
sub (mul p2.y p1.z) (mul p1.y p2.z)
in
if signum u == EQ then
False
else
let
v =
sub (mul p2.x p1.z) (mul p1.x p2.z)
in
signum v == EQ
{-| Multiplies two points
-}
multiply : Point -> BigInt -> Point
multiply p d =
let
dMul3 =
mul d three
negP =
negate p
bitLen =
bitLength dMul3
r =
loopBits p negP d dMul3 (bitLen - 2) bitLen
in
r
loopBits : Point -> Point -> BigInt -> BigInt -> Int -> Int -> Point
loopBits p neg d dMul3 index bitLen =
if index > 0 then
p
else
let
hBit =
testBit dMul3 index
kBit =
testBit d index
r =
twice p
toAdd =
if hBit then
p
else
neg
rr =
if hBit /= kBit then
add r toAdd
else
r
in
loopBits rr neg d dMul3 (index - 1) bitLen
{-| Multiplies two points twice
-}
twice : Point -> Point
twice p =
let
x1 =
p.x
y1 =
p.y
z1 =
p.z
y1z1 =
mod (mul y1 p.z) p.p
y1sqz1 =
mod (mul y1z1 y1) p.p
a =
p.a
-- w = 3 * x1^2 + a * z1^2
w =
if signum a /= EQ then
mod (BigInt.add (mul (square x1) three) (mul (square p.z) a)) p.p
else
mod (mul (square x1) three) p.p
-- x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
x3 =
mod (mul (mul (mul two y1) z1) (sub (square w) (mul (mul (mul eight x1) (square y1)) z1))) p.p
-- y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
y3 =
mod (sub (mul (mul (mul four (square y1)) z1) (sub (mul (mul three w) x1) (mul (mul two (square y1)) z1))) (pow w three)) p.p
z3 =
mod (mul (pow y1z1 three) eight) p.p
in
new p.p p.a x3 y3 z3
{-| Adds two points
-}
add : Point -> Point -> Point
add a b =
let
x1 =
a.x
y1 =
a.y
z1 =
a.z
x2 =
b.x
y2 =
b.y
z2 =
b.z
curveP =
a.p
-- u = Y2 * Z1 - Y1 * Z2
u =
mod (sub (mul y2 z1) (mul y1 z2)) curveP
-- v = X2 * Z1 - X1 * Z2
v =
mod (sub (mul x2 z1) (mul x1 z2)) curveP
result =
if signum v == EQ then
if signum u == EQ then
-- a == b, so double
twice a
else
-- a = -b, so infinity
new a.p a.a zero zero zero
else
let
v2 =
square v
v3 =
mul v2 v
x1v2 =
mul x1 v2
zu2 =
mul (square u) z1
-- x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
x3 =
mod (mul v (sub (mul z2 (sub zu2 (mul two x1v2))) v3)) curveP
-- y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
y3 =
mod (BigInt.add (mul (sub (sub (mul (mul x1v2 three) u) (mul y1 v3)) (mul zu2 u)) z2) (mul u v3)) curveP
-- z3 = v^3 * z1 * z2
z3 =
mod (mul (mul v3 z1) z2) curveP
in
new a.p a.a x3 y3 z3
in
result