<commit_before>{-|

A cryptographic hash function abstraction.

-}

{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts           #-}

module Raaz.Primitives.Hash
       ( HashGadget(..)
       , Hash
       , HMAC(..)
       , sourceHash', sourceHash
       , hash', hash
       , hashFile', hashFile
       ) where

import           Control.Applicative  ((<$>))
import           Control.Monad        (foldM)
import           Data.Default
import           Data.Word            (Word64)
import           Data.Bits
import qualified Data.ByteString      as B
import qualified Data.ByteString.Lazy as L
import           Foreign.Storable     (Storable(..))
import           Foreign.ForeignPtr.Safe
import           Prelude              hiding (length)
import           System.IO            (withBinaryFile, IOMode(ReadMode), Handle)
import           System.IO.Unsafe     (unsafePerformIO)

import           Raaz.ByteSource
import           Raaz.Memory
import           Raaz.Primitives
import           Raaz.Types
import           Raaz.Util.ByteString (length)
import           Raaz.Util.Ptr
import           Raaz.Util.SecureMemory


-- | The class abstracts an arbitrary hash type. A hash should be a
-- block primitive. Computing the hash involved starting at a fixed
-- context and iterating through the blocks of data (suitably padded)
-- by the process function. The last context is then finalised to the
-- value of the hash.
--
-- A Minimum complete definition include @`startHashCxt`@,
-- @`finaliseHash`@, However, for efficiency you might want to define
-- all of the members separately.
--
-- [Warning:] While defining the @'Eq'@ instance of @'Hash' h@, make
-- sure that the @==@ operator takes time independent of the input.
-- This is to avoid timing based side-channel attacks. In particular,
-- /do not/ take the lazy option of deriving the @'Eq'@ instance.
class ( SafeGadget g
      , Eq          (PrimitiveOf g)
      , HasPadding  (PrimitiveOf g)
      , Default     (IV (PrimitiveOf g))
      , CryptoStore (PrimitiveOf g)
      ) => HashGadget g where

  -- | Computes the iterated hash, useful for password
  -- hashing. Although a default implementation is given, you might
  -- want to give an optimized specialised version of this function.
  iterateHash :: g             -- ^ Implementation
              -> Int           -- ^ Number of times to iterate
              -> PrimitiveOf g -- ^ starting hash
              -> PrimitiveOf g
  iterateHash g n h = unsafePerformIO $ allocaBuffer tl (iterateN h)
      where dl = BYTES $ sizeOf h              -- length of msg
            pl = padLength h (cryptoCoerce dl) -- length of pad
            tl = dl + pl                       -- total length
            blks = cryptoCoerce tl `asTypeOf` blocksOf 1 h
            iterateN _ cptr = do
              unsafePad h bits padPtr
              foldM iterateOnce h [1..n]
              where
                bits   = cryptoCoerce dl
                padPtr = cptr `movePtr` dl
                iterateOnce hsh _ = do
                  store cptr hsh
                  initialize g def
                  apply g blks cptr
                  finalize g

  -- | This functions processes data which itself is a hash. One can
  -- use this for iterated hash computation, hmac construction
  -- etc. There is a default definition of this function but
  -- implementations can give a more efficient version.
  processHash :: g           -- ^ Context obtained by processing so far
              -> BITS Word64 -- ^ number of bits processed so far
                             -- (exculding the bits in the hash)
              -> PrimitiveOf g
              -> PrimitiveOf g
  processHash g bits h = unsafePerformIO $ allocaBuffer tl go
     where sz      = BYTES $ sizeOf h
           tBits   = bits + cryptoCoerce sz
           pl      = padLength h tBits
           tl      = sz + pl
           go cptr = do
              store cptr h
              unsafePad h tBits $ cptr `movePtr` sz
              apply g (cryptoCoerce tl) cptr
              finalize g


class (CryptoPrimitive h, HashGadget (Recommended h)) => Hash h where

-- | Hash a given byte source.
sourceHash' :: ( HashGadget g, ByteSource src )
            => g    -- ^ Gadget
            -> src  -- ^ Message
            -> IO (PrimitiveOf g)
sourceHash' g src = do<commit_msg>the HashGadget instance got better defined.<commit_after>{-|

A cryptographic hash function abstraction.

-}

