{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.PubKey.DH
( Params(..)
, PublicNumber(..)
, PrivateNumber(..)
, SharedKey(..)
, generateParams
, generatePrivate
, calculatePublic
, generatePublic
, getShared
) where
import Crypto.Internal.Imports
import Crypto.Number.ModArithmetic (expSafe)
import Crypto.Number.Prime (generateSafePrime)
import Crypto.Number.Generate (generateMax)
import Crypto.Number.Serialize (i2ospOf_)
import Crypto.Random.Types
import Data.ByteArray (ByteArrayAccess, ScrubbedBytes)
import Data.Data
data Params = Params
{ params_p :: Integer
, params_g :: Integer
, params_bits :: Int
} deriving (Show,Read,Eq,Data)
instance NFData Params where
rnf (Params p g bits) = rnf p `seq` rnf g `seq` bits `seq` ()
newtype PublicNumber = PublicNumber Integer
deriving (Show,Read,Eq,Enum,Real,Num,Ord,NFData)
newtype PrivateNumber = PrivateNumber Integer
deriving (Show,Read,Eq,Enum,Real,Num,Ord,NFData)
newtype SharedKey = SharedKey ScrubbedBytes
deriving (Show,Eq,ByteArrayAccess,NFData)
generateParams :: MonadRandom m =>
Int
-> Integer
-> m Params
generateParams bits generator =
(\p -> Params p generator bits) <$> generateSafePrime bits
generatePrivate :: MonadRandom m => Params -> m PrivateNumber
generatePrivate (Params p _ _) = PrivateNumber <$> generateMax p
calculatePublic :: Params -> PrivateNumber -> PublicNumber
calculatePublic (Params p g _) (PrivateNumber x) = PublicNumber $ expSafe g x p
generatePublic :: Params -> PrivateNumber -> PublicNumber
generatePublic = calculatePublic
getShared :: Params -> PrivateNumber -> PublicNumber -> SharedKey
getShared (Params p _ bits) (PrivateNumber x) (PublicNumber y) = SharedKey $ i2ospOf_ ((bits + 7) `div` 8) $ expSafe y x p