content: {-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, DeriveGeneric, ForeignFunctionInterface #-}
  -- |
  -- Module      : Crypto.Saltine.Internal.OneTimeAuth
  -- Copyright   : (c) Max Amanshauser 2021
  -- License     : MIT
  --
  -- Maintainer  : max@lambdalifting.org
  -- Stability   : experimental
  -- Portability : non-portable
  --
  module Crypto.Saltine.Internal.OneTimeAuth (
      onetimeauth_bytes
    , onetimeauth_keybytes
    , c_onetimeauth
    , c_onetimeauth_verify
    , Key(..)
    , Authenticator(..)
  ) where
  
  
  import Control.DeepSeq
  import Crypto.Saltine.Class
  import Crypto.Saltine.Core.Hash     (shorthash)
  import Crypto.Saltine.Internal.Hash (nullShKey)
  import Crypto.Saltine.Internal.Util as U
  import Data.ByteString              (ByteString)
  import Data.Data                    (Data, Typeable)
  import Data.Hashable                (Hashable)
  import Data.Monoid
  import Foreign.C
  import Foreign.Ptr
  import GHC.Generics                 (Generic)
  
  import qualified Data.ByteString as S
  
  -- | An opaque 'auth' cryptographic key.
  newtype Key = Key { unKey :: ByteString } deriving (Ord, Hashable, Data, Typeable, Generic, NFData)
  instance Eq Key where
      Key a == Key b = U.compare a b
  instance Show Key where
      show k = "OneTimeAuth.Key {hashesTo = \"" <> (bin2hex . shorthash nullShKey $ encode k) <> "\"}"
  
  instance IsEncoding Key where
    decode v = if S.length v == onetimeauth_keybytes
             then Just (Key v)
             else Nothing
    {-# INLINE decode #-}
    encode (Key v) = v
    {-# INLINE encode #-}
  
  -- | An opaque 'auth' authenticator.
  newtype Authenticator = Au { unAu :: ByteString } deriving (Eq, Ord, Hashable, Data, Typeable, Generic, NFData)
  instance Show Authenticator where
      show k = "OneTimeAuth.Authenticator " <> bin2hex (encode k)
  
  instance IsEncoding Authenticator where
    decode v = if S.length v == onetimeauth_bytes
             then Just (Au v)
             else Nothing
    {-# INLINE decode #-}
    encode (Au v) = v
    {-# INLINE encode #-}
  
  
  onetimeauth_bytes, onetimeauth_keybytes :: Int
  
  -- OneTimeAuth
  -- | Size of a @crypto_onetimeauth@ authenticator.
  onetimeauth_bytes    = fromIntegral c_crypto_onetimeauth_bytes
  -- | Size of a @crypto_onetimeauth@ authenticator key.
  onetimeauth_keybytes = fromIntegral c_crypto_onetimeauth_keybytes
  
  -- src/libsodium/crypto_onetimeauth/crypto_onetimeauth.c
  foreign import ccall "crypto_onetimeauth_bytes"
    c_crypto_onetimeauth_bytes :: CSize
  foreign import ccall "crypto_onetimeauth_keybytes"
    c_crypto_onetimeauth_keybytes :: CSize
  
  
  foreign import ccall "crypto_onetimeauth"
    c_onetimeauth :: Ptr CChar
                  -- ^ Authenticator output buffer
                  -> Ptr CChar
                  -- ^ Constant message buffer
                  -> CULLong
                  -- ^ Length of message buffer
                  -> Ptr CChar
                  -- ^ Constant key buffer
                  -> IO CInt
                  -- ^ Always 0
  
  -- | We don't even include this in the IO monad since all of the
  -- buffers are constant.
  foreign import ccall "crypto_onetimeauth_verify"
    c_onetimeauth_verify :: Ptr CChar
                         -- ^ Constant authenticator buffer
                         -> Ptr CChar
                         -- ^ Constant message buffer
                         -> CULLong
                         -- ^ Length of message buffer
                         -> Ptr CChar
                         -- ^ Constant key buffer
                         -> CInt
                         -- ^ Success if 0, failure if -1
  