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

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

import Control.Monad (forM_)

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

import Foreign.Storable


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

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


-- Utilities

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

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

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

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

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

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

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

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


-- Encryption

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

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

-- Decryption

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

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


-- Encryptiong rounds

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

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

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

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


-- Decryption rounds

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

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

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

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


-- Generic rounds

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

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


-- Key expansion

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

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

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

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

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

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


-- PITABLE

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