{-# LANGUAGE AllowAmbiguousTypes  #-}
{-# LANGUAGE TypeApplications     #-}
{-# LANGUAGE TypeOperators        #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module ZkFold.Symbolic.Algorithms.Hash.SHA2 (AlgorithmSetup (..), SHA2, sha2, SHA2N, sha2Natural) where

import           Control.DeepSeq                                (NFData, force)
import           Control.Monad                                  (forM_)
import           Data.Bits                                      (shiftL)
import           Data.Proxy                                     (Proxy (..))
import qualified Data.STRef                                     as ST
import           Data.Type.Bool                                 (If)
import qualified Data.Vector                                    as V
import qualified Data.Vector.Mutable                            as VM
import           GHC.TypeLits                                   (Symbol)
import           GHC.TypeNats                                   (Div, Natural, natVal, type (<=?))
import           Prelude                                        (Int, id, pure, zip, ($!), ($), (.), (>>=))
import qualified Prelude                                        as P

import           ZkFold.Base.Algebra.Basic.Class
import           ZkFold.Base.Algebra.Basic.Number
import           ZkFold.Symbolic.Algorithms.Hash.SHA2.Constants (sha224InitialHashes, sha256InitialHashes,
                                                                 sha384InitialHashes, sha512InitialHashes,
                                                                 sha512_224InitialHashes, sha512_256InitialHashes,
                                                                 word32RoundConstants, word64RoundConstants)
import           ZkFold.Symbolic.Data.Bool                      (BoolType (..))
import           ZkFold.Symbolic.Data.ByteString                (ByteString (..), Concat (..), ShiftBits (..),
                                                                 ToWords (..), Truncate (..))
import           ZkFold.Symbolic.Data.Combinators               (Extend (..), Iso (..))
import           ZkFold.Symbolic.Data.UInt                      (UInt)

-- | SHA2 is a family of hashing functions with almost identical implementations but different constants and parameters.
-- This class links these varying parts with the appropriate algorithm.
--
class AlgorithmSetup (algorithm :: Symbol) a where
    type WordSize algorithm :: Natural
    -- ^ The length of words the algorithm operates internally, in bits.

    type ChunkSize algorithm :: Natural
    -- ^ Hashing algorithms from SHA2 family require splitting the input message into blocks.
    -- This type describes the size of these blocks, in bits.

    type ResultSize algorithm :: Natural
    -- ^ The length of the resulting hash, in bits.

    initialHashes :: V.Vector (ByteString (WordSize algorithm) a)
    -- ^ Initial hash values which will be mixed with the message bits.

    roundConstants :: V.Vector (ByteString (WordSize algorithm) a)
    -- ^ Constants used in the internal loop, one per each round.

    truncateResult :: ByteString (8 * WordSize algorithm) a -> ByteString (ResultSize algorithm) a
    -- ^ A function to postprocess the hash. For example, SHA224 requires dropping the last 32 bits of a SHA256 hash.

    sigmaShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
    -- ^ Round rotation values for Sigma in the internal loop.

    sumShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
    -- ^ Round rotation values for Sum in the internal loop.

instance (FromConstant Natural a) => AlgorithmSetup "SHA256" a where
    type WordSize "SHA256" = 32
    type ChunkSize "SHA256" = 512
    type ResultSize "SHA256" = 256
    initialHashes :: Vector (ByteString (WordSize "SHA256") a)
initialHashes = Vector (ByteString 32 a)
Vector (ByteString (WordSize "SHA256") a)
forall a. FromConstant Natural a => Vector a
sha256InitialHashes
    roundConstants :: Vector (ByteString (WordSize "SHA256") a)
roundConstants = Vector (ByteString 32 a)
Vector (ByteString (WordSize "SHA256") a)
forall a. FromConstant Natural a => Vector a
word32RoundConstants
    truncateResult :: ByteString (8 * WordSize "SHA256") a
-> ByteString (ResultSize "SHA256") a
truncateResult = ByteString 256 a -> ByteString 256 a
ByteString (8 * WordSize "SHA256") a
-> ByteString (ResultSize "SHA256") a
forall a. a -> a
id
    sigmaShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sigmaShifts = (Natural
7, Natural
18, Natural
3, Natural
17, Natural
19, Natural
10)
    sumShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sumShifts = (Natural
2, Natural
13, Natural
22, Natural
6, Natural
11, Natural
25)


instance (FromConstant Natural a, Truncate (ByteString 256 a) (ByteString 224 a)) => AlgorithmSetup "SHA224" a where
    type WordSize "SHA224" = 32
    type ChunkSize "SHA224" = 512
    type ResultSize "SHA224" = 224
    initialHashes :: Vector (ByteString (WordSize "SHA224") a)
initialHashes = Vector (ByteString 32 a)
Vector (ByteString (WordSize "SHA224") a)
forall a. FromConstant Natural a => Vector a
sha224InitialHashes
    roundConstants :: Vector (ByteString (WordSize "SHA224") a)
roundConstants = Vector (ByteString 32 a)
Vector (ByteString (WordSize "SHA224") a)
forall a. FromConstant Natural a => Vector a
word32RoundConstants
    truncateResult :: ByteString (8 * WordSize "SHA224") a
-> ByteString (ResultSize "SHA224") a
truncateResult = ByteString 256 a -> ByteString 224 a
ByteString (8 * WordSize "SHA224") a
-> ByteString (ResultSize "SHA224") a
forall a b. Truncate a b => a -> b
truncate
    sigmaShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sigmaShifts = (Natural
7, Natural
18, Natural
3, Natural
17, Natural
19, Natural
10)
    sumShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sumShifts = (Natural
2, Natural
13, Natural
22, Natural
6, Natural
11, Natural
25)

instance (FromConstant Natural a) => AlgorithmSetup "SHA512" a where
    type WordSize "SHA512" = 64
    type ChunkSize "SHA512" = 1024
    type ResultSize "SHA512" = 512
    initialHashes :: Vector (ByteString (WordSize "SHA512") a)
initialHashes = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA512") a)
forall a. FromConstant Natural a => Vector a
sha512InitialHashes
    roundConstants :: Vector (ByteString (WordSize "SHA512") a)
roundConstants = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA512") a)
forall a. FromConstant Natural a => Vector a
word64RoundConstants
    truncateResult :: ByteString (8 * WordSize "SHA512") a
-> ByteString (ResultSize "SHA512") a
truncateResult = ByteString 512 a -> ByteString 512 a
ByteString (8 * WordSize "SHA512") a
-> ByteString (ResultSize "SHA512") a
forall a. a -> a
id
    sigmaShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sigmaShifts = (Natural
1, Natural
8, Natural
7, Natural
19, Natural
61, Natural
6)
    sumShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sumShifts = (Natural
28, Natural
34, Natural
39, Natural
14, Natural
18, Natural
41)

instance (FromConstant Natural a, Truncate (ByteString 512 a) (ByteString 384 a)) => AlgorithmSetup "SHA384" a where
    type WordSize "SHA384" = 64
    type ChunkSize "SHA384" = 1024
    type ResultSize "SHA384" = 384
    initialHashes :: Vector (ByteString (WordSize "SHA384") a)
initialHashes = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA384") a)
forall a. FromConstant Natural a => Vector a
sha384InitialHashes
    roundConstants :: Vector (ByteString (WordSize "SHA384") a)
roundConstants = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA384") a)
forall a. FromConstant Natural a => Vector a
word64RoundConstants
    truncateResult :: ByteString (8 * WordSize "SHA384") a
-> ByteString (ResultSize "SHA384") a
truncateResult = ByteString 512 a -> ByteString 384 a
ByteString (8 * WordSize "SHA384") a
-> ByteString (ResultSize "SHA384") a
forall a b. Truncate a b => a -> b
truncate
    sigmaShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sigmaShifts = (Natural
1, Natural
8, Natural
7, Natural
19, Natural
61, Natural
6)
    sumShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sumShifts = (Natural
28, Natural
34, Natural
39, Natural
14, Natural
18, Natural
41)

instance (FromConstant Natural a, Truncate (ByteString 512 a) (ByteString 224 a)) => AlgorithmSetup "SHA512/224" a where
    type WordSize "SHA512/224" = 64
    type ChunkSize "SHA512/224" = 1024
    type ResultSize "SHA512/224" = 224
    initialHashes :: Vector (ByteString (WordSize "SHA512/224") a)
initialHashes = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA512/224") a)
forall a. FromConstant Natural a => Vector a
sha512_224InitialHashes
    roundConstants :: Vector (ByteString (WordSize "SHA512/224") a)
roundConstants = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA512/224") a)
forall a. FromConstant Natural a => Vector a
word64RoundConstants
    truncateResult :: ByteString (8 * WordSize "SHA512/224") a
-> ByteString (ResultSize "SHA512/224") a
truncateResult = ByteString 512 a -> ByteString 224 a
ByteString (8 * WordSize "SHA512/224") a
-> ByteString (ResultSize "SHA512/224") a
forall a b. Truncate a b => a -> b
truncate
    sigmaShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sigmaShifts = (Natural
1, Natural
8, Natural
7, Natural
19, Natural
61, Natural
6)
    sumShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sumShifts = (Natural
28, Natural
34, Natural
39, Natural
14, Natural
18, Natural
41)

instance (FromConstant Natural a, Truncate (ByteString 512 a) (ByteString 256 a)) => AlgorithmSetup "SHA512/256" a where
    type WordSize "SHA512/256" = 64
    type ChunkSize "SHA512/256" = 1024
    type ResultSize "SHA512/256" = 256
    initialHashes :: Vector (ByteString (WordSize "SHA512/256") a)
initialHashes = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA512/256") a)
forall a. FromConstant Natural a => Vector a
sha512_256InitialHashes
    roundConstants :: Vector (ByteString (WordSize "SHA512/256") a)
roundConstants = Vector (ByteString 64 a)
Vector (ByteString (WordSize "SHA512/256") a)
forall a. FromConstant Natural a => Vector a
word64RoundConstants
    truncateResult :: ByteString (8 * WordSize "SHA512/256") a
-> ByteString (ResultSize "SHA512/256") a
truncateResult = ByteString 512 a -> ByteString 256 a
ByteString (8 * WordSize "SHA512/256") a
-> ByteString (ResultSize "SHA512/256") a
forall a b. Truncate a b => a -> b
truncate
    sigmaShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sigmaShifts = (Natural
1, Natural
8, Natural
7, Natural
19, Natural
61, Natural
6)
    sumShifts :: (Natural, Natural, Natural, Natural, Natural, Natural)
sumShifts = (Natural
28, Natural
34, Natural
39, Natural
14, Natural
18, Natural
41)

-- | On type level, determine the smallest multiple of @divisor@ not less than @n@.
--
type family NextMultiple (n :: Natural) (divisor :: Natural) :: Natural where
    NextMultiple n divisor = divisor * Div (n + divisor - 1) divisor

{- | On type level, determine the length of the message after padding.
    Padding algorithm is described below:

    1. begin with the original message of length L bits
    2. append a single '1' bit
    3. append K '0' bits, where K is the minimum number >= 0 such that (L + 1 + K + 64) is a multiple of 512
    4. append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits

    such that the bits in the message are: <original message of length L> 1 <K zeros> <L as 64 bit integer>

    For SHA384, SHA512 and SHA512/t, replace 512 with 1024 and 64 with 128.
-}
type family PaddedLength (msg :: Natural) (block :: Natural) (lenBits :: Natural) :: Natural where
    PaddedLength msg block lenBits = If (NextMultiple msg block - msg <=? lenBits) (block + NextMultiple msg block) (NextMultiple msg block)

-- | Constraints required for a type-safe SHA2
--
type SHA2 algorithm element k =
   ( AlgorithmSetup algorithm element
   , KnownNat k
   , Finite element
   , NFData element
   , FromConstant Natural element
   , KnownNat (ChunkSize algorithm)
   , KnownNat (WordSize algorithm)
   , KnownNat (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm))
   , Iso (UInt (WordSize algorithm) element) (ByteString (WordSize algorithm) element)
   , Iso (ByteString (WordSize algorithm) element) (UInt (WordSize algorithm) element)
   , AdditiveSemigroup (UInt (WordSize algorithm) element)
   , BoolType (ByteString (WordSize algorithm) element)
   , ShiftBits (ByteString (WordSize algorithm) element)
   , ShiftBits (ByteString (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm)) element)
   , BoolType (ByteString (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm)) element)
   , Extend (ByteString k element) (ByteString (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm)) element)
   , ToWords (ByteString (ChunkSize algorithm) element) (ByteString (WordSize algorithm) element)
   , Concat (ByteString (WordSize algorithm) element) (ByteString (8 * WordSize algorithm) element)
   , ToWords (ByteString (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm)) element) (ByteString (ChunkSize algorithm) element)
   )

