    -- |
    -- Module      : Crypto.PubKey.ECC.DH
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : unknown
    --
    -- Elliptic curve Diffie Hellman
    module Crypto.PubKey.ECC.DH (
        Curve,
        PublicPoint,
        PrivateNumber,
        SharedKey (..),
        generatePrivate,
        calculatePublic,
        getShared,
    ) where

    import Crypto.Number.Generate (generateMax)
    import Crypto.Number.Serialize (i2ospOf_)
    import Crypto.PubKey.DH (SharedKey (..))
    import Crypto.PubKey.ECC.Prim (pointMul)
    import Crypto.PubKey.ECC.Types (
        Curve,
        Point (..),
        PrivateNumber,
        PublicPoint,
        common_curve,
        curveSizeBits,
        ecc_g,
        ecc_n,
     )
    import Crypto.Random.Types

    -- | Generating a private number d.
    generatePrivate :: MonadRandom m => Curve -> m PrivateNumber
    generatePrivate :: forall (m :: * -> *). MonadRandom m => Curve -> m PrivateNumber
    generatePrivate Curve
    curve = PrivateNumber -> m PrivateNumber
    forall (m :: * -> *).
    MonadRandom m =>
    PrivateNumber -> m PrivateNumber
    generateMax PrivateNumber
    n
      where
        n :: PrivateNumber
    n = CurveCommon -> PrivateNumber
    ecc_n (CurveCommon -> PrivateNumber) -> CurveCommon -> PrivateNumber
    forall a b. (a -> b) -> a -> b
    $ Curve -> CurveCommon
    common_curve Curve
    curve

    -- | Generating a public point Q.
    calculatePublic :: Curve -> PrivateNumber -> PublicPoint
    calculatePublic :: Curve -> PrivateNumber -> PublicPoint
    calculatePublic Curve
    curve PrivateNumber
    d = PublicPoint
    q
      where
        g :: PublicPoint
    g = CurveCommon -> PublicPoint
    ecc_g (CurveCommon -> PublicPoint) -> CurveCommon -> PublicPoint
    forall a b. (a -> b) -> a -> b
    $ Curve -> CurveCommon
    common_curve Curve
    curve
        q :: PublicPoint
    q = Curve -> PrivateNumber -> PublicPoint -> PublicPoint
    pointMul Curve
    curve PrivateNumber
    d PublicPoint
    g

    -- | Generating a shared key using our private number and
    --   the other party public point.
    getShared :: Curve -> PrivateNumber -> PublicPoint -> SharedKey
    getShared :: Curve -> PrivateNumber -> PublicPoint -> SharedKey
    getShared Curve
    curve PrivateNumber
    db PublicPoint
    qa = ScrubbedBytes -> SharedKey
    SharedKey (ScrubbedBytes -> SharedKey) -> ScrubbedBytes -> SharedKey
    forall a b. (a -> b) -> a -> b
    $ Int -> PrivateNumber -> ScrubbedBytes
    forall ba. ByteArray ba => Int -> PrivateNumber -> ba
    i2ospOf_ ((Int
    nbBits Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    7) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    8) PrivateNumber
    x
      where
        x :: PrivateNumber
    x = case Curve -> PrivateNumber -> PublicPoint -> PublicPoint
    pointMul Curve
    curve PrivateNumber
    db PublicPoint
    qa of
            Point PrivateNumber
    x' PrivateNumber
    _ -> PrivateNumber
    x'
            PublicPoint
    _ -> [Char] -> PrivateNumber
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "getShared"
        nbBits :: Int
    nbBits = Curve -> Int
    curveSizeBits Curve
    curve