    -- |
    -- Module      : Crypto.PubKey.DSA
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : Good
    --
    -- An implementation of the Digital Signature Algorithm (DSA)

    module Crypto.PubKey.DSA
        ( Params(..)
        , Signature(..)
        , PublicKey(..)
        , PrivateKey(..)
        -- * generation
        , generatePrivate
        , calculatePublic
        -- * signature primitive
        , sign
        , signWith
        -- * verification primitive
        , verify
        ) where

    import Crypto.Random
    import Data.Maybe
    import Data.ByteString (ByteString)
    import Crypto.Number.ModArithmetic (expFast, expSafe, inverse)
    import Crypto.Number.Serialize
    import Crypto.Number.Generate
    import Crypto.Types.PubKey.DSA
    import Crypto.PubKey.HashDescr

    -- | generate a private number with no specific property
    -- this number is usually called X in DSA text.
    generatePrivate :: CPRG g => g -> Params -> (PrivateNumber, g)
    generatePrivate :: g -> Params -> (PrivateNumber, g)
    generatePrivate rng :: g
    rng (Params _ _ q :: PrivateNumber
    q) = g -> PrivateNumber -> (PrivateNumber, g)
    forall g. CPRG g => g -> PrivateNumber -> (PrivateNumber, g)
    generateMax g
    rng PrivateNumber
    q

    -- | Calculate the public number from the parameters and the private key
    calculatePublic :: Params -> PrivateNumber -> PublicNumber
    calculatePublic :: Params -> PrivateNumber -> PrivateNumber
    calculatePublic (Params p :: PrivateNumber
    p g :: PrivateNumber
    g _) x :: PrivateNumber
    x = PrivateNumber -> PrivateNumber -> PrivateNumber -> PrivateNumber
    expSafe PrivateNumber
    g PrivateNumber
    x PrivateNumber
    p

    -- | sign message using the private key and an explicit k number.
    signWith :: Integer         -- ^ k random number
             -> PrivateKey      -- ^ private key
             -> HashFunction    -- ^ hash function
             -> ByteString      -- ^ message to sign
             -> Maybe Signature
    signWith :: PrivateNumber
    -> PrivateKey -> HashFunction -> ByteString -> Maybe Signature
    signWith k :: PrivateNumber
    k pk :: PrivateKey
    pk hash :: HashFunction
    hash msg :: ByteString
    msg
        | PrivateNumber
    r PrivateNumber -> PrivateNumber -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0 Bool -> Bool -> Bool
    || PrivateNumber
    s PrivateNumber -> PrivateNumber -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0  = Maybe Signature
    forall a. Maybe a
    Nothing
        | Bool
    otherwise         = Signature -> Maybe Signature
    forall a. a -> Maybe a
    Just (Signature -> Maybe Signature) -> Signature -> Maybe Signature
    forall a b. (a -> b) -> a -> b
    $ PrivateNumber -> PrivateNumber -> Signature
    Signature PrivateNumber
    r PrivateNumber
    s
        where -- parameters
              (Params p :: PrivateNumber
    p g :: PrivateNumber
    g q :: PrivateNumber
    q) = PrivateKey -> Params
    private_params PrivateKey
    pk
              x :: PrivateNumber
    x         = PrivateKey -> PrivateNumber
    private_x PrivateKey
    pk
              -- compute r,s
              kInv :: PrivateNumber
    kInv      = Maybe PrivateNumber -> PrivateNumber
    forall a. HasCallStack => Maybe a -> a
    fromJust (Maybe PrivateNumber -> PrivateNumber)
    -> Maybe PrivateNumber -> PrivateNumber
    forall a b. (a -> b) -> a -> b
    $ PrivateNumber -> PrivateNumber -> Maybe PrivateNumber
    inverse PrivateNumber
    k PrivateNumber
    q
              hm :: PrivateNumber
    hm        = ByteString -> PrivateNumber
    os2ip (ByteString -> PrivateNumber) -> ByteString -> PrivateNumber
    forall a b. (a -> b) -> a -> b
    $ HashFunction
    hash ByteString
    msg
              r :: PrivateNumber
    r         = PrivateNumber -> PrivateNumber -> PrivateNumber -> PrivateNumber
    expSafe PrivateNumber
    g PrivateNumber
    k PrivateNumber
    p PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Integral a => a -> a -> a
    `mod` PrivateNumber
    q
              s :: PrivateNumber
    s         = (PrivateNumber
    kInv PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Num a => a -> a -> a
    * (PrivateNumber
    hm PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Num a => a -> a -> a
    + PrivateNumber
    x PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Num a => a -> a -> a
    * PrivateNumber
    r)) PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Integral a => a -> a -> a
    `mod` PrivateNumber
    q

    -- | sign message using the private key.
    sign :: CPRG g => g -> PrivateKey -> HashFunction -> ByteString -> (Signature, g)
    sign :: g -> PrivateKey -> HashFunction -> ByteString -> (Signature, g)
    sign rng :: g
    rng pk :: PrivateKey
    pk hash :: HashFunction
    hash msg :: ByteString
    msg =
        case PrivateNumber
    -> PrivateKey -> HashFunction -> ByteString -> Maybe Signature
    signWith PrivateNumber
    k PrivateKey
    pk HashFunction
    hash ByteString
    msg of
            Nothing  -> g -> PrivateKey -> HashFunction -> ByteString -> (Signature, g)
    forall g.
    CPRG g =>
    g -> PrivateKey -> HashFunction -> ByteString -> (Signature, g)
    sign g
    rng' PrivateKey
    pk HashFunction
    hash ByteString
    msg
            Just sig :: Signature
    sig -> (Signature
    sig, g
    rng')
        where (Params _ _ q :: PrivateNumber
    q) = PrivateKey -> Params
    private_params PrivateKey
    pk
              (k :: PrivateNumber
    k, rng' :: g
    rng') = g -> PrivateNumber -> (PrivateNumber, g)
    forall g. CPRG g => g -> PrivateNumber -> (PrivateNumber, g)
    generateMax g
    rng PrivateNumber
    q

    -- | verify a bytestring using the public key.
    verify :: HashFunction -> PublicKey -> Signature -> ByteString -> Bool
    verify :: HashFunction -> PublicKey -> Signature -> ByteString -> Bool
    verify hash :: HashFunction
    hash pk :: PublicKey
    pk (Signature r :: PrivateNumber
    r s :: PrivateNumber
    s) m :: ByteString
    m
        -- Reject the signature if either 0 < r < q or 0 < s < q is not satisfied.
        | PrivateNumber
    r PrivateNumber -> PrivateNumber -> Bool
    forall a. Ord a => a -> a -> Bool
    <= 0 Bool -> Bool -> Bool
    || PrivateNumber
    r PrivateNumber -> PrivateNumber -> Bool
    forall a. Ord a => a -> a -> Bool
    >= PrivateNumber
    q Bool -> Bool -> Bool
    || PrivateNumber
    s PrivateNumber -> PrivateNumber -> Bool
    forall a. Ord a => a -> a -> Bool
    <= 0 Bool -> Bool -> Bool
    || PrivateNumber
    s PrivateNumber -> PrivateNumber -> Bool
    forall a. Ord a => a -> a -> Bool
    >= PrivateNumber
    q = Bool
    False
        | Bool
    otherwise                            = PrivateNumber
    v PrivateNumber -> PrivateNumber -> Bool
    forall a. Eq a => a -> a -> Bool
    == PrivateNumber
    r
        where (Params p :: PrivateNumber
    p g :: PrivateNumber
    g q :: PrivateNumber
    q) = PublicKey -> Params
    public_params PublicKey
    pk
              y :: PrivateNumber
    y       = PublicKey -> PrivateNumber
    public_y PublicKey
    pk
              hm :: PrivateNumber
    hm      = ByteString -> PrivateNumber
    os2ip (ByteString -> PrivateNumber) -> ByteString -> PrivateNumber
    forall a b. (a -> b) -> a -> b
    $ HashFunction
    hash ByteString
    m

              w :: PrivateNumber
    w       = Maybe PrivateNumber -> PrivateNumber
    forall a. HasCallStack => Maybe a -> a
    fromJust (Maybe PrivateNumber -> PrivateNumber)
    -> Maybe PrivateNumber -> PrivateNumber
    forall a b. (a -> b) -> a -> b
    $ PrivateNumber -> PrivateNumber -> Maybe PrivateNumber
    inverse PrivateNumber
    s PrivateNumber
    q
              u1 :: PrivateNumber
    u1      = (PrivateNumber
    hmPrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Num a => a -> a -> a
    *PrivateNumber
    w) PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Integral a => a -> a -> a
    `mod` PrivateNumber
    q
              u2 :: PrivateNumber
    u2      = (PrivateNumber
    rPrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Num a => a -> a -> a
    *PrivateNumber
    w) PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Integral a => a -> a -> a
    `mod` PrivateNumber
    q
              v :: PrivateNumber
    v       = ((PrivateNumber -> PrivateNumber -> PrivateNumber -> PrivateNumber
    expFast PrivateNumber
    g PrivateNumber
    u1 PrivateNumber
    p) PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Num a => a -> a -> a
    * (PrivateNumber -> PrivateNumber -> PrivateNumber -> PrivateNumber
    expFast PrivateNumber
    y PrivateNumber
    u2 PrivateNumber
    p)) PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Integral a => a -> a -> a
    `mod` PrivateNumber
    p PrivateNumber -> PrivateNumber -> PrivateNumber
    forall a. Integral a => a -> a -> a
    `mod` PrivateNumber
    q