-- | A generalised version of SHA2. It is agnostic of the ByteString base field.
-- Sample usage:
--
-- >>> bs = fromConstant (42 :: Natural) :: ByteString 8 (Zp BLS12_381_Scalar)
-- >>> hash = sha2 @"SHA256" bs
--
sha2
    :: forall (algorithm :: Symbol) element k
    .  SHA2 algorithm element k
    => ByteString k element -> ByteString (ResultSize algorithm) element
sha2 :: forall (algorithm :: Symbol) element (k :: Natural).
SHA2 algorithm element k =>
ByteString k element -> ByteString (ResultSize algorithm) element
sha2 ByteString k element
messageBits = forall (algorithm :: Symbol) element.
(AlgorithmSetup algorithm element, NFData element,
 Iso
   (ByteString (WordSize algorithm) element)
   (UInt (WordSize algorithm) element),
 AdditiveSemigroup (UInt (WordSize algorithm) element),
 BoolType (ByteString (WordSize algorithm) element),
 ShiftBits (ByteString (WordSize algorithm) element),
 ToWords
   (ByteString (ChunkSize algorithm) element)
   (ByteString (WordSize algorithm) element),
 Concat
   (ByteString (WordSize algorithm) element)
   (ByteString (8 * WordSize algorithm) element)) =>
