    -- |
    -- Module      : Crypto.Store.Cipher.RC2.Primitive
    -- License     : BSD-style
    -- Maintainer  : Olivier Chéron <olivier.cheron@gmail.com>
    -- Stability   : stable
    -- Portability : good
    --
    {-# LANGUAGE Rank2Types #-}
    module Crypto.Store.Cipher.RC2.Primitive
        ( Key
        , buildKey
        , encrypt
        , decrypt
        ) where

    import Basement.Block
    import Basement.Compat.IsList
    import Basement.Endianness
    import Basement.Types.OffsetSize

    import Control.Monad (forM_)

    import           Data.Bits
    import           Data.ByteArray (ByteArrayAccess)
    import qualified Data.ByteArray as B
    import           Data.Word

    import Foreign.Storable

    -- | Expanded RC2 key
    newtype Key = Key (Block Word16) -- [ K[0], K[1], ..., K[63] ]

    data Q = Q {-# UNPACK #-} !Word16 {-# UNPACK #-} !Word16
               {-# UNPACK #-} !Word16 {-# UNPACK #-} !Word16

    -- Utilities

    decomp64 :: Word64 -> Q
    decomp64 :: Word64 -> Q
    decomp64 Word64
    x =
        let d :: Word16
    d = Word64 -> Word16
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    48)
            c :: Word16
    c = Word64 -> Word16
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    32)
            b :: Word16
    b = Word64 -> Word16
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    16)
            a :: Word16
    a = Word64 -> Word16
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral  Word64
    x
        in Word16 -> Word16 -> Word16 -> Word16 -> Q
    Q Word16
    a Word16
    b Word16
    c Word16
    d

    comp64 :: Q -> Word64
    comp64 :: Q -> Word64
    comp64 (Q Word16
    a Word16
    b Word16
    c Word16
    d) =
        (Word16 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    d Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    48) Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|.
        (Word16 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    c Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    32) Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|.
        (Word16 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    b Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    16) Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|.
         Word16 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    a

    getR :: Q -> Word8 -> Word16
    getR :: Q -> Word8 -> Word16
    getR (Q Word16
    a Word16
    b Word16
    c Word16
    d) Word8
    i =
        case Word8
    i Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .&. Word8
    3 of
            Word8
    0 -> Word16
    a
            Word8
    1 -> Word16
    b
            Word8
    2 -> Word16
    c
            Word8
    _ -> Word16
    d
    {-# INLINE getR #-}

    setR :: Q -> Word8 -> Word16 -> Q
    setR :: Q -> Word8 -> Word16 -> Q
    setR (Q Word16
    a Word16
    b Word16
    c Word16
    d) Word8
    i Word16
    x =
        case Word8
    i Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .&. Word8
    3 of
            Word8
    0 -> Word16 -> Word16 -> Word16 -> Word16 -> Q
    Q Word16
    x Word16
    b Word16
    c Word16
    d
            Word8
    1 -> Word16 -> Word16 -> Word16 -> Word16 -> Q
    Q Word16
    a Word16
    x Word16
    c Word16
    d
            Word8
    2 -> Word16 -> Word16 -> Word16 -> Word16 -> Q
    Q Word16
    a Word16
    b Word16
    x Word16
    d
            Word8
    _ -> Word16 -> Word16 -> Word16 -> Word16 -> Q
    Q Word16
    a Word16
    b Word16
    c Word16
    x
    {-# INLINE setR #-}

    rol :: Word8 -> Word16 -> Word16
    rol :: Word8 -> Word16 -> Word16
    rol Word8
    i =
        case Word8
    i Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .&. Word8
    3 of
            Word8
    0 -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateL Int
    1
            Word8
    1 -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateL Int
    2
            Word8
    2 -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateL Int
    3
            Word8
    _ -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateL Int
    5
    {-# INLINE rol #-}

    ror :: Word8 -> Word16 -> Word16
    ror :: Word8 -> Word16 -> Word16
    ror Word8
    i =
        case Word8
    i Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .&. Word8
    3 of
            Word8
    0 -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateR Int
    1
            Word8
    1 -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateR Int
    2
            Word8
    2 -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateR Int
    3
            Word8
    _ -> (Word16 -> Int -> Word16) -> Int -> Word16 -> Word16
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Word16 -> Int -> Word16
    forall a. Bits a => a -> Int -> a
    rotateR Int
    5
    {-# INLINE ror #-}

    f5 :: (a -> a) -> a -> a
    f5 :: forall a. (a -> a) -> a -> a
    f5 a -> a
    f = a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f

    f6 :: (a -> a) -> a -> a
    f6 :: forall a. (a -> a) -> a -> a
    f6 a -> a
    f = a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> a
    f

    -- Encryption

    -- | Encrypts a block using the specified key
    encrypt :: Key -> Word64 -> Word64
    encrypt :: Key -> Word64 -> Word64
    encrypt Key
    k = Q -> Word64
    comp64 (Q -> Word64) -> (Word64 -> Q) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Q -> Q
    enc Key
    k (Q -> Q) -> (Word64 -> Q) -> Word64 -> Q
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Q
    decomp64

    enc :: Key -> Q -> Q
    enc :: Key -> Q -> Q
    enc Key
    k Q
    r =
        (Q, Int) -> Q
    forall a b. (a, b) -> a
    fst ((Q, Int) -> Q) -> (Q, Int) -> Q
    forall a b. (a -> b) -> a -> b
    $ ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a. (a -> a) -> a -> a
    f5 (Key -> (Q, Int) -> (Q, Int)
    mixingRound Key
    k) ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ Key -> (Q, Int) -> (Q, Int)
    mashingRound Key
    k
            ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a. (a -> a) -> a -> a
    f6 (Key -> (Q, Int) -> (Q, Int)
    mixingRound Key
    k) ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ Key -> (Q, Int) -> (Q, Int)
    mashingRound Key
    k
            ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a. (a -> a) -> a -> a
    f5 (Key -> (Q, Int) -> (Q, Int)
    mixingRound Key
    k) (Q
    r, Int
    0)

    -- Decryption

    -- | Decrypts a block using the specified key
    decrypt :: Key -> Word64 -> Word64
    decrypt :: Key -> Word64 -> Word64
    decrypt Key
    k = Q -> Word64
    comp64 (Q -> Word64) -> (Word64 -> Q) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Q -> Q
    dec Key
    k (Q -> Q) -> (Word64 -> Q) -> Word64 -> Q
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Q
    decomp64

    dec :: Key -> Q -> Q
    dec :: Key -> Q -> Q
    dec Key
    k Q
    r =
        (Q, Int) -> Q
    forall a b. (a, b) -> a
    fst ((Q, Int) -> Q) -> (Q, Int) -> Q
    forall a b. (a -> b) -> a -> b
    $ ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a. (a -> a) -> a -> a
    f5 (Key -> (Q, Int) -> (Q, Int)
    rmixingRound Key
    k) ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ Key -> (Q, Int) -> (Q, Int)
    rmashingRound Key
    k
            ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a. (a -> a) -> a -> a
    f6 (Key -> (Q, Int) -> (Q, Int)
    rmixingRound Key
    k) ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ Key -> (Q, Int) -> (Q, Int)
    rmashingRound Key
    k
            ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a. (a -> a) -> a -> a
    f5 (Key -> (Q, Int) -> (Q, Int)
    rmixingRound Key
    k) (Q
    r, Int
    63)

    -- Encryptiong rounds

    mixUp :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    mixUp :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    mixUp Key
    k Word8
    i input :: (Q, Int)
    input@(Q
    r, Int
    j) = Q -> (Q, Int) -> (Q, Int)
    forall a b. a -> b -> b
    seq Q
    r' ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ Int -> (Q, Int) -> (Q, Int)
    forall a b. a -> b -> b
    seq Int
    j' (Q
    r', Int
    j')
      where j' :: Int
    j' = Int
    j Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1
            r' :: Q
    r' = Q -> Word8 -> Word16 -> Q
    setR Q
    r Word8
    i (Word8 -> Word16 -> Word16
    rol Word8
    i (Word16
    ri Word16 -> Word16 -> Word16
    forall a. Num a => a -> a -> a
    + Key -> Word8 -> (Q, Int) -> Word16
    gmix Key
    k Word8
    i (Q, Int)
    input))
            ri :: Word16
    ri = Q -> Word8 -> Word16
    getR Q
    r Word8
    i
    {-# INLINE mixUp #-}

    mixingRound :: Key -> (Q, Int) -> (Q, Int)
    mixingRound :: Key -> (Q, Int) -> (Q, Int)
    mixingRound Key
    k = Key -> Word8 -> (Q, Int) -> (Q, Int)
    mixUp Key
    k Word8
    3 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    mixUp Key
    k Word8
    2 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    mixUp Key
    k Word8
    1 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    mixUp Key
    k Word8
    0

    mash :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    mash :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    mash = (Word16 -> Word16 -> Word16)
    -> Key -> Word8 -> (Q, Int) -> (Q, Int)
    gmash Word16 -> Word16 -> Word16
    forall a. Num a => a -> a -> a
    (+)
    {-# INLINE mash #-}

    mashingRound :: Key -> (Q, Int) -> (Q, Int)
    mashingRound :: Key -> (Q, Int) -> (Q, Int)
    mashingRound Key
    k = Key -> Word8 -> (Q, Int) -> (Q, Int)
    mash Key
    k Word8
    3 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    mash Key
    k Word8
    2 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    mash Key
    k Word8
    1 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    mash Key
    k Word8
    0

    -- Decryption rounds

    rmixUp :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmixUp :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmixUp Key
    k Word8
    i input :: (Q, Int)
    input@(Q
    r, Int
    j) = Q -> (Q, Int) -> (Q, Int)
    forall a b. a -> b -> b
    seq Q
    r' ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ Int -> (Q, Int) -> (Q, Int)
    forall a b. a -> b -> b
    seq Int
    j' (Q
    r', Int
    j')
      where j' :: Int
    j' = Int
    j Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1
            r' :: Q
    r' = Q -> Word8 -> Word16 -> Q
    setR Q
    r Word8
    i (Word16
    ri Word16 -> Word16 -> Word16
    forall a. Num a => a -> a -> a
    - Key -> Word8 -> (Q, Int) -> Word16
    gmix Key
    k Word8
    i (Q, Int)
    input)
            ri :: Word16
    ri = Word8 -> Word16 -> Word16
    ror Word8
    i (Q -> Word8 -> Word16
    getR Q
    r Word8
    i)
    {-# INLINE rmixUp #-}

    rmixingRound :: Key -> (Q, Int) -> (Q, Int)
    rmixingRound :: Key -> (Q, Int) -> (Q, Int)
    rmixingRound Key
    k = Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmixUp Key
    k Word8
    0 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmixUp Key
    k Word8
    1 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmixUp Key
    k Word8
    2 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmixUp Key
    k Word8
    3

    rmash :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmash :: Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmash = (Word16 -> Word16 -> Word16)
    -> Key -> Word8 -> (Q, Int) -> (Q, Int)
    gmash (-)
    {-# INLINE rmash #-}

    rmashingRound :: Key -> (Q, Int) -> (Q, Int)
    rmashingRound :: Key -> (Q, Int) -> (Q, Int)
    rmashingRound Key
    k = Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmash Key
    k Word8
    0 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmash Key
    k Word8
    1 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmash Key
    k Word8
    2 ((Q, Int) -> (Q, Int))
    -> ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Key -> Word8 -> (Q, Int) -> (Q, Int)
    rmash Key
    k Word8
    3

    -- Generic rounds

    gmix :: Key -> Word8 -> (Q, Int) -> Word16
    gmix :: Key -> Word8 -> (Q, Int) -> Word16
    gmix (Key Block Word16
    k) Word8
    i (Q
    r, Int
    j) = Word16
    kj Word16 -> Word16 -> Word16
    forall a. Num a => a -> a -> a
    + (Word16
    ri1 Word16 -> Word16 -> Word16
    forall a. Bits a => a -> a -> a
    .&. Word16
    ri2) Word16 -> Word16 -> Word16
    forall a. Num a => a -> a -> a
    + (Word16 -> Word16
    forall a. Bits a => a -> a
    complement Word16
    ri1 Word16 -> Word16 -> Word16
    forall a. Bits a => a -> a -> a
    .&. Word16
    ri3)
      where ri1 :: Word16
    ri1 = Q -> Word8 -> Word16
    getR Q
    r (Word8
    i Word8 -> Word8 -> Word8
    forall a. Num a => a -> a -> a
    - Word8
    1)
            ri2 :: Word16
    ri2 = Q -> Word8 -> Word16
    getR Q
    r (Word8
    i Word8 -> Word8 -> Word8
    forall a. Num a => a -> a -> a
    - Word8
    2)
            ri3 :: Word16
    ri3 = Q -> Word8 -> Word16
    getR Q
    r (Word8
    i Word8 -> Word8 -> Word8
    forall a. Num a => a -> a -> a
    - Word8
    3)
            kj :: Word16
    kj  = Block Word16 -> Offset Word16 -> Word16
    forall ty. PrimType ty => Block ty -> Offset ty -> ty
    unsafeIndex Block Word16
    k (Int -> Offset Word16
    forall ty. Int -> Offset ty
    Offset Int
    j)
    {-# INLINE gmix #-}

    gmash :: (Word16 -> Word16 -> Word16)
          -> Key -> Word8 -> (Q, Int) -> (Q, Int)
    gmash :: (Word16 -> Word16 -> Word16)
    -> Key -> Word8 -> (Q, Int) -> (Q, Int)
    gmash Word16 -> Word16 -> Word16
    op (Key Block Word16
    k) Word8
    i (Q
    r, Int
    j) = Q -> (Q, Int) -> (Q, Int)
    forall a b. a -> b -> b
    seq Q
    r' ((Q, Int) -> (Q, Int)) -> (Q, Int) -> (Q, Int)
    forall a b. (a -> b) -> a -> b
    $ Int -> (Q, Int) -> (Q, Int)
    forall a b. a -> b -> b
    seq Int
    j (Q
    r', Int
    j)
      where r' :: Q
    r'  = Q -> Word8 -> Word16 -> Q
    setR Q
    r Word8
    i (Word16
    ri Word16 -> Word16 -> Word16
    `op` Word16
    kp)
            ri :: Word16
    ri  = Q -> Word8 -> Word16
    getR Q
    r Word8
    i
            ri1 :: Word16
    ri1 = Q -> Word8 -> Word16
    getR Q
    r (Word8
    i Word8 -> Word8 -> Word8
    forall a. Num a => a -> a -> a
    - Word8
    1)
            kp :: Word16
    kp  = Block Word16 -> Offset Word16 -> Word16
    forall ty. PrimType ty => Block ty -> Offset ty -> ty
    unsafeIndex Block Word16
    k (Offset Word16 -> Word16) -> Offset Word16 -> Word16
    forall a b. (a -> b) -> a -> b
    $ Int -> Offset Word16
    forall ty. Int -> Offset ty
    Offset (Word16 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    ri1 Int -> Int -> Int
    forall a. Bits a => a -> a -> a
    .&. Int
    63)
    {-# INLINE gmash #-}

    -- Key expansion

    -- | Perform key expansion
    buildKey :: ByteArrayAccess key
             => Int    -- ^ Effective key length in bits
             -> key    -- ^ Input key between 1 and 128 bytes
             -> Key    -- ^ Expanded key
    buildKey :: forall key. ByteArrayAccess key => Int -> key -> Key
    buildKey Int
    t1 key
    key = Block Word16 -> Key
    Key (Block Word16 -> Key) -> Block Word16 -> Key
    forall a b. (a -> b) -> a -> b
    $ Block Word8 -> Block Word16
    doCast (Block Word8 -> Block Word16) -> Block Word8 -> Block Word16
    forall a b. (a -> b) -> a -> b
    $ Int -> (Ptr Word8 -> IO ()) -> Block Word8
    forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
    B.allocAndFreeze Int
    128 ((Ptr Word8 -> IO ()) -> Block Word8)
    -> (Ptr Word8 -> IO ()) -> Block Word8
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    p -> do
        key -> Ptr Word8 -> IO ()
    forall p. key -> Ptr p -> IO ()
    forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
    B.copyByteArrayToPtr key
    key Ptr Word8
    p

        [Int] -> (Int -> IO ()) -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ [Int
    t .. Int
    127] ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    i -> do
            Word8
    pos <- Word8 -> Word8 -> Word8
    forall a. Num a => a -> a -> a
    (+) (Word8 -> Word8 -> Word8) -> IO Word8 -> IO (Word8 -> Word8)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr Word8 -> Int -> IO Word8
    forall a. Storable a => Ptr a -> Int -> IO a
    peekElemOff Ptr Word8
    p (Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) IO (Word8 -> Word8) -> IO Word8 -> IO Word8
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Ptr Word8 -> Int -> IO Word8
    forall a. Storable a => Ptr a -> Int -> IO a
    peekElemOff Ptr Word8
    p (Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    t)
            let b :: Word8
    b = Block Word8 -> Offset Word8 -> Word8
    forall ty. PrimType ty => Block ty -> Offset ty -> ty
    unsafeIndex Block Word8
    piTable (Word8 -> Offset Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    pos)
            Ptr Word8 -> Int -> Word8 -> IO ()
    forall a. Storable a => Ptr a -> Int -> a -> IO ()
    pokeElemOff Ptr Word8
    p Int
    i Word8
    b

        Word8
    pos' <- (Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    .&. Word8
    tm) (Word8 -> Word8) -> IO Word8 -> IO Word8
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr Word8 -> Int -> IO Word8
    forall a. Storable a => Ptr a -> Int -> IO a
    peekElemOff Ptr Word8
    p (Int
    128 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    t8)
        let b' :: Word8
    b' = Block Word8 -> Offset Word8 -> Word8
    forall ty. PrimType ty => Block ty -> Offset ty -> ty
    unsafeIndex Block Word8
    piTable (Word8 -> Offset Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    pos')
        Ptr Word8 -> Int -> Word8 -> IO ()
    forall a. Storable a => Ptr a -> Int -> a -> IO ()
    pokeElemOff Ptr Word8
    p (Int
    128 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    t8) Word8
    b'

        [Int] -> (Int -> IO ()) -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ ([Int] -> [Int]
    forall a. [a] -> [a]
    Prelude.reverse [Int
    0 .. Int
    127 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    t8]) ((Int -> IO ()) -> IO ()) -> (Int -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Int
    i -> do
            Word8
    pos <- Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    xor (Word8 -> Word8 -> Word8) -> IO Word8 -> IO (Word8 -> Word8)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr Word8 -> Int -> IO Word8
    forall a. Storable a => Ptr a -> Int -> IO a
    peekElemOff Ptr Word8
    p (Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) IO (Word8 -> Word8) -> IO Word8 -> IO Word8
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Ptr Word8 -> Int -> IO Word8
    forall a. Storable a => Ptr a -> Int -> IO a
    peekElemOff Ptr Word8
    p (Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    t8)
            let b :: Word8
    b = Block Word8 -> Offset Word8 -> Word8
    forall ty. PrimType ty => Block ty -> Offset ty -> ty
    unsafeIndex Block Word8
    piTable (Word8 -> Offset Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    pos)
            Ptr Word8 -> Int -> Word8 -> IO ()
    forall a. Storable a => Ptr a -> Int -> a -> IO ()
    pokeElemOff Ptr Word8
    p Int
    i Word8
    b

      where t :: Int
    t  = key -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length key
    key
            t8 :: Int
    t8 = (Int
    t1 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    7) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    8
            tm :: Word8
    tm | Int
    t1 Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    8 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    t8 = Word8
    255
               | Bool
    otherwise    = Word8
    255 Word8 -> Word8 -> Word8
    forall a. Integral a => a -> a -> a
    `mod` Word8 -> Int -> Word8
    forall a. Bits a => a -> Int -> a
    shiftL Word8
    1 (Int
    8 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    t1 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    8 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    t8)

            doCast :: Block Word8 -> Block Word16
            doCast :: Block Word8 -> Block Word16
    doCast = (LE Word16 -> Word16) -> Block (LE Word16) -> Block Word16
    forall a b.
    (PrimType a, PrimType b) =>
    (a -> b) -> Block a -> Block b
    Basement.Block.map LE Word16 -> Word16
    forall a. ByteSwap a => LE a -> a
    fromLE (Block (LE Word16) -> Block Word16)
    -> (Block Word8 -> Block (LE Word16))
    -> Block Word8
    -> Block Word16
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Block Word8 -> Block (LE Word16)
    forall a b. (PrimType a, PrimType b) => Block a -> Block b
    cast

    -- PITABLE

    piTable :: Block Word8
    piTable :: Block Word8
    piTable = [Item (Block Word8)] -> Block Word8
    forall l. IsList l => [Item l] -> l
    fromList
        [ Word8
    Item (Block Word8)
    0xd9, Word8
    Item (Block Word8)
    0x78, Word8
    Item (Block Word8)
    0xf9, Word8
    Item (Block Word8)
    0xc4, Word8
    Item (Block Word8)
    0x19, Word8
    Item (Block Word8)
    0xdd, Word8
    Item (Block Word8)
    0xb5, Word8
    Item (Block Word8)
    0xed, Word8
    Item (Block Word8)
    0x28, Word8
    Item (Block Word8)
    0xe9, Word8
    Item (Block Word8)
    0xfd, Word8
    Item (Block Word8)
    0x79, Word8
    Item (Block Word8)
    0x4a, Word8
    Item (Block Word8)
    0xa0, Word8
    Item (Block Word8)
    0xd8, Word8
    Item (Block Word8)
    0x9d
        , Word8
    Item (Block Word8)
    0xc6, Word8
    Item (Block Word8)
    0x7e, Word8
    Item (Block Word8)
    0x37, Word8
    Item (Block Word8)
    0x83, Word8
    Item (Block Word8)
    0x2b, Word8
    Item (Block Word8)
    0x76, Word8
    Item (Block Word8)
    0x53, Word8
    Item (Block Word8)
    0x8e, Word8
    Item (Block Word8)
    0x62, Word8
    Item (Block Word8)
    0x4c, Word8
    Item (Block Word8)
    0x64, Word8
    Item (Block Word8)
    0x88, Word8
    Item (Block Word8)
    0x44, Word8
    Item (Block Word8)
    0x8b, Word8
    Item (Block Word8)
    0xfb, Word8
    Item (Block Word8)
    0xa2
        , Word8
    Item (Block Word8)
    0x17, Word8
    Item (Block Word8)
    0x9a, Word8
    Item (Block Word8)
    0x59, Word8
    Item (Block Word8)
    0xf5, Word8
    Item (Block Word8)
    0x87, Word8
    Item (Block Word8)
    0xb3, Word8
    Item (Block Word8)
    0x4f, Word8
    Item (Block Word8)
    0x13, Word8
    Item (Block Word8)
    0x61, Word8
    Item (Block Word8)
    0x45, Word8
    Item (Block Word8)
    0x6d, Word8
    Item (Block Word8)
    0x8d, Word8
    Item (Block Word8)
    0x09, Word8
    Item (Block Word8)
    0x81, Word8
    Item (Block Word8)
    0x7d, Word8
    Item (Block Word8)
    0x32
        , Word8
    Item (Block Word8)
    0xbd, Word8
    Item (Block Word8)
    0x8f, Word8
    Item (Block Word8)
    0x40, Word8
    Item (Block Word8)
    0xeb, Word8
    Item (Block Word8)
    0x86, Word8
    Item (Block Word8)
    0xb7, Word8
    Item (Block Word8)
    0x7b, Word8
    Item (Block Word8)
    0x0b, Word8
    Item (Block Word8)
    0xf0, Word8
    Item (Block Word8)
    0x95, Word8
    Item (Block Word8)
    0x21, Word8
    Item (Block Word8)
    0x22, Word8
    Item (Block Word8)
    0x5c, Word8
    Item (Block Word8)
    0x6b, Word8
    Item (Block Word8)
    0x4e, Word8
    Item (Block Word8)
    0x82
        , Word8
    Item (Block Word8)
    0x54, Word8
    Item (Block Word8)
    0xd6, Word8
    Item (Block Word8)
    0x65, Word8
    Item (Block Word8)
    0x93, Word8
    Item (Block Word8)
    0xce, Word8
    Item (Block Word8)
    0x60, Word8
    Item (Block Word8)
    0xb2, Word8
    Item (Block Word8)
    0x1c, Word8
    Item (Block Word8)
    0x73, Word8
    Item (Block Word8)
    0x56, Word8
    Item (Block Word8)
    0xc0, Word8
    Item (Block Word8)
    0x14, Word8
    Item (Block Word8)
    0xa7, Word8
    Item (Block Word8)
    0x8c, Word8
    Item (Block Word8)
    0xf1, Word8
    Item (Block Word8)
    0xdc
        , Word8
    Item (Block Word8)
    0x12, Word8
    Item (Block Word8)
    0x75, Word8
    Item (Block Word8)
    0xca, Word8
    Item (Block Word8)
    0x1f, Word8
    Item (Block Word8)
    0x3b, Word8
    Item (Block Word8)
    0xbe, Word8
    Item (Block Word8)
    0xe4, Word8
    Item (Block Word8)
    0xd1, Word8
    Item (Block Word8)
    0x42, Word8
    Item (Block Word8)
    0x3d, Word8
    Item (Block Word8)
    0xd4, Word8
    Item (Block Word8)
    0x30, Word8
    Item (Block Word8)
    0xa3, Word8
    Item (Block Word8)
    0x3c, Word8
    Item (Block Word8)
    0xb6, Word8
    Item (Block Word8)
    0x26
        , Word8
    Item (Block Word8)
    0x6f, Word8
    Item (Block Word8)
    0xbf, Word8
    Item (Block Word8)
    0x0e, Word8
    Item (Block Word8)
    0xda, Word8
    Item (Block Word8)
    0x46, Word8
    Item (Block Word8)
    0x69, Word8
    Item (Block Word8)
    0x07, Word8
    Item (Block Word8)
    0x57, Word8
    Item (Block Word8)
    0x27, Word8
    Item (Block Word8)
    0xf2, Word8
    Item (Block Word8)
    0x1d, Word8
    Item (Block Word8)
    0x9b, Word8
    Item (Block Word8)
    0xbc, Word8
    Item (Block Word8)
    0x94, Word8
    Item (Block Word8)
    0x43, Word8
    Item (Block Word8)
    0x03
        , Word8
    Item (Block Word8)
    0xf8, Word8
    Item (Block Word8)
    0x11, Word8
    Item (Block Word8)
    0xc7, Word8
    Item (Block Word8)
    0xf6, Word8
    Item (Block Word8)
    0x90, Word8
    Item (Block Word8)
    0xef, Word8
    Item (Block Word8)
    0x3e, Word8
    Item (Block Word8)
    0xe7, Word8
    Item (Block Word8)
    0x06, Word8
    Item (Block Word8)
    0xc3, Word8
    Item (Block Word8)
    0xd5, Word8
    Item (Block Word8)
    0x2f, Word8
    Item (Block Word8)
    0xc8, Word8
    Item (Block Word8)
    0x66, Word8
    Item (Block Word8)
    0x1e, Word8
    Item (Block Word8)
    0xd7
        , Word8
    Item (Block Word8)
    0x08, Word8
    Item (Block Word8)
    0xe8, Word8
    Item (Block Word8)
    0xea, Word8
    Item (Block Word8)
    0xde, Word8
    Item (Block Word8)
    0x80, Word8
    Item (Block Word8)
    0x52, Word8
    Item (Block Word8)
    0xee, Word8
    Item (Block Word8)
    0xf7, Word8
    Item (Block Word8)
    0x84, Word8
    Item (Block Word8)
    0xaa, Word8
    Item (Block Word8)
    0x72, Word8
    Item (Block Word8)
    0xac, Word8
    Item (Block Word8)
    0x35, Word8
    Item (Block Word8)
    0x4d, Word8
    Item (Block Word8)
    0x6a, Word8
    Item (Block Word8)
    0x2a
        , Word8
    Item (Block Word8)
    0x96, Word8
    Item (Block Word8)
    0x1a, Word8
    Item (Block Word8)
    0xd2, Word8
    Item (Block Word8)
    0x71, Word8
    Item (Block Word8)
    0x5a, Word8
    Item (Block Word8)
    0x15, Word8
    Item (Block Word8)
    0x49, Word8
    Item (Block Word8)
    0x74, Word8
    Item (Block Word8)
    0x4b, Word8
    Item (Block Word8)
    0x9f, Word8
    Item (Block Word8)
    0xd0, Word8
    Item (Block Word8)
    0x5e, Word8
    Item (Block Word8)
    0x04, Word8
    Item (Block Word8)
    0x18, Word8
    Item (Block Word8)
    0xa4, Word8
    Item (Block Word8)
    0xec
        , Word8
    Item (Block Word8)
    0xc2, Word8
    Item (Block Word8)
    0xe0, Word8
    Item (Block Word8)
    0x41, Word8
    Item (Block Word8)
    0x6e, Word8
    Item (Block Word8)
    0x0f, Word8
    Item (Block Word8)
    0x51, Word8
    Item (Block Word8)
    0xcb, Word8
    Item (Block Word8)
    0xcc, Word8
    Item (Block Word8)
    0x24, Word8
    Item (Block Word8)
    0x91, Word8
    Item (Block Word8)
    0xaf, Word8
    Item (Block Word8)
    0x50, Word8
    Item (Block Word8)
    0xa1, Word8
    Item (Block Word8)
    0xf4, Word8
    Item (Block Word8)
    0x70, Word8
    Item (Block Word8)
    0x39
        , Word8
    Item (Block Word8)
    0x99, Word8
    Item (Block Word8)
    0x7c, Word8
    Item (Block Word8)
    0x3a, Word8
    Item (Block Word8)
    0x85, Word8
    Item (Block Word8)
    0x23, Word8
    Item (Block Word8)
    0xb8, Word8
    Item (Block Word8)
    0xb4, Word8
    Item (Block Word8)
    0x7a, Word8
    Item (Block Word8)
    0xfc, Word8
    Item (Block Word8)
    0x02, Word8
    Item (Block Word8)
    0x36, Word8
    Item (Block Word8)
    0x5b, Word8
    Item (Block Word8)
    0x25, Word8
    Item (Block Word8)
    0x55, Word8
    Item (Block Word8)
    0x97, Word8
    Item (Block Word8)
    0x31
        , Word8
    Item (Block Word8)
    0x2d, Word8
    Item (Block Word8)
    0x5d, Word8
    Item (Block Word8)
    0xfa, Word8
    Item (Block Word8)
    0x98, Word8
    Item (Block Word8)
    0xe3, Word8
    Item (Block Word8)
    0x8a, Word8
    Item (Block Word8)
    0x92, Word8
    Item (Block Word8)
    0xae, Word8
    Item (Block Word8)
    0x05, Word8
    Item (Block Word8)
    0xdf, Word8
    Item (Block Word8)
    0x29, Word8
    Item (Block Word8)
    0x10, Word8
    Item (Block Word8)
    0x67, Word8
    Item (Block Word8)
    0x6c, Word8
    Item (Block Word8)
    0xba, Word8
    Item (Block Word8)
    0xc9
        , Word8
    Item (Block Word8)
    0xd3, Word8
    Item (Block Word8)
    0x00, Word8
    Item (Block Word8)
    0xe6, Word8
    Item (Block Word8)
    0xcf, Word8
    Item (Block Word8)
    0xe1, Word8
    Item (Block Word8)
    0x9e, Word8
    Item (Block Word8)
    0xa8, Word8
    Item (Block Word8)
    0x2c, Word8
    Item (Block Word8)
    0x63, Word8
    Item (Block Word8)
    0x16, Word8
    Item (Block Word8)
    0x01, Word8
    Item (Block Word8)
    0x3f, Word8
    Item (Block Word8)
    0x58, Word8
    Item (Block Word8)
    0xe2, Word8
    Item (Block Word8)
    0x89, Word8
    Item (Block Word8)
    0xa9
        , Word8
    Item (Block Word8)
    0x0d, Word8
    Item (Block Word8)
    0x38, Word8
    Item (Block Word8)
    0x34, Word8
    Item (Block Word8)
    0x1b, Word8
    Item (Block Word8)
    0xab, Word8
    Item (Block Word8)
    0x33, Word8
    Item (Block Word8)
    0xff, Word8
    Item (Block Word8)
    0xb0, Word8
    Item (Block Word8)
    0xbb, Word8
    Item (Block Word8)
    0x48, Word8
    Item (Block Word8)
    0x0c, Word8
    Item (Block Word8)
    0x5f, Word8
    Item (Block Word8)
    0xb9, Word8
    Item (Block Word8)
    0xb1, Word8
    Item (Block Word8)
    0xcd, Word8
    Item (Block Word8)
    0x2e
        , Word8
    Item (Block Word8)
    0xc5, Word8
    Item (Block Word8)
    0xf3, Word8
    Item (Block Word8)
    0xdb, Word8
    Item (Block Word8)
    0x47, Word8
    Item (Block Word8)
    0xe5, Word8
    Item (Block Word8)
    0xa5, Word8
    Item (Block Word8)
    0x9c, Word8
    Item (Block Word8)
    0x77, Word8
    Item (Block Word8)
    0x0a, Word8
    Item (Block Word8)
    0xa6, Word8
    Item (Block Word8)
    0x20, Word8
    Item (Block Word8)
    0x68, Word8
    Item (Block Word8)
    0xfe, Word8
    Item (Block Word8)
    0x7f, Word8
    Item (Block Word8)
    0xc1, Word8
    Item (Block Word8)
    0xad
        ]