{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}

#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveGeneric #-}
#endif

-- |
-- Module      : Crypto.Sign.Ed25519
-- Copyright   : (c) Austin Seipp 2013-2015
-- License     : MIT
--
-- Maintainer  : aseipp@pobox.com
-- Stability   : experimental
-- Portability : portable
--
-- This module provides bindings to the Ed25519 public-key signature
-- system, including detached signatures. The documentation should be
-- self explanatory with complete examples.
--
-- Below the basic documentation you'll find API, performance and
-- security notes, which you may want to read carefully before
-- continuing. (Nonetheless, @Ed25519@ is one of the easiest-to-use
-- signature systems around, and is simple to get started with for
-- building more complex protocols. But the below details are highly
-- educational and should help adjust your expectations properly.)
--
-- For more reading on the underlying implementation and theory
-- (including how to get a copy of the Ed25519 software),
-- visit <http://ed25519.cr.yp.to>. There are two papers that discuss
-- the design of EdDSA/Ed25519 in detail:
--
--   * <http://ed25519.cr.yp.to/ed25519-20110926.pdf "High-speed high-security signatures"> -
--   The original specification by Bernstein, Duif, Lange, Schwabe,
--   and Yang.
--
--   * <http://ed25519.cr.yp.to/eddsa-20150704.pdf "EdDSA for more curves"> -
--   An extension of the original EdDSA specification allowing it to
--   be used with more curves (such as Ed41417, or Ed488), as well as
--   defining the support for __message prehashing__. The original
--   EdDSA is easily derived from the extended version through a few
--   parameter defaults. (This package won't consider non-Ed25519
--   EdDSA systems any further.)
--
module Crypto.Sign.Ed25519
       ( -- * A crash course introduction
         -- $intro

         -- * Keypair creation
         -- $creatingkeys
         PublicKey(..)          -- :: *
       , SecretKey(..)          -- :: *
       , createKeypair          -- :: IO (PublicKey, SecretKey)
       , createKeypairFromSeed_ -- :: ByteString -> Maybe (PublicKey, SecretKey)
       , createKeypairFromSeed  -- :: ByteString -> (PublicKey, SecretKey)
       , toPublicKey            -- :: SecretKey -> PublicKey

         -- * Signing and verifying messages
         -- $signatures
       , sign                 -- :: SecretKey -> ByteString -> ByteString
       , verify               -- :: PublicKey -> ByteString -> Bool

         -- * Detached signatures
         -- $detachedsigs
       , Signature(..)        -- :: *
       , dsign                -- :: SecretKey -> ByteString -> Signature
       , dverify              -- :: PublicKey -> ByteString -> Signature -> Bool
         -- ** Deprecated interface
         -- | The below interface is deprecated but functionally
         -- equivalent to the above; it simply has \"worse\" naming and will
         -- eventually be removed.
       , sign'                -- :: SecretKey -> ByteString -> Signature
       , verify'              -- :: PublicKey -> ByteString -> Signature -> Bool

         -- * Security, design and implementation notes
         -- $security

         -- ** EdDSA background and properties
         -- $background

         -- *** Generation of psuedo-random seeds
         -- $seedgen

         -- ** Performance and implementation
         -- $performance

         -- ** Secure @'SecretKey'@ storage
         -- $keystorage

         -- ** Prehashing and large input messages
         -- $prehashing
       ) where
import           Foreign.C.Types
import           Foreign.ForeignPtr       (withForeignPtr)
import           Foreign.Marshal.Alloc    (alloca)
import           Foreign.Ptr
import           Foreign.Storable

import           System.IO.Unsafe         (unsafePerformIO)

import           Data.Maybe               (fromMaybe)

import           Data.ByteString          as S
import           Data.ByteString.Internal as SI
import           Data.ByteString.Unsafe   as SU
import           Data.Word

#if __GLASGOW_HASKELL__ >= 702
import           GHC.Generics             (Generic)
#endif

-- Doctest setup with some examples

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Data.ByteString.Char8
-- >>> let hash        x = x
-- >>> let readBigFile x = return x

--------------------------------------------------------------------------------
-- Key creation

