<commit_before>{-# LANGUAGE BangPatterns, OverloadedStrings, MultiParamTypeClasses #-}
-- | 256 and 512 bit Skein. Supports "normal" hashing and Skein-MAC.
module Crypto.Threefish.Skein (
    Skein (..), Threefish (..), Block256, Block512, Key256, Key512, Nonce256,
    hash256, hash512
  ) where
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Crypto.Threefish.Threefish256
import Crypto.Threefish.Threefish512
import Crypto.Threefish.UBI
import Crypto.Threefish
import Crypto.Threefish.Skein.Internal
import Data.Bits
import Data.Serialize
import Data.Word
import Data.ByteString.Unsafe
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Marshal.Alloc
import System.IO.Unsafe

class Skein a where
  -- | Calculate the Skein-MAC of a message.
  skeinMAC :: a -> BSL.ByteString -> a
  -- | Calculate the Skein checksum of a message.
  skein :: BSL.ByteString -> a

type Nonce256 = Block256

init256 :: Key256 -> Word64 -> Skein256Ctx
init256 (Block256 k) outlen =
    unsafePerformIO $ do
      c <- mallocForeignPtrBytes 64
      withForeignPtr c $ \ctx -> do
        withKey $ \key -> do
          skein256_init ctx (castPtr key) (outlen*8)
      return (Skein256Ctx c)
  where
    withKey f | BS.length k == 32 = unsafeUseAsCString k (f . castPtr)
              | otherwise         = f nullPtr

update256 :: Skein256Ctx -> Int -> BSL.ByteString -> BS.ByteString
update256 (Skein256Ctx c) outlen bytes =
    unsafePerformIO $ withForeignPtr c $ go 1 bytes
  where
    outblocks =
      case outlen `quotRem` 32 of
        (blocks, 0) -> blocks
        (blocks, _) -> blocks+1
    !msgtype = type2int Message
    go !first !msg !ctx = do
      case BSL.splitAt 16384 msg of
        (chunk, rest)
          | BSL.null chunk ->
            allocaBytes (outblocks*32) $ \ptr -> do
              skein256_output ctx 0 (outblocks-1) ptr
              BS.packCStringLen (castPtr ptr, outlen)
          | otherwise -> do
              let !chunk' =
                    BSL.toStrict chunk
                  (!lst, !len) =
                    if BSL.null rest
                      then (2, fromIntegral $ BS.length chunk')
                      else (0, 16384)
              unsafeUseAsCString chunk' $ \ptr -> do
                skein256_update ctx (first .|. lst) msgtype len (castPtr ptr)
              go 0 rest ctx

hash256 :: Word64 -> Key256 -> BSL.ByteString -> BS.ByteString
hash256 outlen k bs =
    case init256 k outlen of
      ctx -> update256 ctx (fromIntegral outlen) bs

{-# INLINE skein256 #-}
-- | Hash a message using 256 bit Skein.
skein256 :: BSL.ByteString -> Block256
skein256 = Block256 . hash256 32 (Block256 "")

{-# INLINE skeinMAC256 #-}
-- | Create a 256 bit Skein-MAC.
skeinMAC256 :: Key256 -> BSL.ByteString -> Block256
skeinMAC256 key = Block256 . hash256 32 key

instance Skein Block256 where
  skeinMAC = skeinMAC256
  skein    = skein256



---------------------
-- 512 bit version --
---------------------

config512 :: Block512<commit_msg>Implemented toStrict to fix a compilation problem on Debian 7.2<commit_after>{-# LANGUAGE BangPatterns, OverloadedStrings, MultiParamTypeClasses #-}
-- | 256 and 512 bit Skein. Supports "normal" hashing and Skein-MAC.
module Crypto.Threefish.Skein (
    Skein (..), Threefish (..), Block256, Block512, Key256, Key512, Nonce256,
    hash256, hash512
  ) where
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Crypto.Threefish.Threefish256
import Crypto.Threefish.Threefish512
import Crypto.Threefish.UBI
import Crypto.Threefish
import Crypto.Threefish.Skein.Internal
import Data.Bits
import Data.Serialize
import Data.Word
import Data.ByteString.Unsafe
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Marshal.Alloc
import System.IO.Unsafe

class Skein a where
  -- | Calculate the Skein-MAC of a message.
  skeinMAC :: a -> BSL.ByteString -> a
  -- | Calculate the Skein checksum of a message.
  skein :: BSL.ByteString -> a

type Nonce256 = Block256

init256 :: Key256 -> Word64 -> Skein256Ctx
init256 (Block256 k) outlen =
    unsafePerformIO $ do
      c <- mallocForeignPtrBytes 64
      withForeignPtr c $ \ctx -> do
        withKey $ \key -> do
          skein256_init ctx (castPtr key) (outlen*8)
      return (Skein256Ctx c)
  where
    withKey f | BS.length k == 32 = unsafeUseAsCString k (f . castPtr)
              | otherwise         = f nullPtr

update256 :: Skein256Ctx -> Int -> BSL.ByteString -> BS.ByteString
update256 (Skein256Ctx c) outlen bytes =
    unsafePerformIO $ withForeignPtr c $ go 1 bytes
  where
    outblocks =
      case outlen `quotRem` 32 of
        (blocks, 0) -> blocks
        (blocks, _) -> blocks+1
    !msgtype = type2int Message
    go !first !msg !ctx = do
      case BSL.splitAt 16384 msg of
        (chunk, rest)
          | BSL.null chunk ->
            allocaBytes (outblocks*32) $ \ptr -> do
              skein256_output ctx 0 (outblocks-1) ptr
              BS.packCStringLen (castPtr ptr, outlen)
          | otherwise -> do
              let !chunk' =
                    toStrict chunk
                  (!lst, !len) =
                    if BSL.null rest
                      then (2, fromIntegral $ BS.length chunk')
                      else (0, 16384)
              unsafeUseAsCString chunk' $ \ptr -> do
                skein256_update ctx (first .|. lst) msgtype len (castPtr ptr)
              go 0 rest ctx

toStrict :: BSL.ByteString -> BS.ByteString
toStrict = BS.concat . BSL.toChunks

hash256 :: Word64 -> Key256 -> BSL.ByteString -> BS.ByteString
hash256 outlen k bs =
    case init256 k outlen of
      ctx -> update256 ctx (fromIntegral outlen) bs

{-# INLINE skein256 #-}
-- | Hash a message using 256 bit Skein.
skein256 :: BSL.ByteString -> Block256
skein256 = Block256 . hash256 32 (Block256 "")

{-# INLINE skeinMAC256 #-}
-- | Create a 256 bit Skein-MAC.
skeinMAC256 :: Key256 -> BSL.ByteString -> Block256
skeinMAC256 key = Block256 . hash256 32 key

instance Skein Block256 where
  skeinMAC = skeinMAC256
  skein    = skein256



---------------------
-- 512 bit version --
---------------------

config512 :: Block512
{'fraction_non_alphanumeric': 0.10533138875384865, 'fraction_numerical': 0.06352292983309026, 'mean_word_length': 2.3129361245303275, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 50, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '889965', 'n_tokens_mistral': 2225, 'n_tokens_neox': 1912, 'n_words': 596}