Arm.hs (4568B)
1 {-# OPTIONS_HADDOCK hide #-} 2 {-# LANGUAGE BangPatterns #-} 3 4 -- | 5 -- Module: Crypto.Hash.SHA512.Arm 6 -- Copyright: (c) 2024 Jared Tobin 7 -- License: MIT 8 -- Maintainer: Jared Tobin <jared@ppad.tech> 9 -- 10 -- ARM crypto extension support for SHA-512. 11 12 module Crypto.Hash.SHA512.Arm ( 13 sha512_arm_available 14 , hash_arm 15 , hash_arm_with 16 ) where 17 18 import Control.Monad (unless, when) 19 import qualified Data.Bits as B 20 import qualified Data.ByteString as BS 21 import qualified Data.ByteString.Internal as BI 22 import qualified Data.ByteString.Unsafe as BU 23 import Data.Word (Word8, Word64) 24 import Foreign.Marshal.Alloc (allocaBytes) 25 import Foreign.Ptr (Ptr, plusPtr) 26 import Foreign.Storable (poke, peek) 27 import Crypto.Hash.SHA512.Internal (unsafe_padding) 28 import System.IO.Unsafe (unsafePerformIO) 29 30 -- ffi ----------------------------------------------------------------------- 31 32 foreign import ccall unsafe "sha512_block_arm" 33 c_sha512_block :: Ptr Word64 -> Ptr Word8 -> IO () 34 35 foreign import ccall unsafe "sha512_arm_available" 36 c_sha512_arm_available :: IO Int 37 38 -- utilities ----------------------------------------------------------------- 39 40 fi :: (Integral a, Num b) => a -> b 41 fi = fromIntegral 42 {-# INLINE fi #-} 43 44 -- api ----------------------------------------------------------------------- 45 46 sha512_arm_available :: Bool 47 sha512_arm_available = unsafePerformIO c_sha512_arm_available /= 0 48 {-# NOINLINE sha512_arm_available #-} 49 50 hash_arm :: BS.ByteString -> BS.ByteString 51 hash_arm = hash_arm_with mempty 0 52 53 -- | Hash with optional 128-byte prefix and extra length for padding. 54 hash_arm_with 55 :: BS.ByteString -- ^ optional 128-byte prefix (or empty) 56 -> Word64 -- ^ extra length to add for padding 57 -> BS.ByteString -- ^ message 58 -> BS.ByteString 59 hash_arm_with prefix el m@(BI.PS fp off l) = unsafePerformIO $ 60 allocaBytes 64 $ \state -> do 61 poke_iv state 62 -- process prefix block if provided 63 unless (BS.null prefix) $ do 64 let BI.PS pfp poff _ = prefix 65 BI.unsafeWithForeignPtr pfp $ \src -> 66 c_sha512_block state (src `plusPtr` poff) 67 68 go state 0 69 70 let !remaining@(BI.PS _ _ rlen) = BU.unsafeDrop (l - l `rem` 128) m 71 BI.PS padfp padoff _ = unsafe_padding remaining (el + fi l) 72 BI.unsafeWithForeignPtr padfp $ \src -> do 73 c_sha512_block state (src `plusPtr` padoff) 74 when (rlen >= 112) $ 75 c_sha512_block state (src `plusPtr` (padoff + 128)) 76 77 read_state state 78 where 79 go !state !j 80 | j + 128 <= l = do 81 BI.unsafeWithForeignPtr fp $ \src -> 82 c_sha512_block state (src `plusPtr` (off + j)) 83 go state (j + 128) 84 | otherwise = pure () 85 86 -- arm helpers --------------------------------------------------------------- 87 88 poke_iv :: Ptr Word64 -> IO () 89 poke_iv !state = do 90 poke state (0x6a09e667f3bcc908 :: Word64) 91 poke (state `plusPtr` 8) (0xbb67ae8584caa73b :: Word64) 92 poke (state `plusPtr` 16) (0x3c6ef372fe94f82b :: Word64) 93 poke (state `plusPtr` 24) (0xa54ff53a5f1d36f1 :: Word64) 94 poke (state `plusPtr` 32) (0x510e527fade682d1 :: Word64) 95 poke (state `plusPtr` 40) (0x9b05688c2b3e6c1f :: Word64) 96 poke (state `plusPtr` 48) (0x1f83d9abfb41bd6b :: Word64) 97 poke (state `plusPtr` 56) (0x5be0cd19137e2179 :: Word64) 98 99 read_state :: Ptr Word64 -> IO BS.ByteString 100 read_state !state = BI.create 64 $ \out -> do 101 h0 <- peek state :: IO Word64 102 h1 <- peek (state `plusPtr` 8) :: IO Word64 103 h2 <- peek (state `plusPtr` 16) :: IO Word64 104 h3 <- peek (state `plusPtr` 24) :: IO Word64 105 h4 <- peek (state `plusPtr` 32) :: IO Word64 106 h5 <- peek (state `plusPtr` 40) :: IO Word64 107 h6 <- peek (state `plusPtr` 48) :: IO Word64 108 h7 <- peek (state `plusPtr` 56) :: IO Word64 109 poke_word64be out 0 h0 110 poke_word64be out 8 h1 111 poke_word64be out 16 h2 112 poke_word64be out 24 h3 113 poke_word64be out 32 h4 114 poke_word64be out 40 h5 115 poke_word64be out 48 h6 116 poke_word64be out 56 h7 117 118 poke_word64be :: Ptr Word8 -> Int -> Word64 -> IO () 119 poke_word64be !p !off !w = do 120 poke (p `plusPtr` off) (fi (w `B.unsafeShiftR` 56) :: Word8) 121 poke (p `plusPtr` (off + 1)) (fi (w `B.unsafeShiftR` 48) :: Word8) 122 poke (p `plusPtr` (off + 2)) (fi (w `B.unsafeShiftR` 40) :: Word8) 123 poke (p `plusPtr` (off + 3)) (fi (w `B.unsafeShiftR` 32) :: Word8) 124 poke (p `plusPtr` (off + 4)) (fi (w `B.unsafeShiftR` 24) :: Word8) 125 poke (p `plusPtr` (off + 5)) (fi (w `B.unsafeShiftR` 16) :: Word8) 126 poke (p `plusPtr` (off + 6)) (fi (w `B.unsafeShiftR` 8) :: Word8) 127 poke (p `plusPtr` (off + 7)) (fi w :: Word8)