[ByteString (ChunkSize algorithm) element]
-> ByteString (ResultSize algorithm) element
sha2Blocks @algorithm @element [ByteString (ChunkSize algorithm) element]
chunks
    where
        paddedMessage :: ByteString (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm)) element
        paddedMessage :: ByteString
  (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm))
  element
paddedMessage = forall (padTo :: Natural) (lenBits :: Natural) (k :: Natural)
       element.
(KnownNat k, KnownNat (PaddedLength k padTo lenBits),
 FromConstant Natural element,
 ShiftBits (ByteString (PaddedLength k padTo lenBits) element),
 BoolType (ByteString (PaddedLength k padTo lenBits) element),
 Extend
   (ByteString k element)
   (ByteString (PaddedLength k padTo lenBits) element)) =>
ByteString k element
-> ByteString (PaddedLength k padTo lenBits) element
sha2Pad @(ChunkSize algorithm) @(2 * WordSize algorithm) ByteString k element
messageBits

        chunks :: [ByteString (ChunkSize algorithm) element]
        chunks :: [ByteString (ChunkSize algorithm) element]
chunks = ByteString
  (If
     (OrdCond
        (CmpNat
           ((ChunkSize algorithm
             * Div ((k + ChunkSize algorithm) - 1) (ChunkSize algorithm))
            - k)
           (2 * WordSize algorithm))
        'True
        'True
        'False)
     (ChunkSize algorithm
      + (ChunkSize algorithm
         * Div ((k + ChunkSize algorithm) - 1) (ChunkSize algorithm)))
     (ChunkSize algorithm
      * Div ((k + ChunkSize algorithm) - 1) (ChunkSize algorithm)))
  element
-> [ByteString (ChunkSize algorithm) element]
forall a b. ToWords a b => a -> [b]
toWords ByteString
  (If
     (OrdCond
        (CmpNat
           ((ChunkSize algorithm
             * Div ((k + ChunkSize algorithm) - 1) (ChunkSize algorithm))
            - k)
           (2 * WordSize algorithm))
        'True
        'True
        'False)
     (ChunkSize algorithm
      + (ChunkSize algorithm
         * Div ((k + ChunkSize algorithm) - 1) (ChunkSize algorithm)))
     (ChunkSize algorithm
      * Div ((k + ChunkSize algorithm) - 1) (ChunkSize algorithm)))
  element
ByteString
  (PaddedLength k (ChunkSize algorithm) (2 * WordSize algorithm))
  element
paddedMessage

-- | Pad the input bytestring according to the rules described in @PaddedLength@
--
sha2Pad
    :: forall (padTo :: Natural) (lenBits :: Natural) (k :: Natural) element
    .  KnownNat k
    => KnownNat (PaddedLength k padTo lenBits)
    => FromConstant Natural element
    => ShiftBits (ByteString (PaddedLength k padTo lenBits) element)
    => BoolType (ByteString (PaddedLength k padTo lenBits) element)
    => Extend (ByteString k element) (ByteString (PaddedLength k padTo lenBits) element)
    => ByteString k element -> ByteString (PaddedLength k padTo lenBits) element
sha2Pad :: forall (padTo :: Natural) (lenBits :: Natural) (k :: Natural)
       element.
(KnownNat k, KnownNat (PaddedLength k padTo lenBits),
 FromConstant Natural element,
 ShiftBits (ByteString (PaddedLength k padTo lenBits) element),
 BoolType (ByteString (PaddedLength k padTo lenBits) element),
 Extend
   (ByteString k element)
   (ByteString (PaddedLength k padTo lenBits) element)) =>
ByteString k element
-> ByteString (PaddedLength k padTo lenBits) element
sha2Pad ByteString k element
bs = ByteString
  (If
     (OrdCond
        (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
        'True
        'True
        'False)
     (padTo + (padTo * Div ((k + padTo) - 1) padTo))
     (padTo * Div ((k + padTo) - 1) padTo))
  element
ByteString (PaddedLength k padTo lenBits) element
grown ByteString
  (If
     (OrdCond
        (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
        'True
        'True
        'False)
     (padTo + (padTo * Div ((k + padTo) - 1) padTo))
     (padTo * Div ((k + padTo) - 1) padTo))
  element
-> ByteString
     (If
        (OrdCond
           (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
           'True
           'True
           'False)
        (padTo + (padTo * Div ((k + padTo) - 1) padTo))
        (padTo * Div ((k + padTo) - 1) padTo))
     element
-> ByteString
     (If
        (OrdCond
           (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
           'True
           'True
           'False)
        (padTo + (padTo * Div ((k + padTo) - 1) padTo))
        (padTo * Div ((k + padTo) - 1) padTo))
     element
forall b. BoolType b => b -> b -> b
|| Natural
-> ByteString
     (If
        (OrdCond
           (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
           'True
           'True
           'False)
        (padTo + (padTo * Div ((k + padTo) - 1) padTo))
        (padTo * Div ((k + padTo) - 1) padTo))
     element
forall a b. FromConstant a b => a -> b
fromConstant Natural
padValue
    where
        l :: Natural
        l :: Natural
l = Proxy k -> Natural
forall (n :: Natural) (proxy :: Natural -> Type).
KnownNat n =>
proxy n -> Natural
natVal (Proxy k -> Natural) -> Proxy k -> Natural
forall a b. (a -> b) -> a -> b
$ forall (t :: Natural). Proxy t
forall {k} (t :: k). Proxy t
Proxy @k

        diff :: Natural
        diff :: Natural
diff = (Proxy
  (If
     (OrdCond
        (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
        'True
        'True
        'False)
     (padTo + (padTo * Div ((k + padTo) - 1) padTo))
     (padTo * Div ((k + padTo) - 1) padTo))
-> Natural
forall (n :: Natural) (proxy :: Natural -> Type).
KnownNat n =>
proxy n -> Natural
natVal (Proxy
   (If
      (OrdCond
         (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
         'True
         'True
         'False)
      (padTo + (padTo * Div ((k + padTo) - 1) padTo))
      (padTo * Div ((k + padTo) - 1) padTo))
 -> Natural)
-> Proxy
     (If
        (OrdCond
           (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
           'True
           'True
           'False)
        (padTo + (padTo * Div ((k + padTo) - 1) padTo))
        (padTo * Div ((k + padTo) - 1) padTo))
-> Natural
forall a b. (a -> b) -> a -> b
$ forall (t :: Natural). Proxy t
forall {k} (t :: k). Proxy t
Proxy @(PaddedLength k padTo lenBits)) Natural -> Natural -> Natural
-! (Proxy k -> Natural
forall (n :: Natural) (proxy :: Natural -> Type).
KnownNat n =>
proxy n -> Natural
natVal (Proxy k -> Natural) -> Proxy k -> Natural
forall a b. (a -> b) -> a -> b
$ forall (t :: Natural). Proxy t
forall {k} (t :: k). Proxy t
Proxy @k)

        padValue :: Natural
        padValue :: Natural
padValue = Natural
2 Natural -> Natural -> Natural
forall a b. (Num a, Integral b) => a -> b -> a
P.^ (Natural
diff Natural -> Natural -> Natural
-! Natural
1) Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.+ Natural
l

        grown :: ByteString (PaddedLength k padTo lenBits) element
        grown :: ByteString (PaddedLength k padTo lenBits) element
grown = ByteString k element
-> ByteString
     (If
        (OrdCond
           (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
           'True
           'True
           'False)
        (padTo + (padTo * Div ((k + padTo) - 1) padTo))
        (padTo * Div ((k + padTo) - 1) padTo))
     element
forall a b. Extend a b => a -> b
extend ByteString k element
bs ByteString
  (If
     (OrdCond
        (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
        'True
        'True
        'False)
     (padTo + (padTo * Div ((k + padTo) - 1) padTo))
     (padTo * Div ((k + padTo) - 1) padTo))
  element
-> Natural
-> ByteString
     (If
        (OrdCond
           (CmpNat ((padTo * Div ((k + padTo) - 1) padTo) - k) lenBits)
           'True
           'True
           'False)
        (padTo + (padTo * Div ((k + padTo) - 1) padTo))
        (padTo * Div ((k + padTo) - 1) padTo))
     element
forall a. ShiftBits a => a -> Natural -> a
`shiftBitsL` Natural
diff


-- | This allows us to calculate hash of a bytestring represented by a Natural number.
-- This is only useful for testing when the length of the test string is unknown at compile time.
-- This should not be exposed to users (and they probably won't find it useful anyway).
--
instance (KnownNat n, FromConstant Natural a) => ToWords Natural (ByteString n a) where
    toWords :: Natural -> [ByteString n a]
toWords = [ByteString n a] -> [ByteString n a]
forall a. [a] -> [a]
P.reverse ([ByteString n a] -> [ByteString n a])
-> (Natural -> [ByteString n a]) -> Natural -> [ByteString n a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Natural -> [ByteString n a]
toWords'
        where
            toWords' :: Natural -> [ByteString n a]
            toWords' :: Natural -> [ByteString n a]
toWords' Natural
0 = []
            toWords' Natural
n = Natural -> ByteString n a
forall a b. FromConstant a b => a -> b
fromConstant (Natural
n Natural -> Natural -> Natural
forall a. EuclideanDomain a => a -> a -> a
`mod` Natural
base) ByteString n a -> [ByteString n a] -> [ByteString n a]
forall a. a -> [a] -> [a]
: Natural -> [ByteString n a]
toWords' (Natural
n Natural -> Natural -> Natural
forall a. EuclideanDomain a => a -> a -> a
`div` Natural
base)

            base :: Natural
            base :: Natural
base = Natural
2 Natural -> Natural -> Natural
forall a b. (Num a, Integral b) => a -> b -> a
P.^ (forall (n :: Natural). KnownNat n => Natural
value @n)


-- | Constraints required for a SHA2 of a Natural number.
--
type SHA2N algorithm element =
   ( AlgorithmSetup algorithm element
   , Finite element
   , NFData element
   , FromConstant Natural element
   , KnownNat (ChunkSize algorithm)
   , KnownNat (WordSize algorithm)
   , Iso (UInt (WordSize algorithm) element) (ByteString (WordSize algorithm) element)
   , Iso (ByteString (WordSize algorithm) element) (UInt (WordSize algorithm) element)
   , AdditiveSemigroup (UInt (WordSize algorithm) element)
   , BoolType (ByteString (WordSize algorithm) element)
   , ShiftBits (ByteString (WordSize algorithm) element)
   , ToWords (ByteString (ChunkSize algorithm) element) (ByteString (WordSize algorithm) element)
   , Concat (ByteString (WordSize algorithm) element) (ByteString (8 * WordSize algorithm) element)
   )


-- | Same as @sha2@ but accepts a Natural number and length of message in bits instead of a ByteString.
-- Only used for testing.
--
sha2Natural
    :: forall (algorithm :: Symbol) element
    .  SHA2N algorithm element
    => Natural -> Natural -> ByteString (ResultSize algorithm) element
sha2Natural :: forall (algorithm :: Symbol) element.
SHA2N algorithm element =>
Natural -> Natural -> ByteString (ResultSize algorithm) element
sha2Natural Natural
numBits Natural
messageBits = forall (algorithm :: Symbol) element.
(AlgorithmSetup algorithm element, NFData element,
 Iso
   (ByteString (WordSize algorithm) element)
   (UInt (WordSize algorithm) element),
 AdditiveSemigroup (UInt (WordSize algorithm) element),
 BoolType (ByteString (WordSize algorithm) element),
 ShiftBits (ByteString (WordSize algorithm) element),
 ToWords
   (ByteString (ChunkSize algorithm) element)
   (ByteString (WordSize algorithm) element),
 Concat
   (ByteString (WordSize algorithm) element)
   (ByteString (8 * WordSize algorithm) element)) =>
[ByteString (ChunkSize algorithm) element]
-> ByteString (ResultSize algorithm) element
sha2Blocks @algorithm @element [ByteString (ChunkSize algorithm) element]
chunks
    where
        paddedMessage :: Natural
        paddedMessage :: Natural
paddedMessage = (Natural
messageBits Natural -> Int -> Natural
forall a. Bits a => a -> Int -> a
`shiftL` Int
diff) Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.+ (Natural
1 Natural -> Int -> Natural
forall a. Bits a => a -> Int -> a
`shiftL` (Int
diff Int -> Int -> Int
forall a. Num a => a -> a -> a
P.- Int
1)) Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.+ Natural
numBits

        chunkSize :: Natural
        chunkSize :: Natural
chunkSize = forall (n :: Natural). KnownNat n => Natural
value @(ChunkSize algorithm)

        wordSize :: Natural
        wordSize :: Natural
wordSize = forall (n :: Natural). KnownNat n => Natural
value @(WordSize algorithm)

        closestDivisor :: Natural
        closestDivisor :: Natural
closestDivisor = ((Natural
numBits Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.+ Natural
chunkSize Natural -> Natural -> Natural
-! Natural
1) Natural -> Natural -> Natural
forall a. EuclideanDomain a => a -> a -> a
`div` Natural
chunkSize) Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.* Natural
chunkSize

        paddedLength :: Natural
        paddedLength :: Natural
paddedLength
          | Natural
closestDivisor Natural -> Natural -> Natural
-! Natural
numBits Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
P.<= (Natural
2 Natural -> Natural -> Natural
forall a. MultiplicativeSemigroup a => a -> a -> a
* Natural
wordSize) = Natural
closestDivisor Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
P.+ Natural
chunkSize
          | Bool
P.otherwise = Natural
closestDivisor

        diff :: P.Int
        diff :: Int
diff = Natural -> Int
forall a b. (Integral a, Num b) => a -> b
P.fromIntegral (Natural -> Int) -> Natural -> Int
forall a b. (a -> b) -> a -> b
$ Natural
paddedLength Natural -> Natural -> Natural
-! Natural
numBits

        chunks :: [ByteString (ChunkSize algorithm) element]
        chunks :: [ByteString (ChunkSize algorithm) element]
chunks = Natural -> [ByteString (ChunkSize algorithm) element]
forall a b. ToWords a b => a -> [b]
toWords Natural
paddedMessage

-- | Internal loop of the SHA2 family algorithms.
--
-- A note on @force@: it is really necessary, otherwise the algorithm keeps piling up thunks.
-- Even 16 GB of RAM is not enough.
--
sha2Blocks
    :: forall algorithm element
    .  AlgorithmSetup algorithm element
    => NFData element
    => Iso (ByteString (WordSize algorithm) element) (UInt (WordSize algorithm) element)
    => AdditiveSemigroup (UInt (WordSize algorithm) element)
    => BoolType (ByteString (WordSize algorithm) element)
    => ShiftBits (ByteString (WordSize algorithm) element)
    => ToWords (ByteString (ChunkSize algorithm) element) (ByteString (WordSize algorithm) element)
    => Concat (ByteString (WordSize algorithm) element) (ByteString (8 * WordSize algorithm) element)
    => [ByteString (ChunkSize algorithm) element] -> ByteString (ResultSize algorithm) element
sha2Blocks :: forall (algorithm :: Symbol) element.
(AlgorithmSetup algorithm element, NFData element,
 Iso
   (ByteString (WordSize algorithm) element)
   (UInt (WordSize algorithm) element),
 AdditiveSemigroup (UInt (WordSize algorithm) element),
 BoolType (ByteString (WordSize algorithm) element),
 ShiftBits (ByteString (WordSize algorithm) element),
 ToWords
   (ByteString (ChunkSize algorithm) element)
   (ByteString (WordSize algorithm) element),
 Concat
   (ByteString (WordSize algorithm) element)
   (ByteString (8 * WordSize algorithm) element)) =>
[ByteString (ChunkSize algorithm) element]
-> ByteString (ResultSize algorithm) element
sha2Blocks [ByteString (ChunkSize algorithm) element]
chunks = forall (algorithm :: Symbol) a.
AlgorithmSetup algorithm a =>
ByteString (8 * WordSize algorithm) a
-> ByteString (ResultSize algorithm) a
truncateResult @algorithm @element (ByteString (8 * WordSize algorithm) element
 -> ByteString (ResultSize algorithm) element)
-> ByteString (8 * WordSize algorithm) element
-> ByteString (ResultSize algorithm) element
forall a b. (a -> b) -> a -> b
$ [ByteString (WordSize algorithm) element]
-> ByteString (8 * WordSize algorithm) element
forall a b. Concat a b => [a] -> b
concat ([ByteString (WordSize algorithm) element]
 -> ByteString (8 * WordSize algorithm) element)
-> [ByteString (WordSize algorithm) element]
-> ByteString (8 * WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ Vector (ByteString (WordSize algorithm) element)
-> [ByteString (WordSize algorithm) element]
forall a. Vector a -> [a]
V.toList Vector (ByteString (WordSize algorithm) element)
hashParts
    where
        rounds :: Int
        rounds :: Int
rounds = Vector (ByteString (WordSize algorithm) element) -> Int
forall a. Vector a -> Int
V.length (Vector (ByteString (WordSize algorithm) element) -> Int)
-> Vector (ByteString (WordSize algorithm) element) -> Int
forall a b. (a -> b) -> a -> b
$ forall (algorithm :: Symbol) a.
AlgorithmSetup algorithm a =>
Vector (ByteString (WordSize algorithm) a)
roundConstants @algorithm @element

        hashParts :: V.Vector (ByteString (WordSize algorithm) element)
        hashParts :: Vector (ByteString (WordSize algorithm) element)
hashParts = (forall s.
 ST s (MVector s (ByteString (WordSize algorithm) element)))
-> Vector (ByteString (WordSize algorithm) element)
forall a. (forall s. ST s (MVector s a)) -> Vector a
V.create ((forall s.
  ST s (MVector s (ByteString (WordSize algorithm) element)))
 -> Vector (ByteString (WordSize algorithm) element))
-> (forall s.
    ST s (MVector s (ByteString (WordSize algorithm) element)))
-> Vector (ByteString (WordSize algorithm) element)
forall a b. (a -> b) -> a -> b
$ do
            !MVector s (ByteString (WordSize algorithm) element)
hn <- Vector (ByteString (WordSize algorithm) element)
-> ST
     s
     (MVector
        (PrimState (ST s)) (ByteString (WordSize algorithm) element))
forall (m :: Type -> Type) a.
PrimMonad m =>
Vector a -> m (MVector (PrimState m) a)
V.thaw (Vector (ByteString (WordSize algorithm) element)
 -> ST
      s
      (MVector
         (PrimState (ST s)) (ByteString (WordSize algorithm) element)))
-> Vector (ByteString (WordSize algorithm) element)
-> ST
     s
     (MVector
        (PrimState (ST s)) (ByteString (WordSize algorithm) element))
forall a b. (a -> b) -> a -> b
$ forall (algorithm :: Symbol) a.
AlgorithmSetup algorithm a =>
Vector (ByteString (WordSize algorithm) a)
initialHashes @algorithm @element

            [ByteString (ChunkSize algorithm) element]
-> (ByteString (ChunkSize algorithm) element -> ST s ()) -> ST s ()
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [ByteString (ChunkSize algorithm) element]
chunks ((ByteString (ChunkSize algorithm) element -> ST s ()) -> ST s ())
-> (ByteString (ChunkSize algorithm) element -> ST s ()) -> ST s ()
forall a b. (a -> b) -> a -> b
$ \ByteString (ChunkSize algorithm) element
chunk -> do
                let words :: [ByteString (WordSize algorithm) element]
words = forall a b. ToWords a b => a -> [b]
toWords @(ByteString (ChunkSize algorithm) element) @(ByteString (WordSize algorithm) element) ByteString (ChunkSize algorithm) element
chunk
                MVector s (ByteString (WordSize algorithm) element)
messageSchedule <- forall (m :: Type -> Type) a.
PrimMonad m =>
Int -> m (MVector (PrimState m) a)
VM.unsafeNew @_ @(ByteString (WordSize algorithm) element) Int
rounds
                [(Int, ByteString (WordSize algorithm) element)]
-> ((Int, ByteString (WordSize algorithm) element) -> ST s ())
-> ST s ()
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ ([Int]
-> [ByteString (WordSize algorithm) element]
-> [(Int, ByteString (WordSize algorithm) element)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [ByteString (WordSize algorithm) element]
words) (((Int, ByteString (WordSize algorithm) element) -> ST s ())
 -> ST s ())
-> ((Int, ByteString (WordSize algorithm) element) -> ST s ())
-> ST s ()
forall a b. (a -> b) -> a -> b
$ \(Int
ix, ByteString (WordSize algorithm) element
w) -> MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ByteString (WordSize algorithm) element -> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> a -> m ()
VM.write MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
messageSchedule Int
ix ByteString (WordSize algorithm) element
w

                [Int] -> (Int -> ST s ()) -> ST s ()
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
16 .. Int
rounds Int -> Int -> Int
forall a. Num a => a -> a -> a
P.- Int
1] ((Int -> ST s ()) -> ST s ()) -> (Int -> ST s ()) -> ST s ()
forall a b. (a -> b) -> a -> b
$ \Int
ix -> do
                    !ByteString (WordSize algorithm) element
w16 <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
messageSchedule MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` (Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
P.- Int
16)
                    !ByteString (WordSize algorithm) element
w15 <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
messageSchedule MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` (Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
P.- Int
15)
                    !ByteString (WordSize algorithm) element
w7  <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
messageSchedule MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` (Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
P.- Int
7)
                    !ByteString (WordSize algorithm) element
w2  <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
messageSchedule MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` (Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
P.- Int
2)
                    let (Natural
sh0, Natural
sh1, Natural
sh2, Natural
sh3, Natural
sh4, Natural
sh5) = forall (algorithm :: Symbol) a.
AlgorithmSetup algorithm a =>
(Natural, Natural, Natural, Natural, Natural, Natural)
sigmaShifts @algorithm @element
                        s0 :: ByteString (WordSize algorithm) element
s0  = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ (ByteString (WordSize algorithm) element
w15 ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh0) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
w15 ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh1) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
w15 ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`shiftBitsR` Natural
sh2)
                        s1 :: ByteString (WordSize algorithm) element
s1  = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ (ByteString (WordSize algorithm) element
w2 ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh3) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
w2 ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh4) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
w2 ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`shiftBitsR` Natural
sh5)
                    MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ByteString (WordSize algorithm) element -> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> a -> m ()
VM.write MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
messageSchedule Int
ix (ByteString (WordSize algorithm) element -> ST s ())
-> ByteString (WordSize algorithm) element -> ST s ()
forall a b. (a -> b) -> a -> b
$! UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w16 UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
s0 UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w7 UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
s1 :: UInt (WordSize algorithm) element)

                !STRef s (ByteString (WordSize algorithm) element)
aRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
0 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef
                !STRef s (ByteString (WordSize algorithm) element)
bRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
1 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef
                !STRef s (ByteString (WordSize algorithm) element)
cRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
2 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef
                !STRef s (ByteString (WordSize algorithm) element)
dRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
3 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef
                !STRef s (ByteString (WordSize algorithm) element)
eRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
4 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef
                !STRef s (ByteString (WordSize algorithm) element)
fRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
5 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef
                !STRef s (ByteString (WordSize algorithm) element)
gRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
6 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef
                !STRef s (ByteString (WordSize algorithm) element)
hRef <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
7 ST s (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ST s (STRef s (ByteString (WordSize algorithm) element)))
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString (WordSize algorithm) element
-> ST s (STRef s (ByteString (WordSize algorithm) element))
forall a s. a -> ST s (STRef s a)
ST.newSTRef

                [Int] -> (Int -> ST s ()) -> ST s ()
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
0 .. Int
rounds Int -> Int -> Int
forall a. Num a => a -> a -> a
P.- Int
1] ((Int -> ST s ()) -> ST s ()) -> (Int -> ST s ()) -> ST s ()
forall a b. (a -> b) -> a -> b
$ \Int
ix -> do
                    !ByteString (WordSize algorithm) element
a <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
aRef
                    !ByteString (WordSize algorithm) element
b <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
bRef
                    !ByteString (WordSize algorithm) element
c <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
cRef
                    !ByteString (WordSize algorithm) element
d <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
dRef
                    !ByteString (WordSize algorithm) element
e <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
eRef
                    !ByteString (WordSize algorithm) element
f <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
fRef
                    !ByteString (WordSize algorithm) element
g <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
gRef
                    !ByteString (WordSize algorithm) element
h <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
hRef

                    let ki :: ByteString (WordSize algorithm) element
ki = forall (algorithm :: Symbol) a.
AlgorithmSetup algorithm a =>
Vector (ByteString (WordSize algorithm) a)
roundConstants @algorithm @element Vector (ByteString (WordSize algorithm) element)
-> Int -> ByteString (WordSize algorithm) element
forall a. Vector a -> Int -> a
V.! Int
ix
                    ByteString (WordSize algorithm) element
wi <- MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
messageSchedule MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> Int -> ST s (ByteString (WordSize algorithm) element)
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> Int -> m a
`VM.read` Int
ix

                    let (Natural
sh0, Natural
sh1, Natural
sh2, Natural
sh3, Natural
sh4, Natural
sh5) = forall (algorithm :: Symbol) a.
AlgorithmSetup algorithm a =>
(Natural, Natural, Natural, Natural, Natural, Natural)
sumShifts @algorithm @element
                        s1 :: ByteString (WordSize algorithm) element
s1    = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ (ByteString (WordSize algorithm) element
e ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh3) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
e ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh4) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
e ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh5)
                        ch :: ByteString (WordSize algorithm) element
ch    = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ (ByteString (WordSize algorithm) element
e ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
&& ByteString (WordSize algorithm) element
f) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b
not ByteString (WordSize algorithm) element
e ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
&& ByteString (WordSize algorithm) element
g)
                        temp1 :: ByteString (WordSize algorithm) element
temp1 = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
h UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
s1 UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
ch UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
ki UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
wi :: UInt (WordSize algorithm) element) :: ByteString (WordSize algorithm) element
                        s0 :: ByteString (WordSize algorithm) element
s0    = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ (ByteString (WordSize algorithm) element
a ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh0) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
a ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh1) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
a ByteString (WordSize algorithm) element
-> Natural -> ByteString (WordSize algorithm) element
forall a. ShiftBits a => a -> Natural -> a
`rotateBitsR` Natural
sh2)
                        maj :: ByteString (WordSize algorithm) element
maj   = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ (ByteString (WordSize algorithm) element
a ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
&& ByteString (WordSize algorithm) element
b) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
a ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
&& ByteString (WordSize algorithm) element
c) ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
`xor` (ByteString (WordSize algorithm) element
b ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall b. BoolType b => b -> b -> b
&& ByteString (WordSize algorithm) element
c)
                        temp2 :: ByteString (WordSize algorithm) element
temp2 = ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a. NFData a => a -> a
force (ByteString (WordSize algorithm) element
 -> ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. (a -> b) -> a -> b
$ UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
s0 UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
maj :: UInt (WordSize algorithm) element) :: ByteString (WordSize algorithm) element

                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
hRef ByteString (WordSize algorithm) element
g
                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
gRef ByteString (WordSize algorithm) element
f
                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
fRef ByteString (WordSize algorithm) element
e
                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
eRef (ByteString (WordSize algorithm) element -> ST s ())
-> ByteString (WordSize algorithm) element -> ST s ()
forall a b. (a -> b) -> a -> b
$ UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
d UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
temp1 :: UInt (WordSize algorithm) element)
                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
dRef ByteString (WordSize algorithm) element
c
                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
cRef ByteString (WordSize algorithm) element
b
                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
bRef ByteString (WordSize algorithm) element
a
                    STRef s (ByteString (WordSize algorithm) element)
-> ByteString (WordSize algorithm) element -> ST s ()
forall s a. STRef s a -> a -> ST s ()
ST.writeSTRef STRef s (ByteString (WordSize algorithm) element)
aRef (ByteString (WordSize algorithm) element -> ST s ())
-> ByteString (WordSize algorithm) element -> ST s ()
forall a b. (a -> b) -> a -> b
$ UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
temp1 UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
temp2 :: UInt (WordSize algorithm) element)

                !ByteString (WordSize algorithm) element
a <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
aRef
                !ByteString (WordSize algorithm) element
b <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
bRef
                !ByteString (WordSize algorithm) element
c <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
cRef
                !ByteString (WordSize algorithm) element
d <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
dRef
                !ByteString (WordSize algorithm) element
e <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
eRef
                !ByteString (WordSize algorithm) element
f <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
fRef
                !ByteString (WordSize algorithm) element
g <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
gRef
                !ByteString (WordSize algorithm) element
h <- STRef s (ByteString (WordSize algorithm) element)
-> ST s (ByteString (WordSize algorithm) element)
forall s a. STRef s a -> ST s a
ST.readSTRef STRef s (ByteString (WordSize algorithm) element)
hRef

                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
a :: UInt (WordSize algorithm) element)) Int
0
                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
b :: UInt (WordSize algorithm) element)) Int
1
                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
c :: UInt (WordSize algorithm) element)) Int
2
                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
d :: UInt (WordSize algorithm) element)) Int
3
                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
e :: UInt (WordSize algorithm) element)) Int
4
                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
f :: UInt (WordSize algorithm) element)) Int
5
                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
g :: UInt (WordSize algorithm) element)) Int
6
                MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
-> (ByteString (WordSize algorithm) element
    -> ByteString (WordSize algorithm) element)
-> Int
-> ST s ()
forall (m :: Type -> Type) a.
PrimMonad m =>
MVector (PrimState m) a -> (a -> a) -> Int -> m ()
VM.modify MVector s (ByteString (WordSize algorithm) element)
MVector
  (PrimState (ST s)) (ByteString (WordSize algorithm) element)
hn (\ByteString (WordSize algorithm) element
w -> UInt (WordSize algorithm) element
-> ByteString (WordSize algorithm) element
forall a b. Iso a b => a -> b
from (ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
w UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a. AdditiveSemigroup a => a -> a -> a
+ ByteString (WordSize algorithm) element
-> UInt (WordSize algorithm) element
forall a b. Iso a b => a -> b
from ByteString (WordSize algorithm) element
h :: UInt (WordSize algorithm) element)) Int
7

            MVector s (ByteString (WordSize algorithm) element)
-> ST s (MVector s (ByteString (WordSize algorithm) element))
forall a. a -> ST s a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure MVector s (ByteString (WordSize algorithm) element)
hn