{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts           #-}

module Raaz.Primitives.Hash
       ( HashGadget(..)
       , Hash
       , HMAC(..)
       , sourceHash', sourceHash
       , hash', hash
       , hashFile', hashFile
       ) where

import           Control.Applicative  ((<$>))
import           Control.Monad        (foldM)
import           Data.Default
import           Data.Word            (Word64)
import           Data.Bits
import qualified Data.ByteString      as B
import qualified Data.ByteString.Lazy as L
import           Foreign.Storable     (Storable(..))
import           Foreign.ForeignPtr.Safe
import           Prelude              hiding (length)
import           System.IO            (withBinaryFile, IOMode(ReadMode), Handle)
import           System.IO.Unsafe     (unsafePerformIO)

import           Raaz.ByteSource
import           Raaz.Memory
import           Raaz.Primitives
import           Raaz.Types
import           Raaz.Util.ByteString (length)
import           Raaz.Util.Ptr
import           Raaz.Util.SecureMemory


-- | Gadgets that compute a cryptographic hash.
class ( SafeGadget g
      , Eq          (PrimitiveOf g)
      , HasPadding  (PrimitiveOf g)
      , Default     (IV (PrimitiveOf g))
      , CryptoStore (PrimitiveOf g)
      ) => HashGadget g where

  -- | Computes the iterated hash, useful for password
  -- hashing. Although a default implementation is given, you might
  -- want to give an optimized specialised version of this function.
  iterateHash :: g             -- ^ The gadget
              -> Int           -- ^ Number of times to iterate
              -> PrimitiveOf g -- ^ starting hash
              -> IO (PrimitiveOf g)
  iterateHash g n h = allocaBuffer tl (iterateN h)
      where dl = BYTES $ sizeOf h              -- length of msg
            pl = padLength h (cryptoCoerce dl) -- length of pad
            tl = dl + pl                       -- total length
            blks = cryptoCoerce tl `asTypeOf` blocksOf 1 h
            iterateN _ cptr = do
              unsafePad h bits padPtr
              foldM iterateOnce h [1..n]
              where
                bits   = cryptoCoerce dl
                padPtr = cptr `movePtr` dl
                iterateOnce hsh _ = do
                  store cptr hsh
                  initialize g def
                  apply g blks cptr
                  finalize g

  -- | This functions processes data which itself is a hash. One can
  -- use this for iterated hash computation, hmac construction
  -- etc. There is a default definition of this function but
  -- implementations can give a more efficient version.
  processHash :: g           -- ^ The gadget
              -> BITS Word64 -- ^ number of bits processed so far
                             -- (exculding the bits in the hash)
              -> PrimitiveOf g
              -> IO (PrimitiveOf g)
  processHash g bits h = allocaBuffer tl go
     where sz      = BYTES $ sizeOf h
           tBits   = bits + cryptoCoerce sz
           pl      = padLength h tBits
           tl      = sz + pl
           go cptr = do
              store cptr h
              unsafePad h tBits $ cptr `movePtr` sz
              apply g (cryptoCoerce tl) cptr
              finalize g


class (CryptoPrimitive h, HashGadget (Recommended h)) => Hash h where

-- | Hash a given byte source.
sourceHash' :: ( HashGadget g, ByteSource src )
            => g    -- ^ Gadget
            -> src  -- ^ Message
            -> IO (PrimitiveOf g)
sourceHash' g src = do
{'fraction_non_alphanumeric': 0.0736037479965479, 'fraction_numerical': 0.0014794723215386513, 'mean_word_length': 1.6058464503694185, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1666008', 'n_tokens_mistral': 2189, 'n_tokens_neox': 2133, 'n_words': 804}