-- |
-- 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 (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 :: 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 :: 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) in --ke1 = (KA <<<  30) >> 64; ke2 = (KA <<<  30) & MASK64;
        let (Word128 Word64
k7 Word64
k8)   = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
45) in --k7  = (KL <<<  45) >> 64; k8  = (KL <<<  45) & MASK64;
        let (Word128 Word64
k9 Word64
_)    = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
45) in --k9  = (KA <<<  45) >> 64;
        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 :: Array64 -> Array64 -> Array64 -> Camellia
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
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 (Int
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 (Int
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 (Int
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 (Int
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 (Int
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 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) 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 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) in {- FL -}
    let d2c :: Word64
d2c = Word64 -> Word64 -> Word64
flinv Word64
d2b (Mode -> Camellia -> Int -> Word64
getKeyKe Mode
mode Camellia
key Int
1) in {- FLINV -}

    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) in {- FL -}
    let d2e :: Word64
d2e = Word64 -> Word64 -> Word64
flinv Word64
d2d (Mode -> Camellia -> Int -> Word64
getKeyKe Mode
mode Camellia
key Int
3) in {- FLINV -}

    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) 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 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 :: 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 :: 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)