    -- |
    -- Module      : Crypto.PubKey.Rabin.Types
    -- License     : BSD-style
    -- Maintainer  : Carlos Rodriguez-Vega <crodveg@yahoo.es>
    -- Stability   : experimental
    -- Portability : unknown
    --
    module Crypto.PubKey.Rabin.Types
        ( Error(..)
        , generatePrimes
        ) where

    import Crypto.Number.Basic (numBits)
    import Crypto.Number.Prime (generatePrime, findPrimeFromWith)
    import Crypto.Random.Types

    type PrimeCondition = Integer -> Bool

    -- | Error possible during encryption, decryption or signing.
    data Error = MessageTooLong       -- ^ the message to encrypt is too long
               | MessageNotRecognized -- ^ the message decrypted doesn't have a OAEP structure
               | InvalidParameters    -- ^ some parameters lead to breaking assumptions
               deriving (Int -> Error -> ShowS
    [Error] -> ShowS
    Error -> String
    (Int -> Error -> ShowS)
    -> (Error -> String) -> ([Error] -> ShowS) -> Show Error
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Error] -> ShowS
    $cshowList :: [Error] -> ShowS
    show :: Error -> String
    $cshow :: Error -> String
    showsPrec :: Int -> Error -> ShowS
    $cshowsPrec :: Int -> Error -> ShowS
    Show, Error -> Error -> Bool
    (Error -> Error -> Bool) -> (Error -> Error -> Bool) -> Eq Error
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Error -> Error -> Bool
    $c/= :: Error -> Error -> Bool
    == :: Error -> Error -> Bool
    $c== :: Error -> Error -> Bool
    Eq)

    -- | Generate primes p & q
    generatePrimes :: MonadRandom m
                   => Int                   -- ^ size in bytes
                   -> PrimeCondition        -- ^ condition prime p must satisfy
                   -> PrimeCondition        -- ^ condition prime q must satisfy
                   -> m (Integer, Integer)  -- ^ chosen distinct primes p and q
    generatePrimes :: Int -> PrimeCondition -> PrimeCondition -> m (Integer, Integer)
    generatePrimes size :: Int
    size pCond :: PrimeCondition
    pCond qCond :: PrimeCondition
    qCond =
        let pBits :: Int
    pBits = (8Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *(Int
    size Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` 2))
            qBits :: Int
    qBits = (8Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *(Int
    size Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - (Int
    size Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` 2)))
         in do
            Integer
    p <- Int -> PrimeCondition -> m Integer
    forall (m :: * -> *).
    MonadRandom m =>
    Int -> PrimeCondition -> m Integer
    generatePrime' Int
    pBits PrimeCondition
    pCond
            Integer
    q <- Int -> PrimeCondition -> m Integer
    forall (m :: * -> *).
    MonadRandom m =>
    Int -> PrimeCondition -> m Integer
    generatePrime' Int
    qBits PrimeCondition
    qCond
            (Integer, Integer) -> m (Integer, Integer)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Integer
    p, Integer
    q)
          where
            generatePrime' :: Int -> PrimeCondition -> m Integer
    generatePrime' bits :: Int
    bits cond :: PrimeCondition
    cond = do
                Integer
    pr' <- Int -> m Integer
    forall (m :: * -> *). MonadRandom m => Int -> m Integer
    generatePrime Int
    bits
                let pr :: Integer
    pr = PrimeCondition -> Integer -> Integer
    findPrimeFromWith PrimeCondition
    cond Integer
    pr'
                if Integer -> Int
    numBits Integer
    pr Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    bits then Integer -> m Integer
    forall (m :: * -> *) a. Monad m => a -> m a
    return Integer
    pr
                else Int -> PrimeCondition -> m Integer
    generatePrime' Int
    bits PrimeCondition
    cond