    -- |
    -- Module      : Crypto.PubKey.Curve25519
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : unknown
    --
    -- Curve25519 support
    --
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE MagicHash #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    module Crypto.PubKey.Curve25519
        ( SecretKey
        , PublicKey
        , DhSecret
        -- * Smart constructors
        , dhSecret
        , publicKey
        , secretKey
        -- * Methods
        , dh
        , toPublic
        , generateSecretKey
        ) where

    import           Data.Bits
    import           Data.Word
    import           Foreign.Ptr
    import           Foreign.Storable
    import           GHC.Ptr

    import           Crypto.Error
    import           Crypto.Internal.Compat
    import           Crypto.Internal.Imports
    import           Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray)
    import qualified Crypto.Internal.ByteArray as B
    import           Crypto.Random

    -- | A Curve25519 Secret key
    newtype SecretKey = SecretKey ScrubbedBytes
        deriving (Int -> SecretKey -> ShowS
    [SecretKey] -> ShowS
    SecretKey -> String
    (Int -> SecretKey -> ShowS)
    -> (SecretKey -> String)
    -> ([SecretKey] -> ShowS)
    -> Show SecretKey
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> SecretKey -> ShowS
    showsPrec :: Int -> SecretKey -> ShowS
    $cshow :: SecretKey -> String
    show :: SecretKey -> String
    $cshowList :: [SecretKey] -> ShowS
    showList :: [SecretKey] -> ShowS
    Show,SecretKey -> SecretKey -> Bool
    (SecretKey -> SecretKey -> Bool)
    -> (SecretKey -> SecretKey -> Bool) -> Eq SecretKey
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: SecretKey -> SecretKey -> Bool
    == :: SecretKey -> SecretKey -> Bool
    $c/= :: SecretKey -> SecretKey -> Bool
    /= :: SecretKey -> SecretKey -> Bool
    Eq,SecretKey -> Int
    (SecretKey -> Int)
    -> (forall p a. SecretKey -> (Ptr p -> IO a) -> IO a)
    -> (forall p. SecretKey -> Ptr p -> IO ())
    -> ByteArrayAccess SecretKey
    forall p. SecretKey -> Ptr p -> IO ()
    forall ba.
    (ba -> Int)
    -> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
    -> (forall p. ba -> Ptr p -> IO ())
    -> ByteArrayAccess ba
    forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
    $clength :: SecretKey -> Int
    length :: SecretKey -> Int
    $cwithByteArray :: forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
    withByteArray :: forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
    $ccopyByteArrayToPtr :: forall p. SecretKey -> Ptr p -> IO ()
    copyByteArrayToPtr :: forall p. SecretKey -> Ptr p -> IO ()
    ByteArrayAccess,SecretKey -> ()
    (SecretKey -> ()) -> NFData SecretKey
    forall a. (a -> ()) -> NFData a
    $crnf :: SecretKey -> ()
    rnf :: SecretKey -> ()
    NFData)

    -- | A Curve25519 public key
    newtype PublicKey = PublicKey Bytes
        deriving (Int -> PublicKey -> ShowS
    [PublicKey] -> ShowS
    PublicKey -> String
    (Int -> PublicKey -> ShowS)
    -> (PublicKey -> String)
    -> ([PublicKey] -> ShowS)
    -> Show PublicKey
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> PublicKey -> ShowS
    showsPrec :: Int -> PublicKey -> ShowS
    $cshow :: PublicKey -> String
    show :: PublicKey -> String
    $cshowList :: [PublicKey] -> ShowS
    showList :: [PublicKey] -> ShowS
    Show,PublicKey -> PublicKey -> Bool
    (PublicKey -> PublicKey -> Bool)
    -> (PublicKey -> PublicKey -> Bool) -> Eq PublicKey
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: PublicKey -> PublicKey -> Bool
    == :: PublicKey -> PublicKey -> Bool
    $c/= :: PublicKey -> PublicKey -> Bool
    /= :: PublicKey -> PublicKey -> Bool
    Eq,PublicKey -> Int
    (PublicKey -> Int)
    -> (forall p a. PublicKey -> (Ptr p -> IO a) -> IO a)
    -> (forall p. PublicKey -> Ptr p -> IO ())
    -> ByteArrayAccess PublicKey
    forall p. PublicKey -> Ptr p -> IO ()
    forall ba.
    (ba -> Int)
    -> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
    -> (forall p. ba -> Ptr p -> IO ())
    -> ByteArrayAccess ba
    forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
    $clength :: PublicKey -> Int
    length :: PublicKey -> Int
    $cwithByteArray :: forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
    withByteArray :: forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
    $ccopyByteArrayToPtr :: forall p. PublicKey -> Ptr p -> IO ()
    copyByteArrayToPtr :: forall p. PublicKey -> Ptr p -> IO ()
    ByteArrayAccess,PublicKey -> ()
    (PublicKey -> ()) -> NFData PublicKey
    forall a. (a -> ()) -> NFData a
    $crnf :: PublicKey -> ()
    rnf :: PublicKey -> ()
    NFData)

    -- | A Curve25519 Diffie Hellman secret related to a
    -- public key and a secret key.
    newtype DhSecret = DhSecret ScrubbedBytes
        deriving (Int -> DhSecret -> ShowS
    [DhSecret] -> ShowS
    DhSecret -> String
    (Int -> DhSecret -> ShowS)
    -> (DhSecret -> String) -> ([DhSecret] -> ShowS) -> Show DhSecret
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> DhSecret -> ShowS
    showsPrec :: Int -> DhSecret -> ShowS
    $cshow :: DhSecret -> String
    show :: DhSecret -> String
    $cshowList :: [DhSecret] -> ShowS
    showList :: [DhSecret] -> ShowS
    Show,DhSecret -> DhSecret -> Bool
    (DhSecret -> DhSecret -> Bool)
    -> (DhSecret -> DhSecret -> Bool) -> Eq DhSecret
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DhSecret -> DhSecret -> Bool
    == :: DhSecret -> DhSecret -> Bool
    $c/= :: DhSecret -> DhSecret -> Bool
    /= :: DhSecret -> DhSecret -> Bool
    Eq,DhSecret -> Int
    (DhSecret -> Int)
    -> (forall p a. DhSecret -> (Ptr p -> IO a) -> IO a)
    -> (forall p. DhSecret -> Ptr p -> IO ())
    -> ByteArrayAccess DhSecret
    forall p. DhSecret -> Ptr p -> IO ()
    forall ba.
    (ba -> Int)
    -> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
    -> (forall p. ba -> Ptr p -> IO ())
    -> ByteArrayAccess ba
    forall p a. DhSecret -> (Ptr p -> IO a) -> IO a
    $clength :: DhSecret -> Int
    length :: DhSecret -> Int
    $cwithByteArray :: forall p a. DhSecret -> (Ptr p -> IO a) -> IO a
    withByteArray :: forall p a. DhSecret -> (Ptr p -> IO a) -> IO a
    $ccopyByteArrayToPtr :: forall p. DhSecret -> Ptr p -> IO ()
    copyByteArrayToPtr :: forall p. DhSecret -> Ptr p -> IO ()
    ByteArrayAccess,DhSecret -> ()
    (DhSecret -> ()) -> NFData DhSecret
    forall a. (a -> ()) -> NFData a
    $crnf :: DhSecret -> ()
    rnf :: DhSecret -> ()
    NFData)

    -- | Try to build a public key from a bytearray
    publicKey :: ByteArrayAccess bs => bs -> CryptoFailable PublicKey
    publicKey :: forall bs. ByteArrayAccess bs => bs -> CryptoFailable PublicKey
    publicKey bs
    bs
        | bs -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length bs
    bs Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    32 = PublicKey -> CryptoFailable PublicKey
    forall a. a -> CryptoFailable a
    CryptoPassed (PublicKey -> CryptoFailable PublicKey)
    -> PublicKey -> CryptoFailable PublicKey
    forall a b. (a -> b) -> a -> b
    $ Bytes -> PublicKey
    PublicKey (Bytes -> PublicKey) -> Bytes -> PublicKey
    forall a b. (a -> b) -> a -> b
    $ bs -> (Ptr Any -> IO ()) -> Bytes
    forall bs1 bs2 p.
    (ByteArrayAccess bs1, ByteArray bs2) =>
    bs1 -> (Ptr p -> IO ()) -> bs2
    B.copyAndFreeze bs
    bs (\Ptr Any
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ())
        | Bool
    otherwise         = CryptoError -> CryptoFailable PublicKey
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_PublicKeySizeInvalid

    -- | Try to build a secret key from a bytearray
    secretKey :: ByteArrayAccess bs => bs -> CryptoFailable SecretKey
    secretKey :: forall bs. ByteArrayAccess bs => bs -> CryptoFailable SecretKey
    secretKey bs
    bs
        | bs -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length bs
    bs Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    32 = IO (CryptoFailable SecretKey) -> CryptoFailable SecretKey
    forall a. IO a -> a
    unsafeDoIO (IO (CryptoFailable SecretKey) -> CryptoFailable SecretKey)
    -> IO (CryptoFailable SecretKey) -> CryptoFailable SecretKey
    forall a b. (a -> b) -> a -> b
    $ do
            bs
    -> (Ptr Word8 -> IO (CryptoFailable SecretKey))
    -> IO (CryptoFailable SecretKey)
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. bs -> (Ptr p -> IO a) -> IO a
    withByteArray bs
    bs ((Ptr Word8 -> IO (CryptoFailable SecretKey))
     -> IO (CryptoFailable SecretKey))
    -> (Ptr Word8 -> IO (CryptoFailable SecretKey))
    -> IO (CryptoFailable SecretKey)
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    inp -> do
                Bool
    valid <- Ptr Word8 -> IO Bool
    isValidPtr Ptr Word8
    inp
                if Bool
    valid
                    then (SecretKey -> CryptoFailable SecretKey
    forall a. a -> CryptoFailable a
    CryptoPassed (SecretKey -> CryptoFailable SecretKey)
    -> (ScrubbedBytes -> SecretKey)
    -> ScrubbedBytes
    -> CryptoFailable SecretKey
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ScrubbedBytes -> SecretKey
    SecretKey) (ScrubbedBytes -> CryptoFailable SecretKey)
    -> IO ScrubbedBytes -> IO (CryptoFailable SecretKey)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> bs -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
    forall bs1 bs2 p.
    (ByteArrayAccess bs1, ByteArray bs2) =>
    bs1 -> (Ptr p -> IO ()) -> IO bs2
    B.copy bs
    bs (\Ptr Any
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ())
                    else CryptoFailable SecretKey -> IO (CryptoFailable SecretKey)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (CryptoFailable SecretKey -> IO (CryptoFailable SecretKey))
    -> CryptoFailable SecretKey -> IO (CryptoFailable SecretKey)
    forall a b. (a -> b) -> a -> b
    $ CryptoError -> CryptoFailable SecretKey
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_SecretKeyStructureInvalid
        | Bool
    otherwise = CryptoError -> CryptoFailable SecretKey
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_SecretKeySizeInvalid
      where
            --  e[0] &= 0xf8;
            --  e[31] &= 0x7f;
            --  e[31] |= 40;
            isValidPtr :: Ptr Word8 -> IO Bool
            isValidPtr :: Ptr Word8 -> IO Bool
    isValidPtr Ptr Word8
    _ = do
                --b0  <- peekElemOff inp 0
                --b31 <- peekElemOff inp 31
                Bool -> IO Bool
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True
    {-
                return $ and [ testBit b0  0 == False
                             , testBit b0  1 == False
                             , testBit b0  2 == False
                             , testBit b31 7 == False
                             , testBit b31 6 == True
                             ]
    -}
    {-# NOINLINE secretKey #-}

    -- | Create a DhSecret from a bytearray object
    dhSecret :: ByteArrayAccess b => b -> CryptoFailable DhSecret
    dhSecret :: forall b. ByteArrayAccess b => b -> CryptoFailable DhSecret
    dhSecret b
    bs
        | b -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length b
    bs Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    32 = DhSecret -> CryptoFailable DhSecret
    forall a. a -> CryptoFailable a
    CryptoPassed (DhSecret -> CryptoFailable DhSecret)
    -> DhSecret -> CryptoFailable DhSecret
    forall a b. (a -> b) -> a -> b
    $ ScrubbedBytes -> DhSecret
    DhSecret (ScrubbedBytes -> DhSecret) -> ScrubbedBytes -> DhSecret
    forall a b. (a -> b) -> a -> b
    $ b -> (Ptr Any -> IO ()) -> ScrubbedBytes
    forall bs1 bs2 p.
    (ByteArrayAccess bs1, ByteArray bs2) =>
    bs1 -> (Ptr p -> IO ()) -> bs2
    B.copyAndFreeze b
    bs (\Ptr Any
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ())
        | Bool
    otherwise         = CryptoError -> CryptoFailable DhSecret
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_SharedSecretSizeInvalid

    -- | Compute the Diffie Hellman secret from a public key and a secret key.
    --
    -- This implementation may return an all-zero value as it does not check for
    -- the condition.
    dh :: PublicKey -> SecretKey -> DhSecret
    dh :: PublicKey -> SecretKey -> DhSecret
    dh (PublicKey Bytes
    pub) (SecretKey ScrubbedBytes
    sec) = ScrubbedBytes -> DhSecret
    DhSecret (ScrubbedBytes -> DhSecret)
    -> ((Ptr Word8 -> IO ()) -> ScrubbedBytes)
    -> (Ptr Word8 -> IO ())
    -> DhSecret
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
        Int -> (Ptr Word8 -> IO ()) -> ScrubbedBytes
    forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
    B.allocAndFreeze Int
    32        ((Ptr Word8 -> IO ()) -> DhSecret)
    -> (Ptr Word8 -> IO ()) -> DhSecret
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    result ->
        ScrubbedBytes -> (Ptr Word8 -> IO ()) -> IO ()
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
    withByteArray ScrubbedBytes
    sec          ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    psec   ->
        Bytes -> (Ptr Word8 -> IO ()) -> IO ()
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. Bytes -> (Ptr p -> IO a) -> IO a
    withByteArray Bytes
    pub          ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    ppub   ->
            Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO ()
    ccrypton_curve25519 Ptr Word8
    result Ptr Word8
    psec Ptr Word8
    ppub
    {-# NOINLINE dh #-}

    -- | Create a public key from a secret key
    toPublic :: SecretKey -> PublicKey
    toPublic :: SecretKey -> PublicKey
    toPublic (SecretKey ScrubbedBytes
    sec) = Bytes -> PublicKey
    PublicKey (Bytes -> PublicKey)
    -> ((Ptr Word8 -> IO ()) -> Bytes)
    -> (Ptr Word8 -> IO ())
    -> PublicKey
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>
        Int -> (Ptr Word8 -> IO ()) -> Bytes
    forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
    B.allocAndFreeze Int
    32     ((Ptr Word8 -> IO ()) -> PublicKey)
    -> (Ptr Word8 -> IO ()) -> PublicKey
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    result ->
        ScrubbedBytes -> (Ptr Word8 -> IO ()) -> IO ()
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
    withByteArray ScrubbedBytes
    sec       ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    psec   ->
            Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO ()
    ccrypton_curve25519 Ptr Word8
    result Ptr Word8
    psec Ptr Word8
    forall {a}. Ptr a
    basePoint
      where
            basePoint :: Ptr a
    basePoint = Addr# -> Ptr a
    forall a. Addr# -> Ptr a
    Ptr Addr#
    "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
    {-# NOINLINE toPublic #-}

    -- | Generate a secret key.
    generateSecretKey :: MonadRandom m => m SecretKey
    generateSecretKey :: forall (m :: * -> *). MonadRandom m => m SecretKey
    generateSecretKey = ScrubbedBytes -> SecretKey
    tweakToSecretKey (ScrubbedBytes -> SecretKey) -> m ScrubbedBytes -> m SecretKey
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Int -> m ScrubbedBytes
    forall byteArray. ByteArray byteArray => Int -> m byteArray
    forall (m :: * -> *) byteArray.
    (MonadRandom m, ByteArray byteArray) =>
    Int -> m byteArray
    getRandomBytes Int
    32
      where
        tweakToSecretKey :: ScrubbedBytes -> SecretKey
        tweakToSecretKey :: ScrubbedBytes -> SecretKey
    tweakToSecretKey ScrubbedBytes
    bin = ScrubbedBytes -> SecretKey
    SecretKey (ScrubbedBytes -> SecretKey) -> ScrubbedBytes -> SecretKey
    forall a b. (a -> b) -> a -> b
    $ ScrubbedBytes -> (Ptr Word8 -> IO ()) -> ScrubbedBytes
    forall bs1 bs2 p.
    (ByteArrayAccess bs1, ByteArray bs2) =>
    bs1 -> (Ptr p -> IO ()) -> bs2
    B.copyAndFreeze ScrubbedBytes
    bin ((Ptr Word8 -> IO ()) -> ScrubbedBytes)
    -> (Ptr Word8 -> IO ()) -> ScrubbedBytes
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    inp -> do
            Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
    modifyByte Ptr Word8
    inp Int
    0 (\Word8
    e0 -> Word8
    e0 Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .&. Word8
    0xf8)
            Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
    modifyByte Ptr Word8
    inp Int
    31 (\Word8
    e31 -> (Word8
    e31 Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .&. Word8
    0x7f) Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .|. Word8
    0x40)

        modifyByte :: Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
        modifyByte :: Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
    modifyByte Ptr Word8
    p Int
    n Word8 -> Word8
    f = Ptr Word8 -> Int -> IO Word8
    forall b. Ptr b -> Int -> IO Word8
    forall a b. Storable a => Ptr b -> Int -> IO a
    peekByteOff Ptr Word8
    p Int
    n IO Word8 -> (Word8 -> IO ()) -> IO ()
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Ptr Word8 -> Int -> Word8 -> IO ()
    forall b. Ptr b -> Int -> Word8 -> IO ()
    forall a b. Storable a => Ptr b -> Int -> a -> IO ()
    pokeByteOff Ptr Word8
    p Int
    n (Word8 -> IO ()) -> (Word8 -> Word8) -> Word8 -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word8 -> Word8
    f

    foreign import ccall "crypton_curve25519_donna"
        ccrypton_curve25519 :: Ptr Word8 -- ^ public
                               -> Ptr Word8 -- ^ secret
                               -> Ptr Word8 -- ^ basepoint
                               -> IO ()