-- $creatingkeys
--
-- Ed25519 signatures start off life by having a keypair created,
-- using @'createKeypair'@ or @'createKeypairFromSeed_'@, which gives
-- you back a @'SecretKey'@ you can use for signing messages, and a
-- @'PublicKey'@ your users can use to verify you in fact authored the
-- messages.
--
-- Ed25519 is a /deterministic signature system/, meaning that you may
-- always recompute a @'PublicKey'@ and a @'SecretKey'@ from an
-- initial, 32-byte input seed. Despite that, the default interface
-- almost all clients will wish to use is simply @'createKeypair'@,
-- which uses an Operating System provided source of secure randomness
-- to seed key creation. (For more information, see the security notes
-- at the bottom of this page.)

-- | A @'PublicKey'@ created by @'createKeypair'@.
--
-- @since 0.0.1.0
newtype PublicKey = PublicKey { unPublicKey :: ByteString
                                -- ^ Unwrapper for getting the raw
                                -- @'ByteString'@ in a
                                -- @'PublicKey'@. In general you
                                -- should not make any assumptions
                                -- about the underlying blob; this is
                                -- only provided for interoperability.
                              }
        deriving (Eq, Show, Ord)

-- | A @'SecretKey'@ created by @'createKeypair'@. __Be sure to keep this__
-- __safe!__
--
-- @since 0.0.1.0
newtype SecretKey = SecretKey { unSecretKey :: ByteString
                                -- ^ Unwrapper for getting the raw
                                -- @'ByteString'@ in a
                                -- @'SecretKey'@. In general you
                                -- should not make any assumptions
                                -- about the underlying blob; this is
                                -- only provided for interoperability.
                              }
        deriving (Eq, Show, Ord)

#if __GLASGOW_HASKELL__ >= 702
deriving instance Generic PublicKey
deriving instance Generic SecretKey
#endif

-- | Randomly generate a @'SecretKey'@ and @'PublicKey'@ for doing
-- authenticated signing and verification. This essentically calls
-- @'createKeypairFromSeed_'@ with a randomly generated 32-byte seed,
-- the source of which is operating-system dependent (see security
-- notes below). However, internally it is implemented more
-- efficiently (with less allocations and copies).
--
-- If you wish to use your own seed (for design purposes so you may
-- recreate keys, due to high paranoia, or because you have your own
-- source of randomness), please use @'createKeypairFromSeed_'@
-- instead.
--
-- @since 0.0.1.0
createKeypair :: IO (PublicKey, SecretKey)
createKeypair = do
  pk <- SI.mallocByteString cryptoSignPUBLICKEYBYTES
  sk <- SI.mallocByteString cryptoSignSECRETKEYBYTES

  _ <- withForeignPtr pk $ \ppk -> do
    _ <- withForeignPtr sk $ \psk -> do
      _ <- c_crypto_sign_keypair ppk psk
      return ()
    return ()

  return (PublicKey $ SI.fromForeignPtr pk 0 cryptoSignPUBLICKEYBYTES,
          SecretKey $ SI.fromForeignPtr sk 0 cryptoSignSECRETKEYBYTES)

-- | Generate a deterministic @'PublicKey'@ and @'SecretKey'@ from a
-- given 32-byte seed, allowing you to recreate a keypair at any point
-- in time, providing you have the seed available.
--
-- If the input seed is not 32 bytes in length,
-- @'createKeypairFromSeed_'@ returns @'Nothing'@. Otherwise, it
-- always returns @'Just' (pk, sk)@ for the given seed.
--
-- __/NOTE/__: This function will replace @'createKeypairFromSeed'@ in
-- the future.
--
-- @since 0.0.4.0
createKeypairFromSeed_ :: ByteString                  -- ^ 32-byte seed
                      -> Maybe (PublicKey, SecretKey) -- ^ Resulting keypair
createKeypairFromSeed_ seed
  | S.length seed /= cryptoSignSEEDBYTES = Nothing
  | otherwise = unsafePerformIO $ do
    pk <- SI.mallocByteString cryptoSignPUBLICKEYBYTES
    sk <- SI.mallocByteString cryptoSignSECRETKEYBYTES

    _ <- SU.unsafeUseAsCString seed $ \pseed -> do
      _ <- withForeignPtr pk $ \ppk -> do
        _ <- withForeignPtr sk $ \psk -> do
          _ <- c_crypto_sign_seed_keypair ppk psk pseed
          return ()
        return ()
      return ()

    return $ Just (PublicKey $ SI.fromForeignPtr pk 0 cryptoSignPUBLICKEYBYTES,
                   SecretKey $ SI.fromForeignPtr sk 0 cryptoSignSECRETKEYBYTES)

