This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.

ECurve.Point

Handles point calculations

new : BigInt -> BigInt -> BigInt -> BigInt -> BigInt -> Point

Returns a new point from big ints

affineX : Point -> BigInt

Returns the affine of x

affineY : Point -> BigInt

Returns the affine of y

fromAffine : BigInt -> BigInt -> BigInt -> BigInt -> Point

Returns a point from affine parameters

negate : Point -> Point

Returns the negation of a point

equal : Point -> Point -> Bool

Checks if two points are equal

multiply : Point -> BigInt -> Point

Multiplies two points

twice : Point -> Point

Multiplies two points twice

add : Point -> Point -> Point

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