    -- |
    -- 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.
    {-# LANGUAGE MagicHash #-}
    module Crypto.Cipher.Camellia.Primitive
        ( Camellia
        , initCamellia
        , encrypt
        , decrypt
        ) where

    import           Data.Word
    import           Data.Bits

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

    data Mode = Decrypt | Encrypt

    w64tow128 :: (Word64, Word64) -> Word128
    w64tow128 :: (Word64, Word64) -> Word128
    w64tow128 (x1 :: Word64
    x1, x2 :: 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 x :: 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` 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` 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` 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` 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` 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` 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` 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 (t1 :: Word8
    t1,t2 :: Word8
    t2,t3 :: Word8
    t3,t4 :: Word8
    t4,t5 :: Word8
    t5,t6 :: Word8
    t6,t7 :: Word8
    t7,t8 :: 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` 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` 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` 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` 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` 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` 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` 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
                "\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 x :: 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 x :: Word8
    x = Word8 -> Word8
    sbox1 Word8
    x Word8 -> Int -> Word8
    forall a. Bits a => a -> Int -> a
    `rotateL` 1

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

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

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

    rotl128 :: Word128 -> Int -> Word128
    rotl128 :: Word128 -> Int -> Word128
    rotl128 v :: Word128
    v               0  = Word128
    v
    rotl128 (Word128 x1 :: Word64
    x1 x2 :: Word64
    x2) 64 = Word64 -> Word64 -> Word128
    Word128 Word64
    x2 Word64
    x1

    rotl128 v :: Word128
    v@(Word128 x1 :: Word64
    x1 x2 :: Word64
    x2) w :: Int
    w
        | Int
    w Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > 64    = (Word128
    v Word128 -> Int -> Word128
    `rotl128` 64) Word128 -> Int -> Word128
    `rotl128` (Int
    w Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 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 i :: 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 = 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
    - 1
                (x1high :: Word64
    x1high, x1low :: 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)
                (x2high :: Word64
    x2high, x2low :: 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 :: key -> (Word128, Word128, Word128, Word128)
    setKeyInterim keyseed :: 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 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 8)
            kR :: (Word64, Word64)
    kR = (0, 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 :: key -> CryptoFailable Camellia
    initCamellia key :: key
    key
        | key -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length key
    key Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= 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 (kL :: Word128
    kL, _, kA :: Word128
    kA, _) = key -> (Word128, Word128, Word128, Word128)
    forall key.
    ByteArrayAccess key =>
    key -> (Word128, Word128, Word128, Word128)
    setKeyInterim key
    key in

            let (Word128 kw1 :: Word64
    kw1 kw2 :: Word64
    kw2) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` 0) in
            let (Word128 k1 :: Word64
    k1 k2 :: Word64
    k2)   = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` 0) in
            let (Word128 k3 :: Word64
    k3 k4 :: Word64
    k4)   = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` 15) in
            let (Word128 k5 :: Word64
    k5 k6 :: Word64
    k6)   = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` 15) in
            let (Word128 ke1 :: Word64
    ke1 ke2 :: Word64
    ke2) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` 30) in --ke1 = (KA <<<  30) >> 64; ke2 = (KA <<<  30) & MASK64;
            let (Word128 k7 :: Word64
    k7 k8 :: Word64
    k8)   = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` 45) in --k7  = (KL <<<  45) >> 64; k8  = (KL <<<  45) & MASK64;
            let (Word128 k9 :: Word64
    k9 _)    = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` 45) in --k9  = (KA <<<  45) >> 64;
            let (Word128 _ k10 :: Word64
    k10)   = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` 60) in
            let (Word128 k11 :: Word64
    k11 k12 :: Word64
    k12) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` 60) in
            let (Word128 ke3 :: Word64
    ke3 ke4 :: Word64
    ke4) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` 77) in
            let (Word128 k13 :: Word64
    k13 k14 :: Word64
    k14) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` 94) in
            let (Word128 k15 :: Word64
    k15 k16 :: Word64
    k16) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` 94) in
            let (Word128 k17 :: Word64
    k17 k18 :: Word64
    k18) = (Word128
    kL Word128 -> Int -> Word128
    `rotl128` 111) in
            let (Word128 kw3 :: Word64
    kw3 kw4 :: Word64
    kw4) = (Word128
    kA Word128 -> Int -> Word128
    `rotl128` 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 :: Array64 -> Array64 -> Array64 -> Camellia
    Camellia
                { kw :: Array64
    kw = Int -> [Word64] -> Array64
    array64 4 [ Word64
    kw1, Word64
    kw2, Word64
    kw3, Word64
    kw4 ]
                , ke :: Array64
    ke = Int -> [Word64] -> Array64
    array64 4 [ Word64
    ke1, Word64
    ke2, Word64
    ke3, Word64
    ke4 ]
                , k :: Array64
    k  = Int -> [Word64] -> Array64
    array64 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 fin :: Word64
    fin sk :: Word64
    sk =
        let x :: Word64
    x = Word64
    fin Word64 -> Word64 -> Word64
    forall a. Bits a => a -> a -> a
    `xor` Word64
    sk in
        let (t1 :: Word8
    t1, t2 :: Word8
    t2, t3 :: Word8
    t3, t4 :: Word8
    t4, t5 :: Word8
    t5, t6 :: Word8
    t6, t7 :: Word8
    t7, t8 :: 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 fin :: Word64
    fin sk :: Word64
    sk =
        let (x1 :: Word32
    x1, x2 :: Word32
    x2) = Word64 -> (Word32, Word32)
    w64to32 Word64
    fin in
        let (k1 :: Word32
    k1, k2 :: 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` 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 fin :: Word64
    fin sk :: Word64
    sk =
        let (y1 :: Word32
    y1, y2 :: Word32
    y2) = Word64 -> (Word32, Word32)
    w64to32 Word64
    fin in
        let (k1 :: Word32
    k1, k2 :: 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` 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 Encrypt key :: Camellia
    key i :: Int
    i = Camellia -> Array64
    k Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` Int
    i
    getKeyK Decrypt key :: Camellia
    key i :: Int
    i = Camellia -> Array64
    k Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` (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 Encrypt key :: Camellia
    key i :: Int
    i = Camellia -> Array64
    ke Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` Int
    i
    getKeyKe Decrypt key :: Camellia
    key i :: Int
    i = Camellia -> Array64
    ke Camellia
    key Array64 -> Int -> Word64
    `arrayRead64` (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 Encrypt key :: Camellia
    key i :: Int
    i = (Camellia -> Array64
    kw Camellia
    key) Array64 -> Int -> Word64
    `arrayRead64` Int
    i
    getKeyKw Decrypt key :: Camellia
    key i :: Int
    i = (Camellia -> Array64
    kw Camellia
    key) Array64 -> Int -> Word64
    `arrayRead64` ((Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + 2) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `mod` 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
    mode key :: Camellia
    key d1 :: Word64
    d1 d2 :: Word64
    d2 i :: 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 (0Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    i)) in     {- Round 1+i -}
        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 (1Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    i)) in     {- Round 2+i -}
        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 (2Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    i)) in     {- Round 3+i -}
        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 (3Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    i)) in     {- Round 4+i -}
        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 (4Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    i)) in     {- Round 5+i -}
        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 (5Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    i)) in     {- Round 6+i -}
        (Word64
    r6, Word64
    r5)

    doBlock :: Mode -> Camellia -> Word128 -> Word128
    doBlock :: Mode -> Camellia -> Word128 -> Word128
    doBlock mode :: Mode
    mode key :: Camellia
    key (Word128 d1 :: Word64
    d1 d2 :: 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 0) in {- Prewhitening -}
        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 1) in

        let (d1b :: Word64
    d1b, d2b :: Word64
    d2b) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound Mode
    mode Camellia
    key Word64
    d1a Word64
    d2a 0 in

        let d1c :: Word64
    d1c = Word64 -> Word64 -> Word64
    fl    Word64
    d1b (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key 0) in {- FL -}
        let d2c :: Word64
    d2c = Word64 -> Word64 -> Word64
    flinv Word64
    d2b (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key 1) in {- FLINV -}

        let (d1d :: Word64
    d1d, d2d :: Word64
    d2d) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound Mode
    mode Camellia
    key Word64
    d1c Word64
    d2c 6 in

        let d1e :: Word64
    d1e = Word64 -> Word64 -> Word64
    fl    Word64
    d1d (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key 2) in {- FL -}
        let d2e :: Word64
    d2e = Word64 -> Word64 -> Word64
    flinv Word64
    d2d (Mode -> Camellia -> Int -> Word64
    getKeyKe Mode
    mode Camellia
    key 3) in {- FLINV -}

        let (d1f :: Word64
    d1f, d2f :: Word64
    d2f) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
    doBlockRound Mode
    mode Camellia
    key Word64
    d1e Word64
    d2e 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 2) in {- Postwhitening -}
        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 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 :: Camellia -> ba -> ba
    encrypt key :: 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 :: Camellia -> ba -> ba
    decrypt key :: Camellia
    key = (Word128 -> Word128) -> ba -> ba
    forall bs. ByteArray bs => (Word128 -> Word128) -> bs -> bs
    B.mapAsWord128 (Camellia -> Word128 -> Word128
    decryptBlock Camellia
    key)