{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE BangPatterns #-}

-- |
-- Module: Crypto.MAC.Poly1305.Arm
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- ARM acceleration for the Poly1305 MAC.

module Crypto.MAC.Poly1305.Arm (
    poly1305_arm_available
  , mac
  ) where

import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BI
import Data.Word (Word8)
import Foreign.C.Types (CInt(..), CSize(..))
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Ptr (Ptr, plusPtr)
import System.IO.Unsafe (unsafeDupablePerformIO)

-- ffi ------------------------------------------------------------------------

foreign import ccall unsafe "poly1305_mac_arm"
  c_poly1305_mac
    :: Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> IO ()

foreign import ccall unsafe "poly1305_arm_available"
  c_poly1305_arm_available :: IO CInt

-- utilities ------------------------------------------------------------------

fi :: (Integral a, Num b) => a -> b
fi :: forall a b. (Integral a, Num b) => a -> b
fi = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE fi #-}

-- api ------------------------------------------------------------------------

-- | Are ARM extensions available?
poly1305_arm_available :: Bool
poly1305_arm_available :: Bool
poly1305_arm_available =
  IO CInt -> CInt
forall a. IO a -> a
unsafeDupablePerformIO IO CInt
c_poly1305_arm_available CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
0
{-# NOINLINE poly1305_arm_available #-}

-- | Compute a Poly1305 MAC over the message using the given (already-
--   validated 32-byte) key.
mac :: BS.ByteString -> BS.ByteString -> BS.ByteString
mac :: ByteString -> ByteString -> ByteString
mac (BI.PS ForeignPtr Word8
kfp Int
koff Int
_) (BI.PS ForeignPtr Word8
mfp Int
moff Int
mlen) =
  Int -> (Ptr Word8 -> IO ()) -> ByteString
BI.unsafeCreate Int
16 ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
dst ->
    ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
kfp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
kp0 ->
    ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
mfp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
mp0 ->
      Ptr Word8 -> Ptr Word8 -> CSize -> Ptr Word8 -> IO ()
c_poly1305_mac (Ptr Word8
kp0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
koff)
                     (Ptr Word8
mp0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
moff)
                     (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fi Int
mlen)
                     Ptr Word8
dst