    {-# LANGUAGE GeneralizedNewtypeDeriving #-}

    -- |
    -- Module      : Crypto.PubKey.DH
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : Good
    --
    module Crypto.PubKey.DH
        ( Params(..)
        , PublicNumber
        , PrivateNumber
        , SharedKey
        , generateParams
        , generatePrivate
        , calculatePublic
        , generatePublic
        , getShared
        ) where

    import Crypto.Number.ModArithmetic (expSafe)
    import Crypto.Number.Prime (generateSafePrime)
    import Crypto.Number.Generate (generateMax)
    import Crypto.Types.PubKey.DH
    import Crypto.Random
    import Control.Arrow (first)

    -- | generate params from a specific generator (2 or 5 are common values)
    -- we generate a safe prime (a prime number of the form 2p+1 where p is also prime)
    generateParams :: CPRG g => g -> Int -> Integer -> (Params, g)
    generateParams :: g -> Int -> Integer -> (Params, g)
    generateParams rng :: g
    rng bits :: Int
    bits generator :: Integer
    generator =
        (Integer -> Params) -> (Integer, g) -> (Params, g)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (b, d) (c, d)
    first (\p :: Integer
    p -> Integer -> Integer -> Params
    Params Integer
    p Integer
    generator) ((Integer, g) -> (Params, g)) -> (Integer, g) -> (Params, g)
    forall a b. (a -> b) -> a -> b
    $ g -> Int -> (Integer, g)
    forall g. CPRG g => g -> Int -> (Integer, g)
    generateSafePrime g
    rng Int
    bits

    -- | generate a private number with no specific property
    -- this number is usually called X in DH text.
    generatePrivate :: CPRG g => g -> Params -> (PrivateNumber, g)
    generatePrivate :: g -> Params -> (PrivateNumber, g)
    generatePrivate rng :: g
    rng (Params p :: Integer
    p _) = (Integer -> PrivateNumber) -> (Integer, g) -> (PrivateNumber, g)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (b, d) (c, d)
    first Integer -> PrivateNumber
    PrivateNumber ((Integer, g) -> (PrivateNumber, g))
    -> (Integer, g) -> (PrivateNumber, g)
    forall a b. (a -> b) -> a -> b
    $ g -> Integer -> (Integer, g)
    forall g. CPRG g => g -> Integer -> (Integer, g)
    generateMax g
    rng Integer
    p

    -- | calculate the public number from the parameters and the private key
    -- this number is usually called Y in DH text.
    calculatePublic :: Params -> PrivateNumber -> PublicNumber
    calculatePublic :: Params -> PrivateNumber -> PublicNumber
    calculatePublic (Params p :: Integer
    p g :: Integer
    g) (PrivateNumber x :: Integer
    x) = Integer -> PublicNumber
    PublicNumber (Integer -> PublicNumber) -> Integer -> PublicNumber
    forall a b. (a -> b) -> a -> b
    $ Integer -> Integer -> Integer -> Integer
    expSafe Integer
    g Integer
    x Integer
    p

    -- | calculate the public number from the parameters and the private key
    -- this number is usually called Y in DH text.
    --
    -- DEPRECATED use calculatePublic
    generatePublic :: Params -> PrivateNumber -> PublicNumber
    generatePublic :: Params -> PrivateNumber -> PublicNumber
    generatePublic = Params -> PrivateNumber -> PublicNumber
    calculatePublic
    -- commented until 0.3 {-# DEPRECATED generatePublic "use calculatePublic" #-}

    -- | generate a shared key using our private number and the other party public number
    getShared :: Params -> PrivateNumber -> PublicNumber -> SharedKey
    getShared :: Params -> PrivateNumber -> PublicNumber -> SharedKey
    getShared (Params p :: Integer
    p _) (PrivateNumber x :: Integer
    x) (PublicNumber y :: Integer
    y) = Integer -> SharedKey
    SharedKey (Integer -> SharedKey) -> Integer -> SharedKey
    forall a b. (a -> b) -> a -> b
    $ Integer -> Integer -> Integer -> Integer
    expSafe Integer
    y Integer
    x Integer
    p