    -- | Elliptic Curve Arithmetic.
    --
    -- /WARNING:/ These functions are vulnerable to timing attacks.
    {-# LANGUAGE ScopedTypeVariables #-}
    module Crypto.ECC.Simple.Prim
        ( scalarGenerate
        , scalarFromInteger
        , pointAdd
        , pointNegate
        , pointDouble
        , pointBaseMul
        , pointMul
        , pointAddTwoMuls
        , pointFromIntegers
        , isPointAtInfinity
        , isPointValid
        ) where

    import Data.Maybe
    import Data.Proxy
    import Crypto.Number.ModArithmetic
    import Crypto.Number.F2m
    import Crypto.Number.Generate (generateBetween)
    import Crypto.ECC.Simple.Types
    import Crypto.Error
    import Crypto.Random

    -- | Generate a valid scalar for a specific Curve
    scalarGenerate :: forall randomly curve . (MonadRandom randomly, Curve curve) => randomly (Scalar curve)
    scalarGenerate :: randomly (Scalar curve)
    scalarGenerate =
        Integer -> Scalar curve
    forall curve. Integer -> Scalar curve
    Scalar (Integer -> Scalar curve)
    -> randomly Integer -> randomly (Scalar curve)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Integer -> Integer -> randomly Integer
    forall (m :: * -> *).
    MonadRandom m =>
    Integer -> Integer -> m Integer
    generateBetween 1 (Integer
    n Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - 1)
      where
        n :: Integer
    n = CurveParameters curve -> Integer
    forall curve. CurveParameters curve -> Integer
    curveEccN (CurveParameters curve -> Integer)
    -> CurveParameters curve -> Integer
    forall a b. (a -> b) -> a -> b
    $ Proxy curve -> CurveParameters curve
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveParameters curve
    curveParameters (Proxy curve
    forall k (t :: k). Proxy t
    Proxy :: Proxy curve)

    scalarFromInteger :: forall curve . Curve curve => Integer -> CryptoFailable (Scalar curve)
    scalarFromInteger :: Integer -> CryptoFailable (Scalar curve)
    scalarFromInteger n :: Integer
    n
        | Integer
    n Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    < 0  Bool -> Bool -> Bool
    || Integer
    n Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Integer
    mx = CryptoError -> CryptoFailable (Scalar curve)
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed (CryptoError -> CryptoFailable (Scalar curve))
    -> CryptoError -> CryptoFailable (Scalar curve)
    forall a b. (a -> b) -> a -> b
    $ CryptoError
    CryptoError_EcScalarOutOfBounds
        | Bool
    otherwise         = Scalar curve -> CryptoFailable (Scalar curve)
    forall a. a -> CryptoFailable a
    CryptoPassed (Scalar curve -> CryptoFailable (Scalar curve))
    -> Scalar curve -> CryptoFailable (Scalar curve)
    forall a b. (a -> b) -> a -> b
    $ Integer -> Scalar curve
    forall curve. Integer -> Scalar curve
    Scalar Integer
    n
      where
        mx :: Integer
    mx = case Proxy curve -> CurveType
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveType
    curveType (Proxy curve
    forall k (t :: k). Proxy t
    Proxy :: Proxy curve) of
                CurveBinary (CurveBinaryParam b :: Integer
    b) -> Integer
    b
                CurvePrime (CurvePrimeParam p :: Integer
    p)   -> Integer
    p

    --TODO: Extract helper function for `fromMaybe PointO...`

    -- | Elliptic Curve point negation:
    -- @pointNegate p@ returns point @q@ such that @pointAdd p q == PointO@.
    pointNegate :: Curve curve => Point curve -> Point curve
    pointNegate :: Point curve -> Point curve
    pointNegate        PointO     = Point curve
    forall curve. Point curve
    PointO
    pointNegate point :: Point curve
    point@(Point x :: Integer
    x y :: Integer
    y) =
        case Point curve -> CurveType
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveType
    curveType Point curve
    point of
            CurvePrime (CurvePrimeParam p :: Integer
    p) -> Integer -> Integer -> Point curve
    forall curve. Integer -> Integer -> Point curve
    Point Integer
    x (Integer
    p Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    y)
            CurveBinary {} -> Integer -> Integer -> Point curve
    forall curve. Integer -> Integer -> Point curve
    Point Integer
    x (Integer
    x Integer -> Integer -> Integer
    `addF2m` Integer
    y)

    -- | Elliptic Curve point addition.
    --
    -- /WARNING:/ Vulnerable to timing attacks.
    pointAdd :: Curve curve => Point curve -> Point curve -> Point curve
    pointAdd :: Point curve -> Point curve -> Point curve
    pointAdd PointO PointO = Point curve
    forall curve. Point curve
    PointO
    pointAdd PointO q :: Point curve
    q = Point curve
    q
    pointAdd p :: Point curve
    p PointO = Point curve
    p
    pointAdd p :: Point curve
    p q :: Point curve
    q
      | Point curve
    p Point curve -> Point curve -> Bool
    forall a. Eq a => a -> a -> Bool
    == Point curve
    q             = Point curve -> Point curve
    forall curve. Curve curve => Point curve -> Point curve
    pointDouble Point curve
    p
      | Point curve
    p Point curve -> Point curve -> Bool
    forall a. Eq a => a -> a -> Bool
    == Point curve -> Point curve
    forall curve. Curve curve => Point curve -> Point curve
    pointNegate Point curve
    q = Point curve
    forall curve. Point curve
    PointO
    pointAdd point :: Point curve
    point@(Point xp :: Integer
    xp yp :: Integer
    yp) (Point xq :: Integer
    xq yq :: Integer
    yq) =
        case CurveType
    ty of
            CurvePrime (CurvePrimeParam pr :: Integer
    pr) -> Point curve -> Maybe (Point curve) -> Point curve
    forall a. a -> Maybe a -> a
    fromMaybe Point curve
    forall curve. Point curve
    PointO (Maybe (Point curve) -> Point curve)
    -> Maybe (Point curve) -> Point curve
    forall a b. (a -> b) -> a -> b
    $ do
                Integer
    s <- Integer -> Integer -> Integer -> Maybe Integer
    divmod (Integer
    yp Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    yq) (Integer
    xp Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    xq) Integer
    pr
                let xr :: Integer
    xr = (Integer
    s Integer -> Int -> Integer
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (2::Int) Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    xp Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    xq) Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    pr
                    yr :: Integer
    yr = (Integer
    s Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * (Integer
    xp Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    xr) Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    yp) Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    pr
                Point curve -> Maybe (Point curve)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Point curve -> Maybe (Point curve))
    -> Point curve -> Maybe (Point curve)
    forall a b. (a -> b) -> a -> b
    $ Integer -> Integer -> Point curve
    forall curve. Integer -> Integer -> Point curve
    Point Integer
    xr Integer
    yr
            CurveBinary (CurveBinaryParam fx :: Integer
    fx) -> Point curve -> Maybe (Point curve) -> Point curve
    forall a. a -> Maybe a -> a
    fromMaybe Point curve
    forall curve. Point curve
    PointO (Maybe (Point curve) -> Point curve)
    -> Maybe (Point curve) -> Point curve
    forall a b. (a -> b) -> a -> b
    $ do
                Integer
    s <- Integer -> Integer -> Integer -> Maybe Integer
    divF2m Integer
    fx (Integer
    yp Integer -> Integer -> Integer
    `addF2m` Integer
    yq) (Integer
    xp Integer -> Integer -> Integer
    `addF2m` Integer
    xq)
                let xr :: Integer
    xr = Integer -> Integer -> Integer -> Integer
    mulF2m Integer
    fx Integer
    s Integer
    s Integer -> Integer -> Integer
    `addF2m` Integer
    s Integer -> Integer -> Integer
    `addF2m` Integer
    xp Integer -> Integer -> Integer
    `addF2m` Integer
    xq Integer -> Integer -> Integer
    `addF2m` Integer
    a
                    yr :: Integer
    yr = Integer -> Integer -> Integer -> Integer
    mulF2m Integer
    fx Integer
    s (Integer
    xp Integer -> Integer -> Integer
    `addF2m` Integer
    xr) Integer -> Integer -> Integer
    `addF2m` Integer
    xr Integer -> Integer -> Integer
    `addF2m` Integer
    yp
                Point curve -> Maybe (Point curve)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Point curve -> Maybe (Point curve))
    -> Point curve -> Maybe (Point curve)
    forall a b. (a -> b) -> a -> b
    $ Integer -> Integer -> Point curve
    forall curve. Integer -> Integer -> Point curve
    Point Integer
    xr Integer
    yr
      where
        ty :: CurveType
    ty = Point curve -> CurveType
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveType
    curveType Point curve
    point
        cc :: CurveParameters curve
    cc = Point curve -> CurveParameters curve
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveParameters curve
    curveParameters Point curve
    point
        a :: Integer
    a  = CurveParameters curve -> Integer
    forall curve. CurveParameters curve -> Integer
    curveEccA CurveParameters curve
    cc

    -- | Elliptic Curve point doubling.
    --
    -- /WARNING:/ Vulnerable to timing attacks.
    --
    -- This perform the following calculation:
    -- > lambda = (3 * xp ^ 2 + a) / 2 yp
    -- > xr = lambda ^ 2 - 2 xp
    -- > yr = lambda (xp - xr) - yp
    --
    -- With binary curve:
    -- > xp == 0   => P = O
    -- > otherwise =>
    -- >    s = xp + (yp / xp)
    -- >    xr = s ^ 2 + s + a
    -- >    yr = xp ^ 2 + (s+1) * xr
    --
    pointDouble :: Curve curve => Point curve -> Point curve
    pointDouble :: Point curve -> Point curve
    pointDouble PointO = Point curve
    forall curve. Point curve
    PointO
    pointDouble point :: Point curve
    point@(Point xp :: Integer
    xp yp :: Integer
    yp) =
        case CurveType
    ty of
            CurvePrime (CurvePrimeParam pr :: Integer
    pr) -> Point curve -> Maybe (Point curve) -> Point curve
    forall a. a -> Maybe a -> a
    fromMaybe Point curve
    forall curve. Point curve
    PointO (Maybe (Point curve) -> Point curve)
    -> Maybe (Point curve) -> Point curve
    forall a b. (a -> b) -> a -> b
    $ do
                Integer
    lambda <- Integer -> Integer -> Integer -> Maybe Integer
    divmod (3 Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    xp Integer -> Int -> Integer
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (2::Int) Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer
    a) (2 Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    yp) Integer
    pr
                let xr :: Integer
    xr = (Integer
    lambda Integer -> Int -> Integer
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (2::Int) Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - 2 Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    xp) Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    pr
                    yr :: Integer
    yr = (Integer
    lambda Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * (Integer
    xp Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    xr) Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    yp) Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    pr
                Point curve -> Maybe (Point curve)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Point curve -> Maybe (Point curve))
    -> Point curve -> Maybe (Point curve)
    forall a b. (a -> b) -> a -> b
    $ Integer -> Integer -> Point curve
    forall curve. Integer -> Integer -> Point curve
    Point Integer
    xr Integer
    yr
            CurveBinary (CurveBinaryParam fx :: Integer
    fx)
                | Integer
    xp Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0    -> Point curve
    forall curve. Point curve
    PointO
                | Bool
    otherwise  -> Point curve -> Maybe (Point curve) -> Point curve
    forall a. a -> Maybe a -> a
    fromMaybe Point curve
    forall curve. Point curve
    PointO (Maybe (Point curve) -> Point curve)
    -> Maybe (Point curve) -> Point curve
    forall a b. (a -> b) -> a -> b
    $ do
                    Integer
    s <- Integer -> Maybe Integer
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Integer -> Maybe Integer)
    -> (Integer -> Integer) -> Integer -> Maybe Integer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Integer -> Integer -> Integer
    addF2m Integer
    xp (Integer -> Maybe Integer) -> Maybe Integer -> Maybe Integer
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< Integer -> Integer -> Integer -> Maybe Integer
    divF2m Integer
    fx Integer
    yp Integer
    xp
                    let xr :: Integer
    xr = Integer -> Integer -> Integer -> Integer
    mulF2m Integer
    fx Integer
    s Integer
    s Integer -> Integer -> Integer
    `addF2m` Integer
    s Integer -> Integer -> Integer
    `addF2m` Integer
    a
                        yr :: Integer
    yr = Integer -> Integer -> Integer -> Integer
    mulF2m Integer
    fx Integer
    xp Integer
    xp Integer -> Integer -> Integer
    `addF2m` Integer -> Integer -> Integer -> Integer
    mulF2m Integer
    fx Integer
    xr (Integer
    s Integer -> Integer -> Integer
    `addF2m` 1)
                    Point curve -> Maybe (Point curve)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Point curve -> Maybe (Point curve))
    -> Point curve -> Maybe (Point curve)
    forall a b. (a -> b) -> a -> b
    $ Integer -> Integer -> Point curve
    forall curve. Integer -> Integer -> Point curve
    Point Integer
    xr Integer
    yr
      where
        ty :: CurveType
    ty = Point curve -> CurveType
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveType
    curveType Point curve
    point
        cc :: CurveParameters curve
    cc = Point curve -> CurveParameters curve
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveParameters curve
    curveParameters Point curve
    point
        a :: Integer
    a  = CurveParameters curve -> Integer
    forall curve. CurveParameters curve -> Integer
    curveEccA CurveParameters curve
    cc

    -- | Elliptic curve point multiplication using the base
    --
    -- /WARNING:/ Vulnerable to timing attacks.
    pointBaseMul :: Curve curve => Scalar curve -> Point curve
    pointBaseMul :: Scalar curve -> Point curve
    pointBaseMul n :: Scalar curve
    n = Scalar curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Scalar curve -> Point curve -> Point curve
    pointMul Scalar curve
    n (CurveParameters curve -> Point curve
    forall curve. CurveParameters curve -> Point curve
    curveEccG (CurveParameters curve -> Point curve)
    -> CurveParameters curve -> Point curve
    forall a b. (a -> b) -> a -> b
    $ Proxy curve -> CurveParameters curve
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveParameters curve
    curveParameters (forall curve. Proxy curve
    forall k (t :: k). Proxy t
    Proxy :: Proxy curve))

    -- | Elliptic curve point multiplication (double and add algorithm).
    --
    -- /WARNING:/ Vulnerable to timing attacks.
    pointMul :: Curve curve => Scalar curve -> Point curve -> Point curve
    pointMul :: Scalar curve -> Point curve -> Point curve
    pointMul _ PointO = Point curve
    forall curve. Point curve
    PointO
    pointMul (Scalar n :: Integer
    n) p :: Point curve
    p
        | Integer
    n Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0    = Point curve
    forall curve. Point curve
    PointO
        | Integer
    n Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == 1    = Point curve
    p
        | Integer -> Bool
    forall a. Integral a => a -> Bool
    odd Integer
    n     = Point curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Point curve -> Point curve -> Point curve
    pointAdd Point curve
    p (Scalar curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Scalar curve -> Point curve -> Point curve
    pointMul (Integer -> Scalar curve
    forall curve. Integer -> Scalar curve
    Scalar (Integer
    n Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - 1)) Point curve
    p)
        | Bool
    otherwise = Scalar curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Scalar curve -> Point curve -> Point curve
    pointMul (Integer -> Scalar curve
    forall curve. Integer -> Scalar curve
    Scalar (Integer
    n Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `div` 2)) (Point curve -> Point curve
    forall curve. Curve curve => Point curve -> Point curve
    pointDouble Point curve
    p)

    -- | Elliptic curve double-scalar multiplication (uses Shamir's trick).
    --
    -- > pointAddTwoMuls n1 p1 n2 p2 == pointAdd (pointMul n1 p1)
    -- >                                         (pointMul n2 p2)
    --
    -- /WARNING:/ Vulnerable to timing attacks.
    pointAddTwoMuls :: Curve curve => Scalar curve -> Point curve -> Scalar curve -> Point curve -> Point curve
    pointAddTwoMuls :: Scalar curve
    -> Point curve -> Scalar curve -> Point curve -> Point curve
    pointAddTwoMuls _  PointO _  PointO = Point curve
    forall curve. Point curve
    PointO
    pointAddTwoMuls _  PointO n2 :: Scalar curve
    n2 p2 :: Point curve
    p2     = Scalar curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Scalar curve -> Point curve -> Point curve
    pointMul Scalar curve
    n2 Point curve
    p2
    pointAddTwoMuls n1 :: Scalar curve
    n1 p1 :: Point curve
    p1     _  PointO = Scalar curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Scalar curve -> Point curve -> Point curve
    pointMul Scalar curve
    n1 Point curve
    p1
    pointAddTwoMuls (Scalar n1 :: Integer
    n1) p1 :: Point curve
    p1 (Scalar n2 :: Integer
    n2) p2 :: Point curve
    p2 = (Integer, Integer) -> Point curve
    forall a a. (Integral a, Integral a) => (a, a) -> Point curve
    go (Integer
    n1, Integer
    n2)
      where
        p0 :: Point curve
    p0 = Point curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Point curve -> Point curve -> Point curve
    pointAdd Point curve
    p1 Point curve
    p2

        go :: (a, a) -> Point curve
    go (0,  0 ) = Point curve
    forall curve. Point curve
    PointO
        go (k1 :: a
    k1, k2 :: a
    k2) =
            let q :: Point curve
    q = Point curve -> Point curve
    forall curve. Curve curve => Point curve -> Point curve
    pointDouble (Point curve -> Point curve) -> Point curve -> Point curve
    forall a b. (a -> b) -> a -> b
    $ (a, a) -> Point curve
    go (a
    k1 a -> a -> a
    forall a. Integral a => a -> a -> a
    `div` 2, a
    k2 a -> a -> a
    forall a. Integral a => a -> a -> a
    `div` 2)
            in case (a -> Bool
    forall a. Integral a => a -> Bool
    odd a
    k1, a -> Bool
    forall a. Integral a => a -> Bool
    odd a
    k2) of
                (True  , True  ) -> Point curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Point curve -> Point curve -> Point curve
    pointAdd Point curve
    p0 Point curve
    q
                (True  , False ) -> Point curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Point curve -> Point curve -> Point curve
    pointAdd Point curve
    p1 Point curve
    q
                (False , True  ) -> Point curve -> Point curve -> Point curve
    forall curve.
    Curve curve =>
    Point curve -> Point curve -> Point curve
    pointAdd Point curve
    p2 Point curve
    q
                (False , False ) -> Point curve
    q

    -- | Check if a point is the point at infinity.
    isPointAtInfinity :: Point curve -> Bool
    isPointAtInfinity :: Point curve -> Bool
    isPointAtInfinity PointO = Bool
    True
    isPointAtInfinity _      = Bool
    False

    -- | Make a point on a curve from integer (x,y) coordinate
    --
    -- if the point is not valid related to the curve then an error is
    -- returned instead of a point
    pointFromIntegers :: forall curve . Curve curve => (Integer, Integer) -> CryptoFailable (Point curve)
    pointFromIntegers :: (Integer, Integer) -> CryptoFailable (Point curve)
    pointFromIntegers (x :: Integer
    x,y :: Integer
    y)
        | Proxy curve -> Integer -> Integer -> Bool
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> Integer -> Integer -> Bool
    isPointValid (Proxy curve
    forall k (t :: k). Proxy t
    Proxy :: Proxy curve) Integer
    x Integer
    y = Point curve -> CryptoFailable (Point curve)
    forall a. a -> CryptoFailable a
    CryptoPassed (Point curve -> CryptoFailable (Point curve))
    -> Point curve -> CryptoFailable (Point curve)
    forall a b. (a -> b) -> a -> b
    $ Integer -> Integer -> Point curve
    forall curve. Integer -> Integer -> Point curve
    Point Integer
    x Integer
    y
        | Bool
    otherwise                               = CryptoError -> CryptoFailable (Point curve)
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed (CryptoError -> CryptoFailable (Point curve))
    -> CryptoError -> CryptoFailable (Point curve)
    forall a b. (a -> b) -> a -> b
    $ CryptoError
    CryptoError_PointCoordinatesInvalid

    -- | check if a point is on specific curve
    --
    -- This perform three checks:
    --
    -- * x is not out of range
    -- * y is not out of range
    -- * the equation @y^2 = x^3 + a*x + b (mod p)@ holds
    isPointValid :: Curve curve => proxy curve -> Integer -> Integer -> Bool
    isPointValid :: proxy curve -> Integer -> Integer -> Bool
    isPointValid proxy :: proxy curve
    proxy x :: Integer
    x y :: Integer
    y =
        case CurveType
    ty of
            CurvePrime (CurvePrimeParam p :: Integer
    p) ->
                let a :: Integer
    a  = CurveParameters curve -> Integer
    forall curve. CurveParameters curve -> Integer
    curveEccA CurveParameters curve
    cc
                    b :: Integer
    b  = CurveParameters curve -> Integer
    forall curve. CurveParameters curve -> Integer
    curveEccB CurveParameters curve
    cc
                    eqModP :: Integer -> Integer -> Bool
    eqModP z1 :: Integer
    z1 z2 :: Integer
    z2 = (Integer
    z1 Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    p) Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == (Integer
    z2 Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    p)
                    isValid :: Integer -> Bool
    isValid e :: Integer
    e = Integer
    e Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    >= 0 Bool -> Bool -> Bool
    && Integer
    e Integer -> Integer -> Bool
    forall a. Ord a => a -> a -> Bool
    < Integer
    p
                 in Integer -> Bool
    isValid Integer
    x Bool -> Bool -> Bool
    && Integer -> Bool
    isValid Integer
    y Bool -> Bool -> Bool
    && (Integer
    y Integer -> Int -> Integer
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (2 :: Int)) Integer -> Integer -> Bool
    `eqModP` (Integer
    x Integer -> Int -> Integer
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (3 :: Int) Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer
    a Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    x Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer
    b)
            CurveBinary (CurveBinaryParam fx :: Integer
    fx) ->
                let a :: Integer
    a  = CurveParameters curve -> Integer
    forall curve. CurveParameters curve -> Integer
    curveEccA CurveParameters curve
    cc
                    b :: Integer
    b  = CurveParameters curve -> Integer
    forall curve. CurveParameters curve -> Integer
    curveEccB CurveParameters curve
    cc
                    add :: Integer -> Integer -> Integer
    add = Integer -> Integer -> Integer
    addF2m
                    mul :: Integer -> Integer -> Integer
    mul = Integer -> Integer -> Integer -> Integer
    mulF2m Integer
    fx
                    isValid :: Integer -> Bool
    isValid e :: Integer
    e = Integer -> Integer -> Integer
    modF2m Integer
    fx Integer
    e Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == Integer
    e
                 in [Bool] -> Bool
    forall (t :: * -> *). Foldable t => t Bool -> Bool
    and [ Integer -> Bool
    isValid Integer
    x
                        , Integer -> Bool
    isValid Integer
    y
                        , ((((Integer
    x Integer -> Integer -> Integer
    `add` Integer
    a) Integer -> Integer -> Integer
    `mul` Integer
    x Integer -> Integer -> Integer
    `add` Integer
    y) Integer -> Integer -> Integer
    `mul` Integer
    x) Integer -> Integer -> Integer
    `add` Integer
    b Integer -> Integer -> Integer
    `add` (Integer -> Integer -> Integer
    squareF2m Integer
    fx Integer
    y)) Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0
                        ]
      where
        ty :: CurveType
    ty = proxy curve -> CurveType
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveType
    curveType proxy curve
    proxy
        cc :: CurveParameters curve
    cc = proxy curve -> CurveParameters curve
    forall curve (proxy :: * -> *).
    Curve curve =>
    proxy curve -> CurveParameters curve
    curveParameters proxy curve
    proxy

    -- | div and mod
    divmod :: Integer -> Integer -> Integer -> Maybe Integer
    divmod :: Integer -> Integer -> Integer -> Maybe Integer
    divmod y :: Integer
    y x :: Integer
    x m :: Integer
    m = do
        Integer
    i <- Integer -> Integer -> Maybe Integer
    inverse (Integer
    x Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    m) Integer
    m
        Integer -> Maybe Integer
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Integer -> Maybe Integer) -> Integer -> Maybe Integer
    forall a b. (a -> b) -> a -> b
    $ Integer
    y Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    * Integer
    i Integer -> Integer -> Integer
    forall a. Integral a => a -> a -> a
    `mod` Integer
    m