    -- |
    -- Module      : Crypto.PubKey.RSA.PKCS15
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : Good
    module Crypto.PubKey.RSA.PKCS15 (
        -- * Padding and unpadding
        pad,
        padSignature,
        unpad,

        -- * Private key operations
        decrypt,
        decryptSafer,
        sign,
        signSafer,

        -- * Public key operations
        encrypt,
        verify,

        -- * Hash ASN1 description
        HashAlgorithmASN1,
    ) where

    import Crypto.Hash
    import Crypto.PubKey.Internal (and')
    import Crypto.PubKey.RSA (generateBlinder)
    import Crypto.PubKey.RSA.Prim
    import Crypto.PubKey.RSA.Types
    import Crypto.Random.Types

    import Data.ByteString (ByteString)
    import Data.Word

    import Crypto.Internal.ByteArray (ByteArray, Bytes)
    import qualified Crypto.Internal.ByteArray as B

    -- | A specialized class for hash algorithm that can product
    -- a ASN1 wrapped description the algorithm plus the content
    -- of the digest.
    class HashAlgorithm hashAlg => HashAlgorithmASN1 hashAlg where
        -- | Convert a Digest into an ASN1 wrapped descriptive ByteArray
        hashDigestASN1 :: ByteArray out => Digest hashAlg -> out

    -- http://uk.emc.com/emc-plus/rsa-labs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf
    -- EMSA-PKCS1-v1_5
    instance HashAlgorithmASN1 MD2 where
        hashDigestASN1 :: forall out. ByteArray out => Digest MD2 -> out
    hashDigestASN1 =
            [Word8] -> Digest MD2 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x20
                , Word8
    0x30
                , Word8
    0x0c
                , Word8
    0x06
                , Word8
    0x08
                , Word8
    0x2a
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x86
                , Word8
    0xf7
                , Word8
    0x0d
                , Word8
    0x02
                , Word8
    0x02
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x10
                ]
    instance HashAlgorithmASN1 MD5 where
        hashDigestASN1 :: forall out. ByteArray out => Digest MD5 -> out
    hashDigestASN1 =
            [Word8] -> Digest MD5 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x20
                , Word8
    0x30
                , Word8
    0x0c
                , Word8
    0x06
                , Word8
    0x08
                , Word8
    0x2a
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x86
                , Word8
    0xf7
                , Word8
    0x0d
                , Word8
    0x02
                , Word8
    0x05
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x10
                ]
    instance HashAlgorithmASN1 SHA1 where
        hashDigestASN1 :: forall out. ByteArray out => Digest SHA1 -> out
    hashDigestASN1 =
            [Word8] -> Digest SHA1 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x21
                , Word8
    0x30
                , Word8
    0x09
                , Word8
    0x06
                , Word8
    0x05
                , Word8
    0x2b
                , Word8
    0x0e
                , Word8
    0x03
                , Word8
    0x02
                , Word8
    0x1a
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x14
                ]
    instance HashAlgorithmASN1 SHA224 where
        hashDigestASN1 :: forall out. ByteArray out => Digest SHA224 -> out
    hashDigestASN1 =
            [Word8] -> Digest SHA224 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x2d
                , Word8
    0x30
                , Word8
    0x0d
                , Word8
    0x06
                , Word8
    0x09
                , Word8
    0x60
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x01
                , Word8
    0x65
                , Word8
    0x03
                , Word8
    0x04
                , Word8
    0x02
                , Word8
    0x04
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x1c
                ]
    instance HashAlgorithmASN1 SHA256 where
        hashDigestASN1 :: forall out. ByteArray out => Digest SHA256 -> out
    hashDigestASN1 =
            [Word8] -> Digest SHA256 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x31
                , Word8
    0x30
                , Word8
    0x0d
                , Word8
    0x06
                , Word8
    0x09
                , Word8
    0x60
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x01
                , Word8
    0x65
                , Word8
    0x03
                , Word8
    0x04
                , Word8
    0x02
                , Word8
    0x01
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x20
                ]
    instance HashAlgorithmASN1 SHA384 where
        hashDigestASN1 :: forall out. ByteArray out => Digest SHA384 -> out
    hashDigestASN1 =
            [Word8] -> Digest SHA384 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x41
                , Word8
    0x30
                , Word8
    0x0d
                , Word8
    0x06
                , Word8
    0x09
                , Word8
    0x60
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x01
                , Word8
    0x65
                , Word8
    0x03
                , Word8
    0x04
                , Word8
    0x02
                , Word8
    0x02
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x30
                ]
    instance HashAlgorithmASN1 SHA512 where
        hashDigestASN1 :: forall out. ByteArray out => Digest SHA512 -> out
    hashDigestASN1 =
            [Word8] -> Digest SHA512 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x51
                , Word8
    0x30
                , Word8
    0x0d
                , Word8
    0x06
                , Word8
    0x09
                , Word8
    0x60
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x01
                , Word8
    0x65
                , Word8
    0x03
                , Word8
    0x04
                , Word8
    0x02
                , Word8
    0x03
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x40
                ]
    instance HashAlgorithmASN1 SHA512t_224 where
        hashDigestASN1 :: forall out. ByteArray out => Digest SHA512t_224 -> out
    hashDigestASN1 =
            [Word8] -> Digest SHA512t_224 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x2d
                , Word8
    0x30
                , Word8
    0x0d
                , Word8
    0x06
                , Word8
    0x09
                , Word8
    0x60
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x01
                , Word8
    0x65
                , Word8
    0x03
                , Word8
    0x04
                , Word8
    0x02
                , Word8
    0x05
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x1c
                ]
    instance HashAlgorithmASN1 SHA512t_256 where
        hashDigestASN1 :: forall out. ByteArray out => Digest SHA512t_256 -> out
    hashDigestASN1 =
            [Word8] -> Digest SHA512t_256 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x31
                , Word8
    0x30
                , Word8
    0x0d
                , Word8
    0x06
                , Word8
    0x09
                , Word8
    0x60
                , Word8
    0x86
                , Word8
    0x48
                , Word8
    0x01
                , Word8
    0x65
                , Word8
    0x03
                , Word8
    0x04
                , Word8
    0x02
                , Word8
    0x06
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x20
                ]
    instance HashAlgorithmASN1 RIPEMD160 where
        hashDigestASN1 :: forall out. ByteArray out => Digest RIPEMD160 -> out
    hashDigestASN1 =
            [Word8] -> Digest RIPEMD160 -> out
    forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix
                [ Word8
    0x30
                , Word8
    0x21
                , Word8
    0x30
                , Word8
    0x09
                , Word8
    0x06
                , Word8
    0x05
                , Word8
    0x2b
                , Word8
    0x24
                , Word8
    0x03
                , Word8
    0x02
                , Word8
    0x01
                , Word8
    0x05
                , Word8
    0x00
                , Word8
    0x04
                , Word8
    0x14
                ]

    --

    -- ** Hack **

    --
    -- this happens to not need a real ASN1 encoder, because
    -- thanks to the digest being a specific size AND
    -- that the digest data is the last bytes in the encoding,
    -- this allows to just prepend the right prefix to the
    -- computed digest, to make it in the expected and valid shape.
    --
    -- Otherwise the expected structure is in the following form:
    --
    --   Start Sequence
    --     ,Start Sequence
    --       ,OID oid
    --       ,Null
    --     ,End Sequence
    --     ,OctetString digest
    --   ,End Sequence
    addDigestPrefix :: ByteArray out => [Word8] -> Digest hashAlg -> out
    addDigestPrefix :: forall out hashAlg.
    ByteArray out =>
    [Word8] -> Digest hashAlg -> out
    addDigestPrefix [Word8]
    prefix Digest hashAlg
    digest =
        [Word8] -> out
    forall a. ByteArray a => [Word8] -> a
    B.pack [Word8]
    prefix out -> out -> out
    forall bs. ByteArray bs => bs -> bs -> bs
    `B.append` Digest hashAlg -> out
    forall bin bout.
    (ByteArrayAccess bin, ByteArray bout) =>
    bin -> bout
    B.convert Digest hashAlg
    digest

    -- | This produce a standard PKCS1.5 padding for encryption
    pad
        :: (MonadRandom m, ByteArray message) => Int -> message -> m (Either Error message)
    pad :: forall (m :: * -> *) message.
    (MonadRandom m, ByteArray message) =>
    Int -> message -> m (Either Error message)
    pad Int
    len message
    m
        | message -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length message
    m Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    11 = Either Error message -> m (Either Error message)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Error -> Either Error message
    forall a b. a -> Either a b
    Left Error
    MessageTooLong)
        | Bool
    otherwise = do
            padding <- Int -> m message
    forall bytearray (m :: * -> *).
    (ByteArray bytearray, MonadRandom m) =>
    Int -> m bytearray
    getNonNullRandom (Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - message -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length message
    m Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    3)
            return $ Right $ B.concat [B.pack [0, 2], padding, B.pack [0], m]
      where
        -- get random non-null bytes
        getNonNullRandom :: (ByteArray bytearray, MonadRandom m) => Int -> m bytearray
        getNonNullRandom :: forall bytearray (m :: * -> *).
    (ByteArray bytearray, MonadRandom m) =>
    Int -> m bytearray
    getNonNullRandom Int
    n = do
            bs0 <- Int -> m Bytes
    forall byteArray. ByteArray byteArray => Int -> m byteArray
    forall (m :: * -> *) byteArray.
    (MonadRandom m, ByteArray byteArray) =>
    Int -> m byteArray
    getRandomBytes Int
    n
            let bytes = [Word8] -> bytearray
    forall a. ByteArray a => [Word8] -> a
    B.pack ([Word8] -> bytearray) -> [Word8] -> bytearray
    forall a b. (a -> b) -> a -> b
    $ (Word8 -> Bool) -> [Word8] -> [Word8]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word8
    0) ([Word8] -> [Word8]) -> [Word8] -> [Word8]
    forall a b. (a -> b) -> a -> b
    $ Bytes -> [Word8]
    forall a. ByteArrayAccess a => a -> [Word8]
    B.unpack (Bytes
    bs0 :: Bytes)
                left = Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - bytearray -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length bytearray
    bytes
            if left == 0
                then return bytes
                else do
                    bend <- getNonNullRandom left
                    return (bytes `B.append` bend)

    -- | Produce a standard PKCS1.5 padding for signature
    padSignature
        :: ByteArray signature => Int -> signature -> Either Error signature
    padSignature :: forall signature.
    ByteArray signature =>
    Int -> signature -> Either Error signature
    padSignature Int
    klen signature
    signature
        | Int
    klen Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    siglen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    11 = Error -> Either Error signature
    forall a b. a -> Either a b
    Left Error
    SignatureTooLong
        | Bool
    otherwise = signature -> Either Error signature
    forall a b. b -> Either a b
    Right ([Word8] -> signature
    forall a. ByteArray a => [Word8] -> a
    B.pack [Word8]
    padding signature -> signature -> signature
    forall bs. ByteArray bs => bs -> bs -> bs
    `B.append` signature
    signature)
      where
        siglen :: Int
    siglen = signature -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length signature
    signature
        padding :: [Word8]
    padding = Word8
    0 Word8 -> [Word8] -> [Word8]
    forall a. a -> [a] -> [a]
    : Word8
    1 Word8 -> [Word8] -> [Word8]
    forall a. a -> [a] -> [a]
    : (Int -> Word8 -> [Word8]
    forall a. Int -> a -> [a]
    replicate (Int
    klen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    siglen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    3) Word8
    0xff [Word8] -> [Word8] -> [Word8]
    forall a. [a] -> [a] -> [a]
    ++ [Word8
    0])

    -- | Try to remove a standard PKCS1.5 encryption padding.
    unpad :: ByteArray bytearray => bytearray -> Either Error bytearray
    unpad :: forall bytearray.
    ByteArray bytearray =>
    bytearray -> Either Error bytearray
    unpad bytearray
    packed
        | Bool
    paddingSuccess = bytearray -> Either Error bytearray
    forall a b. b -> Either a b
    Right bytearray
    m
        | Bool
    otherwise = Error -> Either Error bytearray
    forall a b. a -> Either a b
    Left Error
    MessageNotRecognized
      where
        (bytearray
    zt, bytearray
    ps0m) = Int -> bytearray -> (bytearray, bytearray)
    forall bs. ByteArray bs => Int -> bs -> (bs, bs)
    B.splitAt Int
    2 bytearray
    packed
        (bytearray
    ps, bytearray
    zm) = (Word8 -> Bool) -> bytearray -> (bytearray, bytearray)
    forall bs. ByteArray bs => (Word8 -> Bool) -> bs -> (bs, bs)
    B.span (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word8
    0) bytearray
    ps0m
        (bytearray
    z, bytearray
    m) = Int -> bytearray -> (bytearray, bytearray)
    forall bs. ByteArray bs => Int -> bs -> (bs, bs)
    B.splitAt Int
    1 bytearray
    zm
        paddingSuccess :: Bool
    paddingSuccess =
            [Bool] -> Bool
    and'
                [ bytearray
    zt bytearray -> Bytes -> Bool
    forall bs1 bs2.
    (ByteArrayAccess bs1, ByteArrayAccess bs2) =>
    bs1 -> bs2 -> Bool
    `B.constEq` ([Word8] -> Bytes
    forall a. ByteArray a => [Word8] -> a
    B.pack [Word8
    0, Word8
    2] :: Bytes)
                , bytearray
    z bytearray -> bytearray -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int -> bytearray
    forall ba. ByteArray ba => Int -> ba
    B.zero Int
    1
                , bytearray -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length bytearray
    ps Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    8
                ]

    -- | decrypt message using the private key.
    --
    -- When the decryption is not in a context where an attacker could gain
    -- information from the timing of the operation, the blinder can be set to None.
    --
    -- If unsure always set a blinder or use decryptSafer
    --
    -- The message is returned un-padded.
    decrypt
        :: Maybe Blinder
        -- ^ optional blinder
        -> PrivateKey
        -- ^ RSA private key
        -> ByteString
        -- ^ cipher text
        -> Either Error ByteString
    decrypt :: Maybe Blinder
    -> PrivateKey -> ByteString -> Either Error ByteString
    decrypt Maybe Blinder
    blinder PrivateKey
    pk ByteString
    c
        | ByteString -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length ByteString
    c Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= (PrivateKey -> Int
    private_size PrivateKey
    pk) = Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    MessageSizeIncorrect
        | Bool
    otherwise = ByteString -> Either Error ByteString
    forall bytearray.
    ByteArray bytearray =>
    bytearray -> Either Error bytearray
    unpad (ByteString -> Either Error ByteString)
    -> ByteString -> Either Error ByteString
    forall a b. (a -> b) -> a -> b
    $ Maybe Blinder -> PrivateKey -> ByteString -> ByteString
    forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
    dp Maybe Blinder
    blinder PrivateKey
    pk ByteString
    c

    -- | decrypt message using the private key and by automatically generating a blinder.
    decryptSafer
        :: MonadRandom m
        => PrivateKey
        -- ^ RSA private key
        -> ByteString
        -- ^ cipher text
        -> m (Either Error ByteString)
    decryptSafer :: forall (m :: * -> *).
    MonadRandom m =>
    PrivateKey -> ByteString -> m (Either Error ByteString)
    decryptSafer PrivateKey
    pk ByteString
    b = do
        blinder <- Integer -> m Blinder
    forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
    generateBlinder (PrivateKey -> Integer
    private_n PrivateKey
    pk)
        return (decrypt (Just blinder) pk b)

    -- | encrypt a bytestring using the public key.
    --
    -- The message needs to be smaller than the key size - 11.
    -- The message should not be padded.
    encrypt
        :: MonadRandom m => PublicKey -> ByteString -> m (Either Error ByteString)
    encrypt :: forall (m :: * -> *).
    MonadRandom m =>
    PublicKey -> ByteString -> m (Either Error ByteString)
    encrypt PublicKey
    pk ByteString
    m = do
        r <- Int -> ByteString -> m (Either Error ByteString)
    forall (m :: * -> *) message.
    (MonadRandom m, ByteArray message) =>
    Int -> message -> m (Either Error message)
    pad (PublicKey -> Int
    public_size PublicKey
    pk) ByteString
    m
        case r of
            Left Error
    err -> Either Error ByteString -> m (Either Error ByteString)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Either Error ByteString -> m (Either Error ByteString))
    -> Either Error ByteString -> m (Either Error ByteString)
    forall a b. (a -> b) -> a -> b
    $ Error -> Either Error ByteString
    forall a b. a -> Either a b
    Left Error
    err
            Right ByteString
    em -> Either Error ByteString -> m (Either Error ByteString)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Either Error ByteString -> m (Either Error ByteString))
    -> Either Error ByteString -> m (Either Error ByteString)
    forall a b. (a -> b) -> a -> b
    $ ByteString -> Either Error ByteString
    forall a b. b -> Either a b
    Right (PublicKey -> ByteString -> ByteString
    forall ba. ByteArray ba => PublicKey -> ba -> ba
    ep PublicKey
    pk ByteString
    em)

    -- | sign message using private key, a hash and its ASN1 description
    --
    -- When the signature is not in a context where an attacker could gain
    -- information from the timing of the operation, the blinder can be set to None.
    --
    -- If unsure always set a blinder or use signSafer
    sign
        :: HashAlgorithmASN1 hashAlg
        => Maybe Blinder
        -- ^ optional blinder
        -> Maybe hashAlg
        -- ^ hash algorithm
        -> PrivateKey
        -- ^ private key
        -> ByteString
        -- ^ message to sign
        -> Either Error ByteString
    sign :: forall hashAlg.
    HashAlgorithmASN1 hashAlg =>
    Maybe Blinder
    -> Maybe hashAlg
    -> PrivateKey
    -> ByteString
    -> Either Error ByteString
    sign Maybe Blinder
    blinder Maybe hashAlg
    hashDescr PrivateKey
    pk ByteString
    m = Maybe Blinder -> PrivateKey -> ByteString -> ByteString
    forall ba. ByteArray ba => Maybe Blinder -> PrivateKey -> ba -> ba
    dp Maybe Blinder
    blinder PrivateKey
    pk (ByteString -> ByteString)
    -> Either Error ByteString -> Either Error ByteString
    forall a b. (a -> b) -> Either Error a -> Either Error b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
    forall hashAlg.
    HashAlgorithmASN1 hashAlg =>
    Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
    makeSignature Maybe hashAlg
    hashDescr (PrivateKey -> Int
    private_size PrivateKey
    pk) ByteString
    m

    -- | sign message using the private key and by automatically generating a blinder.
    signSafer
        :: (HashAlgorithmASN1 hashAlg, MonadRandom m)
        => Maybe hashAlg
        -- ^ Hash algorithm
        -> PrivateKey
        -- ^ private key
        -> ByteString
        -- ^ message to sign
        -> m (Either Error ByteString)
    signSafer :: forall hashAlg (m :: * -> *).
    (HashAlgorithmASN1 hashAlg, MonadRandom m) =>
    Maybe hashAlg
    -> PrivateKey -> ByteString -> m (Either Error ByteString)
    signSafer Maybe hashAlg
    hashAlg PrivateKey
    pk ByteString
    m = do
        blinder <- Integer -> m Blinder
    forall (m :: * -> *). MonadRandom m => Integer -> m Blinder
    generateBlinder (PrivateKey -> Integer
    private_n PrivateKey
    pk)
        return (sign (Just blinder) hashAlg pk m)

    -- | verify message with the signed message
    verify
        :: HashAlgorithmASN1 hashAlg
        => Maybe hashAlg
        -> PublicKey
        -> ByteString
        -> ByteString
        -> Bool
    verify :: forall hashAlg.
    HashAlgorithmASN1 hashAlg =>
    Maybe hashAlg -> PublicKey -> ByteString -> ByteString -> Bool
    verify Maybe hashAlg
    hashAlg PublicKey
    pk ByteString
    m ByteString
    sm =
        case Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
    forall hashAlg.
    HashAlgorithmASN1 hashAlg =>
    Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
    makeSignature Maybe hashAlg
    hashAlg (PublicKey -> Int
    public_size PublicKey
    pk) ByteString
    m of
            Left Error
    _ -> Bool
    False
            Right ByteString
    s -> ByteString
    s ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == (PublicKey -> ByteString -> ByteString
    forall ba. ByteArray ba => PublicKey -> ba -> ba
    ep PublicKey
    pk ByteString
    sm)

    -- | make signature digest, used in 'sign' and 'verify'
    makeSignature
        :: HashAlgorithmASN1 hashAlg
        => Maybe hashAlg
        -- ^ optional hashing algorithm
        -> Int
        -> ByteString
        -> Either Error ByteString
    makeSignature :: forall hashAlg.
    HashAlgorithmASN1 hashAlg =>
    Maybe hashAlg -> Int -> ByteString -> Either Error ByteString
    makeSignature Maybe hashAlg
    Nothing Int
    klen ByteString
    m = Int -> ByteString -> Either Error ByteString
    forall signature.
    ByteArray signature =>
    Int -> signature -> Either Error signature
    padSignature Int
    klen ByteString
    m
    makeSignature (Just hashAlg
    hashAlg) Int
    klen ByteString
    m = Int -> ByteString -> Either Error ByteString
    forall signature.
    ByteArray signature =>
    Int -> signature -> Either Error signature
    padSignature Int
    klen (Digest hashAlg -> ByteString
    forall out. ByteArray out => Digest hashAlg -> out
    forall hashAlg out.
    (HashAlgorithmASN1 hashAlg, ByteArray out) =>
    Digest hashAlg -> out
    hashDigestASN1 (Digest hashAlg -> ByteString) -> Digest hashAlg -> ByteString
    forall a b. (a -> b) -> a -> b
    $ hashAlg -> ByteString -> Digest hashAlg
    forall ba alg.
    (ByteArrayAccess ba, HashAlgorithm alg) =>
    alg -> ba -> Digest alg
    hashWith hashAlg
    hashAlg ByteString
    m)