-- | Generate a deterministic @'PublicKey'@ and @'SecretKey'@ from a
-- given 32-byte seed, allowing you to recreate a keypair at any point
-- in time, providing you have the seed available.
--
-- Note that this will @'error'@ if the given input is not 32 bytes in
-- length, so you must be careful with this input.
--
-- @since 0.0.3.0
createKeypairFromSeed :: ByteString             -- ^ 32-byte seed
                      -> (PublicKey, SecretKey) -- ^ Resulting keypair
createKeypairFromSeed seed
  = fromMaybe (error "seed has incorrect length") (createKeypairFromSeed_ seed)
{-# DEPRECATED createKeypairFromSeed "This function is unsafe as it can @'fail'@ with an invalid input. Use @'createKeypairWithSeed_'@ instead." #-}

-- | Derive the @'PublicKey'@ for a given @'SecretKey'@. This is a
-- convenience which allows (for example) using @'createKeypair'@ and
-- only ever storing the returned @'SecretKey'@ for any future
-- operations.
--
-- @since 0.0.3.0
toPublicKey :: SecretKey -- ^ Any valid @'SecretKey'@
            -> PublicKey -- ^ Corresponding @'PublicKey'@
toPublicKey = PublicKey . S.drop prefixBytes  . unSecretKey
  where prefixBytes = cryptoSignSECRETKEYBYTES - cryptoSignPUBLICKEYBYTES

--------------------------------------------------------------------------------
-- Default, non-detached API

-- $signatures
--
-- By default, the Ed25519 interface computes a /signed message/ given
-- a @'SecretKey'@ and an input message. A /signed message/ consists
-- of an Ed25519 signature (of unspecified format), followed by the
-- input message.  This means that given an input message of @M@
-- bytes, you get back a message of @M+N@ bytes where @N@ is a
-- constant (the size of the Ed25519 signature blob).
--
-- The default interface in this package reflects that. As a result,
-- any time you use @'sign'@ or @'verify'@ you will be given back the
-- full input, and then some.
--

-- | Sign a message with a particular @'SecretKey'@. Note that the resulting
-- signed message contains both the message itself, and the signature
-- attached. If you only want the signature of a given input string,
-- please see @'dsign'@.
--
-- @since 0.0.1.0
sign :: SecretKey
     -- ^ Signers @'SecretKey'@
     -> ByteString
     -- ^ Input message
     -> ByteString
     -- ^ Resulting signed message
sign (SecretKey sk) xs =
  unsafePerformIO . SU.unsafeUseAsCStringLen xs $ \(mstr,mlen) ->
    SU.unsafeUseAsCString sk $ \psk ->
      SI.createAndTrim (mlen+cryptoSignBYTES) $ \out ->
        alloca $ \smlen -> do
          _ <- c_crypto_sign out smlen mstr (fromIntegral mlen) psk
          fromIntegral `fmap` peek smlen
{-# INLINE sign #-}

-- | Verifies a signed message against a @'PublicKey'@. Note that the input
-- message must be generated by @'sign'@ (that is, it is the message
-- itself plus its signature). If you want to verify an arbitrary
-- signature against an arbitrary message, please see @'dverify'@.
--
-- @since 0.0.1.0
verify :: PublicKey
       -- ^ Signers @'PublicKey'@
       -> ByteString
       -- ^ Signed message
       -> Bool
       -- ^ Verification result
verify (PublicKey pk) xs =
  unsafePerformIO . SU.unsafeUseAsCStringLen xs $ \(smstr,smlen) ->
    SU.unsafeUseAsCString pk $ \ppk ->
      alloca $ \pmlen -> do
        out <- SI.mallocByteString smlen
        r <- withForeignPtr out $ \pout ->
               c_crypto_sign_open pout pmlen smstr (fromIntegral smlen) ppk

        return (r == 0)
{-# INLINE verify #-}

--------------------------------------------------------------------------------
-- Detached signature support

-- $detachedsigs
--
-- This package also provides an alternative interface for /detached/
-- /signatures/, which is more in-line with what you might
-- traditionally expect from a signing API. In this mode, the
-- @'dsign'@ and @'dverify'@ interfaces simply return a constant-sized
-- blob, representing the Ed25519 signature of the input message.
--
-- This allows users to independently download, verify or attach
-- signatures to messages in any way they see fit - for example, by
-- providing a tarball file to download, with a corresponding @.sig@
-- file containing the Ed25519 signature from the author.

-- | A @'Signature'@ which is detached from the message it signed.
--
-- @since 0.0.1.0
newtype Signature = Signature { unSignature :: ByteString
                                -- ^ Unwrapper for getting the raw
                                -- @'ByteString'@ in a
                                -- @'Signature'@. In general you
                                -- should not make any assumptions
                                -- about the underlying blob; this is
                                -- only provided for interoperability.
                              }
        deriving (Eq, Show, Ord)

#if __GLASGOW_HASKELL__ >= 702
deriving instance Generic Signature
#endif

-- | Sign a message with a particular @'SecretKey'@, only returning the
-- @'Signature'@ without the message.
--
-- @since 0.0.4.0
dsign :: SecretKey
      -- ^ Signers @'SecretKey'@
      -> ByteString
      -- ^ Input message
      -> Signature
      -- ^ Message @'Signature'@, without the message
dsign sk xs =
  let sm = sign sk xs
      l  = S.length sm
  in Signature $! S.take (l - S.length xs) sm
{-# INLINE dsign #-}

-- | Verify a message with a detached @'Signature'@ against a given
-- @'PublicKey'@.
--
-- @since 0.0.4.0
dverify :: PublicKey
        -- ^ Signers @'PublicKey'@
        -> ByteString
        -- ^ Raw input message
        -> Signature
        -- ^ Message @'Signature'@
        -> Bool
        -- ^ Verification result
dverify pk xs (Signature sig) = verify pk (sig `S.append` xs)
{-# INLINE dverify #-}

-- | Sign a message with a particular @'SecretKey'@, only returning the
-- @'Signature'@ without the message. Simply an alias for @'dsign'@.
--
-- @since 0.0.1.0
sign' :: SecretKey
      -- ^ Signers @'SecretKey'@
      -> ByteString
      -- ^ Input message
      -> Signature
      -- ^ Message @'Signature'@, without the message
sign' sk xs = dsign sk xs
{-# DEPRECATED sign' "@'sign''@ will be removed in a future release; use @'dsign'@ instead." #-}

-- | Verify a message with a detached @'Signature'@ against a given
-- @'PublicKey'@. Simply an alias for @'dverify'@.
--
-- @since 0.0.1.0
verify' :: PublicKey
        -- ^ Signers @'PublicKey'@
        -> ByteString
        -- ^ Raw input message
        -> Signature
        -- ^ Message @'Signature'@
        -> Bool
        -- ^ Verification result
verify' pk xs sig = dverify pk xs sig
{-# DEPRECATED verify' "@'verify''@ will be removed in a future release; use @'dverify'@ instead." #-}

--------------------------------------------------------------------------------
-- FFI binding

cryptoSignSECRETKEYBYTES :: Int
cryptoSignSECRETKEYBYTES = 64

cryptoSignPUBLICKEYBYTES :: Int
cryptoSignPUBLICKEYBYTES = 32

cryptoSignBYTES :: Int
cryptoSignBYTES = 64

cryptoSignSEEDBYTES :: Int
cryptoSignSEEDBYTES = 32

foreign import ccall unsafe "ed25519_sign_seed_keypair"
  c_crypto_sign_seed_keypair :: Ptr Word8 -> Ptr Word8
                             -> Ptr CChar -> IO CInt

foreign import ccall unsafe "ed25519_sign_keypair"
  c_crypto_sign_keypair :: Ptr Word8 -> Ptr Word8 -> IO CInt

foreign import ccall unsafe "ed25519_sign"
  c_crypto_sign :: Ptr Word8 -> Ptr CULLong ->
                   Ptr CChar -> CULLong -> Ptr CChar -> IO CULLong

foreign import ccall unsafe "ed25519_sign_open"
  c_crypto_sign_open :: Ptr Word8 -> Ptr CULLong ->
                        Ptr CChar -> CULLong -> Ptr CChar -> IO CInt

--------------------------------------------------------------------------------
-- Documentation and notes

-- $intro
--
-- The simplest use of this library is one where you probably need to
-- sign short messages, so they can be verified independently. That's
-- easily done by first creating a keypair with @'createKeypair'@, and
-- using @'sign'@ to create a signed message. Then, you can distribute
-- your public key and the signed message, and any recipient can
-- verify that message:
--
-- >>> (pk, sk) <- createKeypair
-- >>> let msg = sign sk "Hello world"
-- >>> verify pk msg
-- True
--
-- This interface is fine if your messages are small and simple binary
-- blobs you want to verify in an opaque manner, but internally it
-- creates a copy of the input message. Often, you'll want the
-- signature independently of the message, and that can be done with
-- @'dsign'@ and @'dverify'@. Naturally, verification fails if the
-- message is incorrect:
--
-- >>> (pk, sk) <- createKeypair
-- >>> let msg = "Hello world" :: ByteString
-- >>> let sig = dsign sk msg
-- >>> dverify pk msg sig
-- True
-- >>> dverify pk "Hello world" sig
-- True
-- >>> dverify pk "Goodbye world" sig
-- False
--
-- Finally, it's worth keeping in mind this package doesn't expose any
-- kind of incremental interface, and signing/verification can be
-- expensive. So, if you're dealing with __large inputs__, you can
-- hash the input with a robust, fast cryptographic hash, and then
-- sign that (for example, the @hash@ function below could be
-- __SHA-512__ or __BLAKE2b__):
--
-- >>> (pk, sk) <- createKeypair
-- >>> msg <- readBigFile "blob.tar.gz" :: IO ByteString
-- >>> let sig = dsign sk (hash msg)
-- >>> dverify pk (hash msg) sig
-- True
--
-- See the notes at the bottom of this module for more on message
-- prehashing (as it acts slightly differently in an EdDSA system).

-- $security
--
-- Included below are some notes on the security aspects of the
-- Ed25519 signature system, its implementation and design, this
-- package, and suggestions for how you might use it properly.



-- $background
--
-- Ed25519 is a specific instantiation of the __EdDSA__ digital
-- signature scheme - a high performance, secure-by-design variant of
-- Schnorr signatures based on "Twisted Edwards Curves" (hence the
-- name __Ed__DSA). The (__extended__) EdDSA system is defined by an
-- elliptic curve:
--
-- > ax^2 + y^2 = 1 + d*x^2*y^2
--
-- along with several other parameters, chosen by the implementation
-- in question. These parameters include @a@, @d@, and a field @GF(p)@
-- where @p@ is prime. Ed25519 specifically uses @d = -121665/121666@,
-- @a = -1@, and the finite field @GF((2^155)-19)@, where @(2^155)-19@
-- is a prime number (which is also the namesake of the algorithm in
-- question, as Ed__25519__). This yields the equation:
--
-- > -x^2 + y^2 = 1 - (121665/121666)*x^2*y^2
--
-- This curve is \'birationally equivalent\' to the well-known
-- Montgomery curve \'Curve25519\', which means that EdDSA shares the
-- same the difficult problem as Curve25519: that of the Elliptic
-- Curve Discrete Logarithm Problem (ECDLP). Ed25519 is currently
-- still the recommended EdDSA curve for most deployments.
--
-- As Ed25519 is an elliptic curve algorithm, the security level
-- (i.e. number of computations taken to find a solution to the ECDLP
-- with the fastest known attacks) is roughly half the key size in
-- bits, as it stands. As Ed25519 features 32-byte keys, the security
-- level of Ed25519 is thus @2^((32*8)/2) = 2^128@, far beyond any
-- attacker capability (modulo major breakthroughs for the ECDLP,
-- which would likely catastrophically be applicable to other systems
-- too).
--
-- Ed25519 designed to meet the standard notion of unforgeability for
-- a public-key signature scheme under chosen-message attacks. This
-- means that even should the attacker be able to request someone sign
-- any arbitrary message of their choice (hence /chosen-message/),
-- they are still not capable of any forgery what-so-ever, even the
-- weakest kind of \'existential forgery\'.


-- $seedgen
--
-- Seed generation as done by @'createKeypair'@ uses Operating System
-- provided APIs for generating cryptographically secure psuedo-random
-- data to be used as an Ed25519 key seed. Your own deterministic keys
-- may be generated using @'createKeypairFromSeed_'@, provided you have
-- your own cryptographically secure psuedo-random data from
-- somewhere.
--
-- On __Linux__, __OS X__ and __other Unix__ machines, the
-- @\/dev\/urandom@ device is consulted internally in order to generate
-- random data. In the current implementation, a global file
-- descriptor is used through the lifetime of the program to
-- periodically get psuedo-random data.
--
-- On __Windows__, the @CryptGenRandom@ API is used internally. This
-- does not require file handles of any kind, and should work on all
-- versions of Windows. (Windows may instead use @RtlGenRandom@ in the
-- future for even less overhead.)
--
-- In the future, there are plans for this package to internally take
-- advantage of better APIs when they are available; for example, on
-- Linux 3.17 and above, @getrandom(2)@ provides psuedo-random data
-- directly through the internal pool provided by @\/dev\/urandom@,
-- without a file descriptor. Similarly, OpenBSD provides the
-- @arc4random(3)@ family of functions, which internally uses a data
-- generator based on ChaCha20. These should offer somewhat better
-- efficiency, and also avoid file-descriptor exhaustion attacks which
-- could lead to denial of service in some scenarios.



-- $performance
--
-- Ed25519 is exceptionally fast, although the implementation provided
-- by this package is not the fastest possible implementation. Indeed,
-- it is rather slow, even by non-handwritten-assembly standards of
-- speed. That said, it should still be competitive with most other
-- signature schemes: the underlying implementation is @ref10@ from
-- <http://bench.cr.yp.to/ SUPERCOP>, authored by Daniel J. Bernstein,
-- which is within the
-- <http://bench.cr.yp.to/impl-sign/ed25519.html realm of competition>
-- against some assembly implementations (only 2x slower), and much
-- faster than the slow reference implementation (25x slower). When up
-- <http://bench.cr.yp.to/web-impl/amd64-skylake-crypto_sign.html against RSA>
-- signatures (ronald3072) on a modern Intel machine, it is still __15x__
-- faster at signing messages /at the same 128-bit security level/.
--
-- On the author's Sandy Bridge i5-2520M 2.50GHz CPU, the benchmarking
-- code included with the library reports the following numbers for
-- the Haskell interface:
--
-- @
-- benchmarking deterministic key generation
-- time                 250.0 μs   (249.8 μs .. 250.3 μs)
--                      1.000 R²   (1.000 R² .. 1.000 R²)
-- mean                 250.0 μs   (249.9 μs .. 250.2 μs)
-- std dev              467.0 ns   (331.7 ns .. 627.9 ns)
--
-- benchmarking signing a 256 byte message
-- time                 273.2 μs   (273.0 μs .. 273.4 μs)
--                      1.000 R²   (1.000 R² .. 1.000 R²)
-- mean                 273.3 μs   (273.1 μs .. 273.5 μs)
-- std dev              616.2 ns   (374.1 ns .. 998.8 ns)
--
-- benchmarking verifying a signature
-- time                 635.7 μs   (634.6 μs .. 637.3 μs)
--                      1.000 R²   (1.000 R² .. 1.000 R²)
-- mean                 635.4 μs   (635.0 μs .. 636.0 μs)
-- std dev              1.687 μs   (999.3 ns .. 2.487 μs)
--
-- benchmarking roundtrip 256-byte sign/verify
-- time                 923.6 μs   (910.0 μs .. 950.6 μs)
--                      0.998 R²   (0.996 R² .. 1.000 R²)
-- mean                 913.2 μs   (910.6 μs .. 923.0 μs)
-- std dev              15.93 μs   (1.820 μs .. 33.72 μs)
-- @
--
-- In the future, this package will hopefully provide an opt-in (or
-- possibly default) implementation of
-- <https://github.com/floodyberry/ed25519-donna ed25519-donna>, which
-- should dramatically increase speed at no cost for many/all
-- platforms.



-- $keystorage
--
-- By default, keys are not encrypted in any meaningful manner with
-- any mechanism, and this package does not provide any means of doing
-- so. As a result, your secret keys are only as secure as the
-- computing environment housing them - a server alone out on the
-- hostile internet, or a USB stick that's susceptable to theft.
--
-- If you wish to add some security to your keys, a very simple and
-- effective way is __to add a password to your @'SecretKey'@ with a__
-- __KDF and a hash__. How does this work?
--
--   * First, hash the secret key you have generated. Use this as a
--   __checksum__ of the original key. Truncating this hash to save
--   space is acceptable; see below for more details and boring
--   hemming and hawing.
--
--   * Given an input password, use a KDF to stretch it to the length
--   of a @'SecretKey'@.
--
--   * XOR the @'SecretKey'@ bytewise, directly with the output of
--   your chosen KDF.
--
--   * Attach the checksum you generated to the resulting encrypted
--   key, and store it as you like.
--
-- In this mode, your key is XOR'd with the psuedo-random result of a
-- KDF, which will stretch simple passwords like "I am the robot" into
-- a suitable amount of psuedo-random data for a given secret key to
-- be encrypted with. Decryption is simply the act of taking the
-- password, generating the psuedo-random stream again, XORing the key
-- bytewise, and validating the checksum. In this sense, you are
-- simply using a KDF as a short stream cipher.
--
-- __Recommendation__: Encrypt keys by stretching a password with
-- __scrypt__ (or __yescrypt__), using better-than-default parameters.
-- (These being @N = 2^14@, @r = 8@, @p = 1@; the default results in
-- 16mb of memory per invocation, and this is the recommended default
-- for 'interactive systems'; signing keys may be loaded on-startup
-- for some things however, so it may be profitable to increase
-- security as well as memory use in these cases. For example, at @N =
-- 2^18@, @r = 10@ and @p = 2@, you'll get 320mb of memory per use,
-- which may be acceptable for dramatic security increases. See
-- elsewhere for exact memory use.) Checksums may be computed with an
-- exceptionally fast hash such as __BLAKE2b__.
--
-- __Bonus points__: Print that resulting checksum + key out on a
-- piece of paper (~100 bytes, tops), and put /that/ somewhere safe.
--
-- __Q__: What is the hash needed for? __A__: A simple file integrity
-- check. Rather than invoke complicated methods of verifying if an
-- ed25519 keypair is valid (as it is simply an opaque binary blob,
-- for all intents and purposes), especially after 'streaming
-- decryption', it's far easier to simply compute and compare against
-- a checksum of the original to determine if decryption with your
-- password worked.
--
-- __Q__: Wait, why is it OK to truncate the hash here? That sounds
-- scary. Won't that open up collisions or something like that if they
-- stole my encrypted key?  __A__: No. The hash in this case is only
-- used as a checksum to see if the password is legitimate after
-- running the KDF and XORing with the result. Think about how the
-- \'challenge\' itself is chosen: if you know @H(m)@, do you want to
-- find @m@ itself, or simply find @m'@ where @H(m') = H(m)@?  To
-- forge a signature, you want the original key, @m@. Suppose given an
-- input of 256-bits, we hashed it and truncated to one bit. Finding
-- collisions would be easy: you would only need to try a few times to
-- find a collision or preimage. But you probably found @m'@ such that
-- @H(m') = H(m)@ - you didn't necessarily find @m@ itself. In this
-- sense, finding collisions or preimages of the hash is not useful to
-- the attacker, because you must find the unique @m@.
--
-- __Q__: Okay, why use hashes at all? Why not CRC32? __A__: You could
-- do that, it wouldn't change much. You can really use any kind of
-- error detecting code you want. The thing is, some hashes such as
-- __BLAKE2__ are very fast in things like software (not every CPU has
-- CRC instructions, not all software uses CRC instructions), and
-- you're likely to already have a fast, modern hash function sitting
-- around anyway if you're signing stuff with Ed25519. Why not use it?



-- $prehashing
--
-- __Message prehashing__ (although not an official term in any right)
-- is the idea of first taking an input @x@, using a
-- __cryptographically secure__ hash function @H@ to calculate @y =
-- H(x)@, and then generating a signature via @Sign(secretKey,
-- y)@. The idea is that signing is often expensive, while hashing is
-- often extremely fast. As a result, signing the hash of a message
-- (which should be indistinguishable from a truly random function) is
-- often faster than simply signing the full message alone, and in
-- larger cases can save a significant amount of CPU cycles. However,
-- internally Ed25519 uses a hash function @H@ already to hash the
-- input message for computing the signature. Thus, there is a
-- question - is it appropriate or desireable to hash the input
-- already if this is the case?
--
-- Generally speaking, it's OK to prehash messages before giving them
-- to Ed25519. However, there is a caveat. In the paper
-- <http://ed25519.cr.yp.to/eddsa-20150704.pdf "EdDSA for more curves">,
-- the authors of the original EdDSA enhance the specification by
-- extending it with a message prehash function, @H'@, along with an
-- internal hash @H@. Here, the prehash @H'@ is simply applied to the
-- original message first before anything else. The original EdDSA
-- specification (and the implementation in /this package/) was a
-- trivial case of this enhancement: it was implicit that @H'@ is
-- simply the identity function. We call the case where @H'@ is the
-- identity function __PureEdDSA__, while the case where @H'@ is a
-- cryptographic hash function is known as __HashEdDSA__. (Thus, the
-- interfaces @'sign'@ and @'dsign'@ implement PureEdDSA - while they can
-- be converted to HashEdDSA by simply hashing the @'ByteString'@
-- first with some other function.)
--
-- However, the authors note that HashEdDSA suffers from a weakness
-- that PureEdDSA does not - PureEdDSA is resiliant to collision
-- attacks in the underlying hash function @H@, while HashEdDSA is
-- vulnerable to collisions in @H'@. This is an important
-- distinction. Assume that the attacker finds a collision such that
-- @H'(x) = H'(y)@, and then gets convinces a signer to HashEdDSA-sign
-- @x@ - the attacker may then forge this signature and use it as the
-- same signature as for the message @y@. For a hash function of
-- @N@-bits of output, a collision attack takes roughly @2^(N/2)@
-- operations.
--
-- Ed25519 internally sets @H = SHA-512@ anyway, which has no known
-- collision attacks or weaknesses in any meaningful sense. It is
-- however slower compared to other, more modern hash functions, and
-- is used on the input message in its entirety (and there are no
-- plans to switch the internal implementation of this package, or the
-- standard Ed25519 away from @H = SHA-512@).
--
-- But note: /all other hash-then-sign constructions suffer from/
-- /this/, in the sense they are all vulnerable to collision attacks
-- in @H'@, should you prehash the message. In fact, PureEdDSA is
-- unique (as far as I am aware) in that it is immune to collision
-- attacks in @H@ - should a collision be found, it would not suffer
-- from these forgeries. By this view, it's arguable that /depending/
-- on the HashEdDSA construction (for efficiency or size purposes)
-- when using EdDSA is somewhat less robust, even if SHA-512 or
-- whatever is not very fast. Despite that, just about any /modern/
-- /hash/ you pick is going to be collision resistant to a fine degree
-- (say, 256 bits of output, therefore collisions 'at best' happen in
-- @2^128@ operations), so in practice this robustness issue may not
-- be that big of a deal.
--
-- However, the more pertinent issue is that due to the current design
-- of the API which requires the entire blob to sign up front, using
-- the HashEdDSA construction is often much more convenient, faster
-- and sometimes /necessary/ too. For example, when signing very large
-- messages (such as creating a very large @tar.gz@ file which you
-- wish to sign after creation), it is often convenient and possible
-- to use \'incremental\' hashing APIs to incrementally consume data
-- blocks from the input in a constant amount of memory. At the end of
-- consumption, you can \'finalize\' the data blocks and get back a
-- final N-bit hash, and sign this hash all in a constant amount of
-- memory. With the current API, using PureDSA would require you
-- loading the entire file up front to either sign, or verify it. This
-- is especially unoptimal for possibly smaller, low-memory systems
-- (where decompression, hashing or verification are all best done in
-- constant space if possible).
--
-- Beware however, that if you do this sort of incremental hashing for
-- large blobs, you are __taking untrusted data__ and hashing it
-- __before checking the signature__ - be __exceptionally careful__
-- with data from a possibly untrustworthy source until you can verify
-- the signature.
--
-- So, __some basic guidelines are__:
--
--   - If you are simply not worried about efficiency very much, just
--   use __PureEdDSA__ (i.e.  just use @'sign'@ and @'verify'@
--   directly).
--
--   - If you have __lots of small messages__, use __PureEdDSA__ (i.e.
--   just use @'sign'@ and @'verify'@ directly).
--
--   - If you have to sign/verify __large messages__, possibly __in__
--   __an incremental fashion__, use __HashEdDSA__ with __a fast__
--   __hash__ (i.e.  just hash a message before using @'sign'@ or
--   @'verify'@ on it).
--
--       - A hash like __BLAKE2b__ is recommended. Fast and very secure.
--
--       - Remember: __never touch input data in any form until you__
--       __are done hashing it and verifying the signature__.
--
-- As a result, you should be safe hashing your input before passing
-- it to @'sign'@ or @'dsign'@ in this library if you desire, and it may
-- save you CPU cycles for large inputs. It should be no different
-- than the typical /hash-then-sign/ construction you see elsewhere,
-- with the same downfalls. Should you do this, an extremely
-- fast-yet-secure hash such as __BLAKE2b__ is recommended, which is
-- even faster than MD5 or SHA-1 (and __do not ever use MD5 or__
-- __SHA-1__, on that note - they suffer from collision attacks).