    {-# LANGUAGE MagicHash #-}

    -- |
    -- Module      : Crypto.Cipher.Camellia.Primitive
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : Good
    --
    -- This only cover Camellia 128 bits for now. The API will change once
    -- 192 and 256 mode are implemented too.
    module Crypto.Cipher.Camellia.Primitive (
        Camellia,
        initCamellia,
        encrypt,
        decrypt,
    ) where

    import Data.Bits
    import Data.Word

    import Crypto.Error
    import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
    import qualified Crypto.Internal.ByteArray as B
    import Crypto.Internal.WordArray
    import Crypto.Internal.Words
    import Data.Memory.Endian

    data Mode = Decrypt | Encrypt

    w64tow128 :: (Word64, Word64) -> Word128
    w64tow128 :: (Word64, Word64) -> Word128
    w64tow128 (Word64
    x1, Word64
    x2) = Word64 -> Word64 -> Word128
    Word128 Word64
    x1 Word64
    x2

    w64tow8 :: Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
    w64tow8 :: Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
    w64tow8 Word64
    x = (Word8
    t1, Word8
    t2, Word8
    t3, Word8
    t4, Word8
    t5, Word8
    t6, Word8
    t7, Word8
    t8)
      where
        t1 :: Word8
    t1 = Word64 -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    56)
        t2 :: Word8
    t2 = Word64 -> Word8
    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)
        t3 :: Word8
    t3 = Word64 -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    40)
        t4 :: Word8
    t4 = Word64 -> Word8
    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)
        t5 :: Word8
    t5 = Word64 -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    24)
        t6 :: Word8
    t6 = Word64 -> Word8
    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)
        t7 :: Word8
    t7 = Word64 -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftR` Int
    8)
        t8 :: Word8
    t8 = Word64 -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64
    x)

    w8tow64 :: (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8) -> Word64
    w8tow64 :: (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8) -> Word64
    w8tow64 (Word8
    t1, Word8
    t2, Word8
    t3, Word8
    t4, Word8
    t5, Word8
    t6, Word8
    t7, Word8
    t8) =
        (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t1 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    56)
            Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t2 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    48)
            Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t3 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    40)
            Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t4 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    32)
            Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t5 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    24)
            Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t6 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    16)
            Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t7 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `shiftL` Int
    8)
            Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. (Word8 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    t8)

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

    sbox1 :: Word8 -> Word8
    sbox1 :: Word8 -> Word8
    sbox1 Word8
    x = Int -> Word8
    sbox (Word8 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word8
    x)

    sbox2 :: Word8 -> Word8
    sbox2 :: Word8 -> Word8
    sbox2 Word8
    x = Word8 -> Word8
    sbox1 Word8
    x Word8 -> Int -> Word8
    forall a. Bits a => a -> Int -> a
    `rotateL` Int
    1

    sbox3 :: Word8 -> Word8
    sbox3 :: Word8 -> Word8
    sbox3 Word8
    x = Word8 -> Word8
    sbox1 Word8
    x Word8 -> Int -> Word8
    forall a. Bits a => a -> Int -> a
    `rotateL` Int
    7

    sbox4 :: Word8 -> Word8
    sbox4 :: Word8 -> Word8
    sbox4 Word8
    x = Word8 -> Word8
    sbox1 (Word8
    x Word8 -> Int -> Word8
    forall a. Bits a => a -> Int -> a
    `rotateL` Int
    1)

    sigma1, sigma2, sigma3, sigma4, sigma5, sigma6 :: Word64
    sigma1 :: Word64
    sigma1 = Word64
    0xA09E667F3BCC908B
    sigma2 :: Word64
    sigma2 = Word64
    0xB67AE8584CAA73B2
    sigma3 :: Word64
    sigma3 = Word64
    0xC6EF372FE94F82BE
    sigma4 :: Word64
    sigma4 = Word64
    0x54FF53A5F1D36F1C
    sigma5 :: Word64
    sigma5 = Word64
    0x10E527FADE682D1D
    sigma6 :: Word64
    sigma6 = Word64
    0xB05688C2B3E6C1FD

    rotl128 :: Word128 -> Int -> Word128
    rotl128 :: Word128 -> Int -> Word128
    rotl128 Word128
    v Int
    0 = Word128
    v
    rotl128 (Word128 Word64
    x1 Word64
    x2) Int
    64 = Word64 -> Word64 -> Word128
    Word128 Word64
    x2 Word64
    x1
    rotl128 v :: Word128
    v@(Word128 Word64
    x1 Word64
    x2) Int
    w
        | Int
    w Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    64 = (Word128
    v Word128 -> Int -> Word128
    `rotl128` Int
    64) Word128 -> Int -> Word128
    `rotl128` (Int
    w Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    64)
        | Bool
    otherwise = Word64 -> Word64 -> Word128
    Word128 (Word64
    x1high Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. Word64
    x2low) (Word64
    x2high Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    .|. Word64
    x1low)
      where
        splitBits :: b -> (b, b)
    splitBits b
    i = (b
    i b -> b -> b
    forall a. Bits a => a -> a -> a
    .&. b -> b
    forall a. Bits a => a -> a
    complement b
    x, b
    i b -> b -> b
    forall a. Bits a => a -> a -> a
    .&. b
    x)
          where
            x :: b
    x = b
    2 b -> Int -> b
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ Int
    w b -> b -> b
    forall a. Num a => a -> a -> a
    - b
    1
        (Word64
    x1high, Word64
    x1low) = Word64 -> (Word64, Word64)
    forall {b}. (Bits b, Num b) => b -> (b, b)
    splitBits (Word64
    x1 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `rotateL` Int
    w)
        (Word64
    x2high, Word64
    x2low) = Word64 -> (Word64, Word64)
    forall {b}. (Bits b, Num b) => b -> (b, b)
    splitBits (Word64
    x2 Word64 -> Int -> Word64
    forall a. Bits a => a -> Int -> a
    `rotateL` Int
    w)

    -- | Camellia context
    data Camellia = Camellia
        { Camellia -> Array64
    k :: Array64
        , Camellia -> Array64
    kw :: Array64
        , Camellia -> Array64
    ke :: Array64
        }

    setKeyInterim
        :: ByteArrayAccess key => key -> (Word128, Word128, Word128, Word128)
    setKeyInterim :: forall key.
    ByteArrayAccess key =>
    key -> (Word128, Word128, Word128, Word128)
    setKeyInterim key
    keyseed = ((Word64, Word64) -> Word128
    w64tow128 (Word64, Word64)
    kL, (Word64, Word64) -> Word128
    w64tow128 (Word64, Word64)
    kR, (Word64, Word64) -> Word128
    w64tow128 (Word64, Word64)
    kA, (Word64, Word64) -> Word128
    w64tow128 (Word64, Word64)
    kB)
      where
        kL :: (Word64, Word64)
    kL = (BE Word64 -> Word64
    forall a. ByteSwap a => BE a -> a
    fromBE (BE Word64 -> Word64) -> BE Word64 -> Word64
    forall a b. (a -> b) -> a -> b
    $ key -> Int -> BE Word64
    forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
    B.toW64BE key
    keyseed Int
    0, BE Word64 -> Word64
    forall a. ByteSwap a => BE a -> a
    fromBE (BE Word64 -> Word64) -> BE Word64 -> Word64
    forall a b. (a -> b) -> a -> b
    $ key -> Int -> BE Word64
    forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
    B.toW64BE key
    keyseed Int
    8)
        kR :: (Word64, Word64)
    kR = (Word64
    0, Word64
    0)

        kA :: (Word64, Word64)
    kA =
            let d1 :: Word64
    d1 = ((Word64, Word64) -> Word64
    forall a b. (a, b) -> a
    fst (Word64, Word64)
    kL Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Word64, Word64) -> Word64
    forall a b. (a, b) -> a
    fst (Word64, Word64)
    kR)
                d2 :: Word64
    d2 = ((Word64, Word64) -> Word64
    forall a b. (a, b) -> b
    snd (Word64, Word64)
    kL Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Word64, Word64) -> Word64
    forall a b. (a, b) -> b
    snd (Word64, Word64)
    kR)
                d3 :: Word64
    d3 = Word64
    d2 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    d1 Word64
    sigma1
                d4 :: Word64
    d4 = Word64
    d1 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    d3 Word64
    sigma2
                d5 :: Word64
    d5 = Word64
    d4 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` ((Word64, Word64) -> Word64
    forall a b. (a, b) -> a
    fst (Word64, Word64)
    kL)
                d6 :: Word64
    d6 = Word64
    d3 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` ((Word64, Word64) -> Word64
    forall a b. (a, b) -> b
    snd (Word64, Word64)
    kL)
                d7 :: Word64
    d7 = Word64
    d6 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    d5 Word64
    sigma3
                d8 :: Word64
    d8 = Word64
    d5 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    d7 Word64
    sigma4
             in (Word64
    d8, Word64
    d7)

        kB :: (Word64, Word64)
    kB =
            let d1 :: Word64
    d1 = ((Word64, Word64) -> Word64
    forall a b. (a, b) -> a
    fst (Word64, Word64)
    kA Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Word64, Word64) -> Word64
    forall a b. (a, b) -> a
    fst (Word64, Word64)
    kR)
                d2 :: Word64
    d2 = ((Word64, Word64) -> Word64
    forall a b. (a, b) -> b
    snd (Word64, Word64)
    kA Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Word64, Word64) -> Word64
    forall a b. (a, b) -> b
    snd (Word64, Word64)
    kR)
                d3 :: Word64
    d3 = Word64
    d2 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    d1 Word64
    sigma5
                d4 :: Word64
    d4 = Word64
    d1 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    d3 Word64
    sigma6
             in (Word64
    d4, Word64
    d3)

    -- | Initialize a 128-bit key
    --
    -- Return the initialized key or a error message if the given
    -- keyseed was not 16-bytes in length.
    initCamellia
        :: ByteArray key
        => key
        -- ^ The key to create the camellia context
        -> CryptoFailable Camellia
    initCamellia :: forall key. ByteArray key => key -> CryptoFailable Camellia
    initCamellia key
    key
        | key -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length key
    key Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    16 = CryptoError -> CryptoFailable Camellia
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed (CryptoError -> CryptoFailable Camellia)
    -> CryptoError -> CryptoFailable Camellia
    forall a b. (a -> b) -> a -> b
    $ CryptoError
    CryptoError_KeySizeInvalid
        | Bool
    otherwise =
            let (Word128
    kL, Word128
    _, Word128
    kA, Word128
    _) = key -> (Word128, Word128, Word128, Word128)
    forall key.
    ByteArrayAccess key =>
    key -> (Word128, Word128, Word128, Word128)
    setKeyInterim key
    key
             in let (Word128 Word64
    kw1 Word64
    kw2) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` Int
    0)
                 in let (Word128 Word64
    k1 Word64
    k2) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` Int
    0)
                     in let (Word128 Word64
    k3 Word64
    k4) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` Int
    15)
                         in let (Word128 Word64
    k5 Word64
    k6) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` Int
    15)
                             in let (Word128 Word64
    ke1 Word64
    ke2) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` Int
    30) -- ke1 = (KA <<<  30) >> 64; ke2 = (KA <<<  30) & MASK64;
                                 in let (Word128 Word64
    k7 Word64
    k8) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` Int
    45) -- k7  = (KL <<<  45) >> 64; k8  = (KL <<<  45) & MASK64;
                                     in let (Word128 Word64
    k9 Word64
    _) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` Int
    45) -- k9  = (KA <<<  45) >> 64;
                                         in let (Word128 Word64
    _ Word64
    k10) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` Int
    60)
                                             in let (Word128 Word64
    k11 Word64
    k12) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` Int
    60)
                                                 in let (Word128 Word64
    ke3 Word64
    ke4) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` Int
    77)
                                                     in let (Word128 Word64
    k13 Word64
    k14) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` Int
    94)
                                                         in let (Word128 Word64
    k15 Word64
    k16) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` Int
    94)
                                                             in let (Word128 Word64
    k17 Word64
    k18) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` Int
    111)
                                                                 in let (Word128 Word64
    kw3 Word64
    kw4) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` Int
    111)
                                                                     in Camellia -> CryptoFailable Camellia
    forall a. a -> CryptoFailable a
    CryptoPassed (Camellia -> CryptoFailable Camellia)
    -> Camellia -> CryptoFailable Camellia
    forall a b. (a -> b) -> a -> b
    $
                                                                            Camellia
                                                                                { kw :: Array64
    kw = Int -> [Word64] -> Array64
    array64 Int
    4 [Word64
    kw1, Word64
    kw2, Word64
    kw3, Word64
    kw4]
                                                                                , ke :: Array64
    ke = Int -> [Word64] -> Array64
    array64 Int
    4 [Word64
    ke1, Word64
    ke2, Word64
    ke3, Word64
    ke4]
                                                                                , k :: Array64
    k =
                                                                                    Int -> [Word64] -> Array64
    array64
                                                                                        Int
    18
                                                                                        [ Word64
    k1
                                                                                        , Word64
    k2
                                                                                        , Word64
    k3
                                                                                        , Word64
    k4
                                                                                        , Word64
    k5
                                                                                        , Word64
    k6
                                                                                        , Word64
    k7
                                                                                        , Word64
    k8
                                                                                        , Word64
    k9
                                                                                        , Word64
    k10
                                                                                        , Word64
    k11
                                                                                        , Word64
    k12
                                                                                        , Word64
    k13
                                                                                        , Word64
    k14
                                                                                        , Word64
    k15
                                                                                        , Word64
    k16
                                                                                        , Word64
    k17
                                                                                        , Word64
    k18
                                                                                        ]
                                                                                }

    feistel :: Word64 -> Word64 -> Word64
    feistel :: Word64 -> Word64 -> Word64
    feistel Word64
    fin Word64
    sk =
        let x :: Word64
    x = Word64
    fin Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64
    sk
         in let (Word8
    t1, Word8
    t2, Word8
    t3, Word8
    t4, Word8
    t5, Word8
    t6, Word8
    t7, Word8
    t8) = Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
    w64tow8 Word64
    x
             in let t1' :: Word8
    t1' = Word8 -> Word8
    sbox1 Word8
    t1
                 in let t2' :: Word8
    t2' = Word8 -> Word8
    sbox2 Word8
    t2
                     in let t3' :: Word8
    t3' = Word8 -> Word8
    sbox3 Word8
    t3
                         in let t4' :: Word8
    t4' = Word8 -> Word8
    sbox4 Word8
    t4
                             in let t5' :: Word8
    t5' = Word8 -> Word8
    sbox2 Word8
    t5
                                 in let t6' :: Word8
    t6' = Word8 -> Word8
    sbox3 Word8
    t6
                                     in let t7' :: Word8
    t7' = Word8 -> Word8
    sbox4 Word8
    t7
                                         in let t8' :: Word8
    t8' = Word8 -> Word8
    sbox1 Word8
    t8
                                             in let y1 :: Word8
    y1 = Word8
    t1' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t3' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t4' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t6' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t7' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t8'
                                                 in let y2 :: Word8
    y2 = Word8
    t1' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t2' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t4' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t5' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t7' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t8'
                                                     in let y3 :: Word8
    y3 = Word8
    t1' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t2' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t3' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t5' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t6' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t8'
                                                         in let y4 :: Word8
    y4 = Word8
    t2' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t3' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t4' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t5' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t6' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t7'
                                                             in let y5 :: Word8
    y5 = Word8
    t1' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t2' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t6' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t7' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t8'
                                                                 in let y6 :: Word8
    y6 = Word8
    t2' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t3' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t5' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t7' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t8'
                                                                     in let y7 :: Word8
    y7 = Word8
    t3' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t4' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t5' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t6' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t8'
                                                                         in let y8 :: Word8
    y8 = Word8
    t1' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t4' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t5' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t6' Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    `xor` Word8
    t7'
                                                                             in (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8) -> Word64
    w8tow64 (Word8
    y1, Word8
    y2, Word8
    y3, Word8
    y4, Word8
    y5, Word8
    y6, Word8
    y7, Word8
    y8)

    fl :: Word64 -> Word64 -> Word64
    fl :: Word64 -> Word64 -> Word64
    fl Word64
    fin Word64
    sk =
        let (Word32
    x1, Word32
    x2) = Word64 -> (Word32, Word32)
    w64to32 Word64
    fin
         in let (Word32
    k1, Word32
    k2) = Word64 -> (Word32, Word32)
    w64to32 Word64
    sk
             in let y2 :: Word32
    y2 = Word32
    x2 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` ((Word32
    x1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .&. Word32
    k1) Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `rotateL` Int
    1)
                 in let y1 :: Word32
    y1 = Word32
    x1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` (Word32
    y2 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .|. Word32
    k2)
                     in (Word32, Word32) -> Word64
    w32to64 (Word32
    y1, Word32
    y2)

    flinv :: Word64 -> Word64 -> Word64
    flinv :: Word64 -> Word64 -> Word64
    flinv Word64
    fin Word64
    sk =
        let (Word32
    y1, Word32
    y2) = Word64 -> (Word32, Word32)
    w64to32 Word64
    fin
         in let (Word32
    k1, Word32
    k2) = Word64 -> (Word32, Word32)
    w64to32 Word64
    sk
             in let x1 :: Word32
    x1 = Word32
    y1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` (Word32
    y2 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .|. Word32
    k2)
                 in let x2 :: Word32
    x2 = Word32
    y2 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    `xor` ((Word32
    x1 Word32 -> Word32 -> Word32
    forall a. Bits a => a -> a -> a
    .&. Word32
    k1) Word32 -> Int -> Word32
    forall a. Bits a => a -> Int -> a
    `rotateL` Int
    1)
                     in (Word32, Word32) -> Word64
    w32to64 (Word32
    x1, Word32
    x2)

    {- in decrypt mode 0->17 1->16 ... -}
    getKeyK :: Mode -> Camellia -> Int -> Word64
    getKeyK :: Mode -> Camellia -> Int -> Word64
    getKeyK Mode
    Encrypt Camellia
    key Int
    i = Camellia -> Array64
    k Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` Int
    i
    getKeyK Mode
    Decrypt Camellia
    key Int
    i = Camellia -> Array64
    k Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` (Int
    17 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    i)

    {- in decrypt mode 0->3 1->2 2->1 3->0 -}
    getKeyKe :: Mode -> Camellia -> Int -> Word64
    getKeyKe :: Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    Encrypt Camellia
    key Int
    i = Camellia -> Array64
    ke Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` Int
    i
    getKeyKe Mode
    Decrypt Camellia
    key Int
    i = Camellia -> Array64
    ke Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` (Int
    3 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    i)

    {- in decrypt mode 0->2 1->3 2->0 3->1 -}
    getKeyKw :: Mode -> Camellia -> Int -> Word64
    getKeyKw :: Mode -> Camellia -> Int -> Word64
    getKeyKw Mode
    Encrypt Camellia
    key Int
    i = (Camellia -> Array64
    kw Camellia
    key) Array64 -> Int -> Word64
    `arrayRead64` Int
    i
    getKeyKw Mode
    Decrypt Camellia
    key Int
    i = (Camellia -> Array64
    kw Camellia
    key) Array64 -> Int -> Word64
    `arrayRead64` ((Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `mod` Int
    4)

    {- perform the following
        D2 = D2 ^ F(D1, k1);     // Round 1
        D1 = D1 ^ F(D2, k2);     // Round 2
        D2 = D2 ^ F(D1, k3);     // Round 3
        D1 = D1 ^ F(D2, k4);     // Round 4
        D2 = D2 ^ F(D1, k5);     // Round 5
        D1 = D1 ^ F(D2, k6);     // Round 6
     -}
    doBlockRound :: Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound :: Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound Mode
    mode Camellia
    key Word64
    d1 Word64
    d2 Int
    i =
        let r1 :: Word64
    r1 = Word64
    d2 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    d1 (Mode -> Camellia -> Int -> Word64
    getKeyK Mode
    mode Camellia
    key (Int
    0 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    i {- Round 1+i -}))
         in let r2 :: Word64
    r2 = Word64
    d1 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    r1 (Mode -> Camellia -> Int -> Word64
    getKeyK Mode
    mode Camellia
    key (Int
    1 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    i {- Round 2+i -}))
             in let r3 :: Word64
    r3 = Word64
    r1 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    r2 (Mode -> Camellia -> Int -> Word64
    getKeyK Mode
    mode Camellia
    key (Int
    2 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    i {- Round 3+i -}))
                 in let r4 :: Word64
    r4 = Word64
    r2 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    r3 (Mode -> Camellia -> Int -> Word64
    getKeyK Mode
    mode Camellia
    key (Int
    3 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    i {- Round 4+i -}))
                     in let r5 :: Word64
    r5 = Word64
    r3 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    r4 (Mode -> Camellia -> Int -> Word64
    getKeyK Mode
    mode Camellia
    key (Int
    4 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    i {- Round 5+i -}))
                         in let r6 :: Word64
    r6 = Word64
    r4 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64 -> Word64 -> Word64
    feistel Word64
    r5 (Mode -> Camellia -> Int -> Word64
    getKeyK Mode
    mode Camellia
    key (Int
    5 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    i {- Round 6+i -}))
                             in (Word64
    r6, Word64
    r5)

    doBlock :: Mode -> Camellia -> Word128 -> Word128
    doBlock :: Mode -> Camellia -> Word128 -> Word128
    doBlock Mode
    mode Camellia
    key (Word128 Word64
    d1 Word64
    d2) =
        let d1a :: Word64
    d1a = Word64
    d1 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Mode -> Camellia -> Int -> Word64
    getKeyKw Mode
    mode Camellia
    key Int
    0 {- Prewhitening -})
         in let d2a :: Word64
    d2a = Word64
    d2 Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Mode -> Camellia -> Int -> Word64
    getKeyKw Mode
    mode Camellia
    key Int
    1)
             in let (Word64
    d1b, Word64
    d2b) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound Mode
    mode Camellia
    key Word64
    d1a Word64
    d2a Int
    0
                 in let d1c :: Word64
    d1c = Word64 -> Word64 -> Word64
    fl Word64
    d1b (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key Int
    0 {- FL -})
                     in let d2c :: Word64
    d2c = Word64 -> Word64 -> Word64
    flinv Word64
    d2b (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key Int
    1 {- FLINV -})
                         in let (Word64
    d1d, Word64
    d2d) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound Mode
    mode Camellia
    key Word64
    d1c Word64
    d2c Int
    6
                             in let d1e :: Word64
    d1e = Word64 -> Word64 -> Word64
    fl Word64
    d1d (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key Int
    2 {- FL -})
                                 in let d2e :: Word64
    d2e = Word64 -> Word64 -> Word64
    flinv Word64
    d2d (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key Int
    3 {- FLINV -})
                                     in let (Word64
    d1f, Word64
    d2f) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound Mode
    mode Camellia
    key Word64
    d1e Word64
    d2e Int
    12
                                         in let d2g :: Word64
    d2g = Word64
    d2f Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Mode -> Camellia -> Int -> Word64
    getKeyKw Mode
    mode Camellia
    key Int
    2 {- Postwhitening -})
                                             in let d1g :: Word64
    d1g = Word64
    d1f Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` (Mode -> Camellia -> Int -> Word64
    getKeyKw Mode
    mode Camellia
    key Int
    3)
                                                 in (Word64, Word64) -> Word128
    w64tow128 (Word64
    d2g, Word64
    d1g)

    {- encryption for 128 bits blocks -}
    encryptBlock :: Camellia -> Word128 -> Word128
    encryptBlock :: Camellia -> Word128 -> Word128
    encryptBlock = Mode -> Camellia -> Word128 -> Word128
    doBlock Mode
    Encrypt

    {- decryption for 128 bits blocks -}
    decryptBlock :: Camellia -> Word128 -> Word128
    decryptBlock :: Camellia -> Word128 -> Word128
    decryptBlock = Mode -> Camellia -> Word128 -> Word128
    doBlock Mode
    Decrypt

    -- | Encrypts the given ByteString using the given Key
    encrypt
        :: ByteArray ba
        => Camellia
        -- ^ The key to use
        -> ba
        -- ^ The data to encrypt
        -> ba
    encrypt :: forall ba. ByteArray ba => Camellia -> ba -> ba
    encrypt Camellia
    key = (Word128 -> Word128) -> ba -> ba
    forall bs. ByteArray bs => (Word128 -> Word128) -> bs -> bs
    B.mapAsWord128 (Camellia -> Word128 -> Word128
    encryptBlock Camellia
    key)

    -- | Decrypts the given ByteString using the given Key
    decrypt
        :: ByteArray ba
        => Camellia
        -- ^ The key to use
        -> ba
        -- ^ The data to decrypt
        -> ba
    decrypt :: forall ba. ByteArray ba => Camellia -> ba -> ba
    decrypt Camellia
    key = (Word128 -> Word128) -> ba -> ba
    forall bs. ByteArray bs => (Word128 -> Word128) -> bs -> bs
    B.mapAsWord128 (Camellia -> Word128 -> Word128
    decryptBlock Camellia
    key)