# LANGUAGE GeneralizedNewtypeDeriving #
# LANGUAGE TypeFamilies                #
# LANGUAGE FlexibleInstances           #
# LANGUAGE MultiParamTypeClasses       #
{-# LANGUAGE DataKinds                  #-}
# LANGUAGE FlexibleContexts            #
{-# CFILES raaz/hash/sha1/portable.c    #-}

-- |
--
-- Module      : Raaz.Primitive.Sha2.Internal
-- Description : Internal modules for sha2 family of hashes.
  Copyright    : ( c )    , 2019
-- License     : Apache-2.0 OR BSD-3-Clause
-- Maintainer  : Piyush P Kurur <>
-- Stability   : experimental
--
module Raaz.Primitive.Sha2.Internal
       ( -- * The sha2 types
         Sha512, Sha256
       , Sha512Mem, Sha256Mem
       , process512Last
       , process256Last
       ) where

import           Data.Vector.Unboxed        ( Unbox )
import           Foreign.Storable           ( Storable(..) )
import           GHC.TypeLits


import           Raaz.Core
import           Raaz.Core.Transfer.Unsafe
import           Raaz.Primitive.HashMemory

----------------------------- The blake2 type ---------------------------------

-- | The Sha2 type.
newtype Sha2 w = Sha2 (Tuple 8 w)
               deriving (Eq, Equality, Storable, EndianStore)

instance ( Unbox w
         , EndianStore w
         ) => Primitive (Sha2 w) where
  type WordType      (Sha2 w) = w
  type WordsPerBlock (Sha2 w) = 16


instance (Unbox w, EndianStore w) => Encodable (Sha2 w)

instance (EndianStore w, Unbox w) => IsString (Sha2 w) where
  fromString = fromBase16

instance (EndianStore w, Unbox w) => Show (Sha2 w) where
  show =  showBase16


  | The Sha512 cryptographic hash .
type Sha512 = Sha2 (BE Word64)

-- | The Sha256 cryptographic hash.
type Sha256 = Sha2 (BE Word32)

-- | The initial value to start the blake2b hashing. This is equal to
  the iv ` xor ` the parameter block .
sha512Init :: Sha512
sha512Init = Sha2 $ unsafeFromList [ 0x6a09e667f3bcc908
                                   , 0xbb67ae8584caa73b
                                   , 0x3c6ef372fe94f82b
                                   , 0xa54ff53a5f1d36f1
                                   , 0x510e527fade682d1
                                   , 0x9b05688c2b3e6c1f
                                   , 0x1f83d9abfb41bd6b
                                   , 0x5be0cd19137e2179
                                   ]

-- | The initial value to start the blake2b hashing. This is equal to
  the iv ` xor ` the parameter block .
sha256Init :: Sha256
sha256Init = Sha2 $ unsafeFromList [ 0x6a09e667
                                   , 0xbb67ae85
                                   , 0x3c6ef372
                                   , 0xa54ff53a
                                   , 0x510e527f
                                   , 0x9b05688c
                                   , 0x1f83d9ab
                                   , 0x5be0cd19
                                   ]

-------------------------------- Memory element for Sha512 -----------------------

  | The memory used by sha512 implementations .
type Sha512Mem = HashMemory128 Sha512

-- | The memory used bha sha256 implementations.
type Sha256Mem = HashMemory64 Sha256

instance Initialisable Sha256Mem () where
  initialise _ = initialise sha256Init

instance Initialisable Sha512Mem () where
  initialise _ = initialise sha512Init


-- | The block compressor for sha256.
type Compressor256 n =  AlignedBlockPtr n Sha256
                     -> BlockCount Sha256
                     -> Sha256Mem -> IO ()
  | The block compressor for sha512
type Compressor512 n =  AlignedBlockPtr n Sha512
                     -> BlockCount Sha512
                     -> Sha512Mem -> IO ()

-- | Takes a block processing function for sha256 and gives a last
-- bytes processor.
process256Last :: KnownNat n
               => Compressor256 n    -- ^ block compressor
               -> AlignedBlockPtr n Sha256
               -> BYTES Int
               -> Sha256Mem
               -> IO ()
process256Last comp buf nbytes sha256mem = do
  updateLength nbytes sha256mem
  totalBytes  <- fmap bigEndian <$> getLength sha256mem
  let pad      = padding256 nbytes totalBytes
      blocks   = atMost $ transferSize pad
    in unsafeTransfer pad buf >> comp buf blocks sha256mem

  | Takes a block processing function for sha512 and gives a last
-- bytes processor.
process512Last :: KnownNat n
               => Compressor512 n
               -> AlignedBlockPtr n Sha512
               -> BYTES Int
               -> Sha512Mem
               -> IO ()
process512Last comp buf nbytes sha512mem = do
  updateLength128 nbytes sha512mem
  uLen  <- fmap bigEndian <$> getULength sha512mem
  lLen  <- fmap bigEndian <$> getLLength sha512mem
  let pad      = padding512 nbytes uLen lLen
      blocks   = atMost $ transferSize pad
      in unsafeTransfer pad buf >> comp buf blocks sha512mem

-- | The padding for sha256 as a writer.
padding256 :: BYTES Int         -- Data in buffer.
           -> BYTES (BE Word64) -- Message length
           -> WriteTo
padding256 bufSize msgLen  =
  glueWrites 0 boundary (padBit1 bufSize) lengthWrite
  where boundary    = blocksOf 1 (Proxy :: Proxy Sha256)
        lengthWrite = write $ shiftL msgLen 3

  | The padding for sha512 as a writer .
padding512 :: BYTES Int         -- Data in buffer.
           -> BYTES (BE Word64) -- Message length higher
           -> BYTES (BE Word64) -- Message length lower
           -> WriteTo
padding512 bufSize uLen lLen  = glueWrites 0 boundary (padBit1 bufSize) lengthWrite
  where boundary    = blocksOf 1 (Proxy :: Proxy Sha512)
        lengthWrite = write up `mappend` write lp
        up          = shiftL uLen 3 .|. shiftR lLen 61
        lp          = shiftL lLen 3


  | Pad the message with a 1 - bit .
padBit1 :: BYTES Int -- ^ message length
        -> WriteTo
padBit1  sz = skip sz <> writeStorable (0x80 :: Word8)

# LANGUAGE DataKinds                  #
# CFILES raaz/hash/sha1/portable.c    #
 |

 Module      : Raaz.Primitive.Sha2.Internal
 Description : Internal modules for sha2 family of hashes.
 License     : Apache-2.0 OR BSD-3-Clause
 Maintainer  : Piyush P Kurur <>
 Stability   : experimental

 * The sha2 types
--------------------------- The blake2 type ---------------------------------
 | The Sha2 type.
 | The Sha256 cryptographic hash.
 | The initial value to start the blake2b hashing. This is equal to
 | The initial value to start the blake2b hashing. This is equal to
------------------------------ Memory element for Sha512 -----------------------
 | The memory used bha sha256 implementations.
 | The block compressor for sha256.
 | Takes a block processing function for sha256 and gives a last
 bytes processor.
 ^ block compressor
 bytes processor.
 | The padding for sha256 as a writer.
 Data in buffer.
 Message length
 Data in buffer.
 Message length higher
 Message length lower
 ^ message length
# LANGUAGE GeneralizedNewtypeDeriving #
# LANGUAGE TypeFamilies                #
# LANGUAGE FlexibleInstances           #
# LANGUAGE MultiParamTypeClasses       #
# LANGUAGE FlexibleContexts            #

  Copyright    : ( c )    , 2019
module Raaz.Primitive.Sha2.Internal
         Sha512, Sha256
       , Sha512Mem, Sha256Mem
       , process512Last
       , process256Last
       ) where

import           Data.Vector.Unboxed        ( Unbox )
import           Foreign.Storable           ( Storable(..) )
import           GHC.TypeLits


import           Raaz.Core
import           Raaz.Core.Transfer.Unsafe
import           Raaz.Primitive.HashMemory


newtype Sha2 w = Sha2 (Tuple 8 w)
               deriving (Eq, Equality, Storable, EndianStore)

instance ( Unbox w
         , EndianStore w
         ) => Primitive (Sha2 w) where
  type WordType      (Sha2 w) = w
  type WordsPerBlock (Sha2 w) = 16


instance (Unbox w, EndianStore w) => Encodable (Sha2 w)

instance (EndianStore w, Unbox w) => IsString (Sha2 w) where
  fromString = fromBase16

instance (EndianStore w, Unbox w) => Show (Sha2 w) where
  show =  showBase16


  | The Sha512 cryptographic hash .
type Sha512 = Sha2 (BE Word64)

type Sha256 = Sha2 (BE Word32)

  the iv ` xor ` the parameter block .
sha512Init :: Sha512
sha512Init = Sha2 $ unsafeFromList [ 0x6a09e667f3bcc908
                                   , 0xbb67ae8584caa73b
                                   , 0x3c6ef372fe94f82b
                                   , 0xa54ff53a5f1d36f1
                                   , 0x510e527fade682d1
                                   , 0x9b05688c2b3e6c1f
                                   , 0x1f83d9abfb41bd6b
                                   , 0x5be0cd19137e2179
                                   ]

  the iv ` xor ` the parameter block .
sha256Init :: Sha256
sha256Init = Sha2 $ unsafeFromList [ 0x6a09e667
                                   , 0xbb67ae85
                                   , 0x3c6ef372
                                   , 0xa54ff53a
                                   , 0x510e527f
                                   , 0x9b05688c
                                   , 0x1f83d9ab
                                   , 0x5be0cd19
                                   ]


  | The memory used by sha512 implementations .
type Sha512Mem = HashMemory128 Sha512

type Sha256Mem = HashMemory64 Sha256

instance Initialisable Sha256Mem () where
  initialise _ = initialise sha256Init

instance Initialisable Sha512Mem () where
  initialise _ = initialise sha512Init


type Compressor256 n =  AlignedBlockPtr n Sha256
                     -> BlockCount Sha256
                     -> Sha256Mem -> IO ()
  | The block compressor for sha512
type Compressor512 n =  AlignedBlockPtr n Sha512
                     -> BlockCount Sha512
                     -> Sha512Mem -> IO ()

process256Last :: KnownNat n
               -> AlignedBlockPtr n Sha256
               -> BYTES Int
               -> Sha256Mem
               -> IO ()
process256Last comp buf nbytes sha256mem = do
  updateLength nbytes sha256mem
  totalBytes  <- fmap bigEndian <$> getLength sha256mem
  let pad      = padding256 nbytes totalBytes
      blocks   = atMost $ transferSize pad
    in unsafeTransfer pad buf >> comp buf blocks sha256mem

  | Takes a block processing function for sha512 and gives a last
process512Last :: KnownNat n
               => Compressor512 n
               -> AlignedBlockPtr n Sha512
               -> BYTES Int
               -> Sha512Mem
               -> IO ()
process512Last comp buf nbytes sha512mem = do
  updateLength128 nbytes sha512mem
  uLen  <- fmap bigEndian <$> getULength sha512mem
  lLen  <- fmap bigEndian <$> getLLength sha512mem
  let pad      = padding512 nbytes uLen lLen
      blocks   = atMost $ transferSize pad
      in unsafeTransfer pad buf >> comp buf blocks sha512mem

           -> WriteTo
padding256 bufSize msgLen  =
  glueWrites 0 boundary (padBit1 bufSize) lengthWrite
  where boundary    = blocksOf 1 (Proxy :: Proxy Sha256)
        lengthWrite = write $ shiftL msgLen 3

  | The padding for sha512 as a writer .
           -> WriteTo
padding512 bufSize uLen lLen  = glueWrites 0 boundary (padBit1 bufSize) lengthWrite
  where boundary    = blocksOf 1 (Proxy :: Proxy Sha512)
        lengthWrite = write up `mappend` write lp
        up          = shiftL uLen 3 .|. shiftR lLen 61
        lp          = shiftL lLen 3


  | Pad the message with a 1 - bit .
        -> WriteTo
padBit1  sz = skip sz <> writeStorable (0x80 :: Word8)
