diff --git a/Crypto/Cipher/AES.hs b/Crypto/Cipher/AES.hs
--- a/Crypto/Cipher/AES.hs
+++ b/Crypto/Cipher/AES.hs
@@ -1,1006 +1,1014 @@
--- |
--- Module      : Crypto.Cipher.AES
--- License     : BSD-style
--- Maintainer  : Vincent Hanquez <vincent@snarc.org>
--- Stability   : experimental
--- Portability : Good
-
-module Crypto.Cipher.AES
-	( Key
-	, IV
-	-- * Basic encryption and decryption
-	, encrypt
-	, decrypt
-	-- * CBC encryption and decryption
-	, encryptCBC
-	, decryptCBC
-	-- * key building mechanism
-	, initKey128
-	, initKey192
-	, initKey256
-	-- * Wrappers for "crypto-api" instances
-	, AES128
-	, AES192
-	, AES256
-	) where
-
-import Data.Word
-import Data.Vector.Unboxed (Vector)
-import qualified Data.Vector.Unboxed as V
-import Data.Bits
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as B
-import qualified Data.ByteString.Unsafe as B
-import qualified Data.ByteString.Internal as B
-
-import Foreign.Ptr
-import Foreign.Storable
-
-import Data.Tagged (Tagged(..))
-import Crypto.Classes (BlockCipher(..))
-import Data.Serialize (Serialize(..), getByteString, putByteString)
-
-import Control.Monad (forM_)
-import Control.Monad.Primitive
-
-import Data.Primitive.ByteArray
-
-newtype AES128 = A128 { unA128 :: Key }
-newtype AES192 = A192 { unA192 :: Key }
-newtype AES256 = A256 { unA256 :: Key }
-
-instance BlockCipher AES128 where
-	blockSize    = Tagged 128
-	encryptBlock = encrypt . unA128
-	decryptBlock = decrypt . unA128
-	buildKey b   = either (const Nothing) (Just . A128) $ initKey128 b
-	keyLength    = Tagged 128
-
-instance BlockCipher AES192 where
-	blockSize    = Tagged 128
-	encryptBlock = encrypt . unA192
-	decryptBlock = decrypt . unA192
-	buildKey b   = either (const Nothing) (Just . A192) $ initKey192 b
-	keyLength    = Tagged 192
-
-instance BlockCipher AES256 where
-	blockSize    = Tagged 128
-	encryptBlock = encrypt . unA256
-	decryptBlock = decrypt . unA256
-	buildKey b   = either (const Nothing) (Just . A256) $ initKey256 b
-	keyLength    = Tagged 256
-
-serializeKey :: Key -> ByteString
-serializeKey (Key v)
-	| V.length v == 176 = B.pack $ map (V.unsafeIndex v) [0..15]
-	| V.length v == 208 = B.pack $ map (V.unsafeIndex v) [0..23]
-	| otherwise         = B.pack $ map (V.unsafeIndex v) [0..31]
-
-instance Serialize AES128 where
-	put = putByteString . serializeKey . unA128
-	get = do
-		raw <- getByteString (128 `div` 8)
-		case buildKey raw of
-			Nothing -> fail "Invalid raw key material."
-			Just k  -> return k
-
-instance Serialize AES192 where
-	put = putByteString . serializeKey . unA192
-	get = do
-		raw <- getByteString (192 `div` 8)
-		case buildKey raw of
-			Nothing -> fail "Invalid raw key material."
-			Just k  -> return k
-
-instance Serialize AES256 where
-	put = putByteString . serializeKey . unA256
-	get = do
-		raw <- getByteString (256 `div` 8)
-		case buildKey raw of
-			Nothing -> fail "Invalid raw key material."
-			Just k  -> return k
-
-data Key = Key (Vector Word8)
-	deriving (Show,Eq)
-
-type IV = B.ByteString
-
-type AESState = MutableByteArray RealWorld
-
-{- | encrypt using CBC mode
- - IV need to be 16 bytes and the data to encrypt a multiple of 16 bytes -}
-encryptCBC :: Key -> IV -> B.ByteString -> B.ByteString
-encryptCBC key iv b
-	| B.length iv /= 16        = error "invalid IV length"
-	| B.length b `mod` 16 /= 0 = error "invalid data length"
-	| otherwise                = B.concat $ encryptIter iv (makeChunks b)
-		where
-			encryptIter _   []     = []
-			encryptIter iv' (x:xs) =
-				let r = coreEncrypt key $ B.pack $ B.zipWith xor iv' x in
-				r : encryptIter r xs
-
-{- | encrypt using simple EBC mode -}
-encrypt :: Key -> B.ByteString -> B.ByteString
-encrypt key b
-	| B.length b `mod` 16 /= 0 = error "invalid data length"
-	| otherwise                = B.concat $ doChunks (coreEncrypt key) b
-
-{- | decrypt using CBC mode
- - IV need to be 16 bytes and the data to decrypt a multiple of 16 bytes -}
-decryptCBC :: Key -> IV -> B.ByteString -> B.ByteString
-decryptCBC key iv b
-	| B.length iv /= 16        = error "invalid IV length"
-	| B.length b `mod` 16 /= 0 = error "invalid data length"
-	| otherwise                = B.concat $ decryptIter iv (makeChunks b)
-		where
-			decryptIter _   []     = []
-			decryptIter iv' (x:xs) =
-				let r = B.pack $ B.zipWith xor iv' $ coreDecrypt key x in
-				r : decryptIter x xs
-
-{- | decrypt using simple EBC mode -}
-decrypt :: Key -> B.ByteString -> B.ByteString
-decrypt key b
-	| B.length b `mod` 16 /= 0 = error "invalid data length"
-	| otherwise                = B.concat $ doChunks (coreDecrypt key) b
-
-doChunks :: (B.ByteString -> B.ByteString) -> B.ByteString -> [B.ByteString]
-doChunks f b =
-	let (x, rest) = B.splitAt 16 b in
-	if B.length rest >= 16
-		then f x : doChunks f rest
-		else [ f x ]
-
-makeChunks :: B.ByteString -> [B.ByteString]
-makeChunks = doChunks id
-
-newAESState :: IO AESState
-newAESState = newAlignedPinnedByteArray 16 16
-
-coreEncrypt :: Key -> ByteString -> ByteString
-coreEncrypt key input = B.unsafeCreate (B.length input) $ \ptr -> do
-	st <- newAESState
-	swapBlock input st
-	aesMain (getNbr key) key st
-	swapBlockInv st ptr
-
-coreDecrypt :: Key -> ByteString -> ByteString
-coreDecrypt key input = B.unsafeCreate (B.length input) $ \ptr -> do
-	st <- newAESState
-	swapBlock input st
-	aesMainInv (getNbr key) key st
-	swapBlockInv st ptr
-
-getNbr :: Key -> Int
-getNbr (Key v)
-	| V.length v == 176 = 10
-	| V.length v == 208 = 12
-	| otherwise         = 14
-
-initKey128, initKey192, initKey256 :: ByteString -> Either String Key
-
-initKey128 = initKey 16
-initKey192 = initKey 24
-initKey256 = initKey 32
-
-initKey :: Int -> ByteString -> Either String Key
-initKey sz b
-	| B.length b == sz = Right $ coreExpandKey (V.generate sz $ B.unsafeIndex b)
-	| otherwise        = Left "wrong key size"
-
-aesMain :: Int -> Key -> AESState -> IO ()
-aesMain nbr key blk = do
-	addRoundKey key 0 blk
-	forM_ [1..nbr-1] $ \i -> do
-		shiftRows blk >> mixColumns blk >> addRoundKey key i blk
-	shiftRows blk >> addRoundKey key nbr blk
-
-aesMainInv :: Int -> Key -> AESState -> IO ()
-aesMainInv nbr key blk = do
-	addRoundKey key nbr blk
-	forM_ (reverse [1..nbr-1]) $ \i -> do
-		shiftRowsInv blk >> addRoundKey key i blk >> mixColumnsInv blk
-	shiftRowsInv blk >> addRoundKey key 0 blk
-
-{-# INLINE swapIndex #-}
-swapIndex :: Int -> Int
-swapIndex 0 = 0
-swapIndex 1 = 4
-swapIndex 2 = 8
-swapIndex 3 = 12
-swapIndex 4 = 1
-swapIndex 5 = 5
-swapIndex 6 = 9
-swapIndex 7 = 13
-swapIndex 8 = 2
-swapIndex 9 = 6
-swapIndex 10 = 10
-swapIndex 11 = 14
-swapIndex 12 = 3
-swapIndex 13 = 7
-swapIndex 14 = 11
-swapIndex 15 = 15
-swapIndex _  = 0
-
-coreExpandKey :: Vector Word8 -> Key
-coreExpandKey vkey
-	| V.length vkey == 16 = Key (V.concat (ek0 : ekN16))
-	| V.length vkey == 24 = Key (V.concat (ek0 : ekN24))
-	| V.length vkey == 32 = Key (V.concat (ek0 : ekN32))
-	| otherwise           = Key (V.empty)
-	where
-		ek0 = vkey
-		ekN16 = reverse $ snd $ foldl (generateFold generate16) (ek0, []) [1..10]
-
-		ekN24 =
-			let (lk, acc) = foldl (generateFold generate24) (ek0, []) [1..7] in
-			let nk = generate16 lk 8 in
-			reverse (nk : acc)
-
-		ekN32 =
-			let (lk, acc) = foldl (generateFold generate32) (ek0, []) [1..6] in
-			let nk = generate16 lk 7 in
-			reverse (nk : acc)
-
-		generateFold gen (prevk, accK) it = let nk = gen prevk it in (nk, nk : accK)
-
-		generate16 prevk it =
-			let len = V.length prevk in
-			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)
-			                (V.unsafeIndex prevk $ len - 3)
-			                (V.unsafeIndex prevk $ len - 2)
-			                (V.unsafeIndex prevk $ len - 1) in
-			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in
-			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in
-			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in
-			let     (e12,e13,e14,e15) = xorVector prevk 12 eg2 in
-			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15]
-
-		generate24 prevk it =
-			let len = V.length prevk in
-			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)
-			                (V.unsafeIndex prevk $ len - 3)
-			                (V.unsafeIndex prevk $ len - 2)
-			                (V.unsafeIndex prevk $ len - 1) in
-			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in
-			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in
-			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in
-			let eg3@(e12,e13,e14,e15) = xorVector prevk 12 eg2 in
-			let eg4@(e16,e17,e18,e19) = xorVector prevk 16 eg3 in
-			let     (e20,e21,e22,e23) = xorVector prevk 20 eg4 in
-			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15,e16,e17,e18,e19,e20,e21,e22,e23]
-
-		generate32 prevk it =
-			let len = V.length prevk in
-			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)
-			                (V.unsafeIndex prevk $ len - 3)
-			                (V.unsafeIndex prevk $ len - 2)
-			                (V.unsafeIndex prevk $ len - 1) in
-			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in
-			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in
-			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in
-			let eg3@(e12,e13,e14,e15) = xorVector prevk 12 eg2 in
-			let eg4@(e16,e17,e18,e19) = xorSboxVector prevk 16 eg3 in
-			let eg5@(e20,e21,e22,e23) = xorVector prevk 20 eg4 in
-			let eg6@(e24,e25,e26,e27) = xorVector prevk 24 eg5 in
-			let     (e28,e29,e30,e31) = xorVector prevk 28 eg6 in
-			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15,e16
-			           ,e17,e18,e19,e20,e21,e22,e23,e24,e25,e26,e27,e28,e29,e30,e31]
-
-		xorVector k i (t0,t1,t2,t3) =
-			( V.unsafeIndex k (i+0) `xor` t0
-			, V.unsafeIndex k (i+1) `xor` t1
-			, V.unsafeIndex k (i+2) `xor` t2
-			, V.unsafeIndex k (i+3) `xor` t3
-			)
-
-		xorSboxVector k i (t0,t1,t2,t3) =
-			( V.unsafeIndex k (i+0) `xor` sbox t0
-			, V.unsafeIndex k (i+1) `xor` sbox t1
-			, V.unsafeIndex k (i+2) `xor` sbox t2
-			, V.unsafeIndex k (i+3) `xor` sbox t3
-			)
-
-		cR0 it r0 r1 r2 r3 =
-			(sbox r1 `xor` mRcon it, sbox r2, sbox r3, sbox r0)
-
-{-# INLINE shiftRows #-}
-shiftRows :: AESState -> IO ()
-shiftRows blk = do
-	r32 blk 0 >>= w32 blk 0 . msbox32
-	r32 blk 1 >>= \t1 -> w32 blk 1 $ rotateR (msbox32 t1) 8
-	r32 blk 2 >>= \t2 -> w32 blk 2 $ rotateR (msbox32 t2) 16
-	r32 blk 3 >>= \t3 -> w32 blk 3 $ rotateR (msbox32 t3) 24
-
-{-# INLINE addRoundKey #-}
-addRoundKey :: Key -> Int -> AESState -> IO ()
-addRoundKey (Key key) i blk = forM_ [0..15] $ \n -> do
-	r8 blk n >>= \v1 -> w8 blk n $ v1 `xor` V.unsafeIndex key (16 * i + swapIndex n)
-
-{-# INLINE mixColumns #-}
-mixColumns :: AESState -> IO ()
-mixColumns state = pr 0 >> pr 1 >> pr 2 >> pr 3
-	where
-		{-# INLINE pr #-}
-		pr i = do
-			cpy0 <- r8 state (0 * 4 + i)
-			cpy1 <- r8 state (1 * 4 + i)
-			cpy2 <- r8 state (2 * 4 + i)
-			cpy3 <- r8 state (3 * 4 + i)
-
-			let state0 = gm2 cpy0 `xor` gm1 cpy3 `xor` gm1 cpy2 `xor` gm3 cpy1
-			let state4 = gm2 cpy1 `xor` gm1 cpy0 `xor` gm1 cpy3 `xor` gm3 cpy2
-			let state8 = gm2 cpy2 `xor` gm1 cpy1 `xor` gm1 cpy0 `xor` gm3 cpy3
-			let state12 = gm2 cpy3 `xor` gm1 cpy2 `xor` gm1 cpy1 `xor` gm3 cpy0
-
-			w8 state (0 * 4 + i) state0
-			w8 state (1 * 4 + i) state4
-			w8 state (2 * 4 + i) state8
-			w8 state (3 * 4 + i) state12
-		{-# INLINE gm1 #-}
-		gm1 a = a
-		{-# INLINE gm2 #-}
-		gm2 a = V.unsafeIndex gmtab2 $ fromIntegral a
-		{-# INLINE gm3 #-}
-		gm3 a = V.unsafeIndex gmtab3 $ fromIntegral a
-
-{-# INLINE shiftRowsInv #-}
-shiftRowsInv :: AESState -> IO ()
-shiftRowsInv blk = do
-	r32 blk 0 >>= w32 blk 0 . mrsbox32
-	r32 blk 1 >>= \t1 -> w32 blk 1 $ mrsbox32 $ rotateL t1 8
-	r32 blk 2 >>= \t2 -> w32 blk 2 $ mrsbox32 $ rotateL t2 16
-	r32 blk 3 >>= \t3 -> w32 blk 3 $ mrsbox32 $ rotateL t3 24
-
-{-# INLINE mixColumnsInv #-}
-mixColumnsInv :: AESState -> IO ()
-mixColumnsInv state = pr 0 >> pr 1 >> pr 2 >> pr 3
-	where
-		{-# INLINE pr #-}
-		pr i = do
-			cpy0 <- r8 state (0 * 4 + i)
-			cpy1 <- r8 state (1 * 4 + i)
-			cpy2 <- r8 state (2 * 4 + i)
-			cpy3 <- r8 state (3 * 4 + i)
-
-			let state0  = gm14 cpy0 `xor` gm9 cpy3 `xor` gm13 cpy2 `xor` gm11 cpy1
-			let state4  = gm14 cpy1 `xor` gm9 cpy0 `xor` gm13 cpy3 `xor` gm11 cpy2
-			let state8  = gm14 cpy2 `xor` gm9 cpy1 `xor` gm13 cpy0 `xor` gm11 cpy3
-			let state12 = gm14 cpy3 `xor` gm9 cpy2 `xor` gm13 cpy1 `xor` gm11 cpy0
-
-			w8 state (0 * 4 + i) state0
-			w8 state (1 * 4 + i) state4
-			w8 state (2 * 4 + i) state8
-			w8 state (3 * 4 + i) state12
-
-		{-# INLINE gm14 #-}
-		{-# INLINE gm13 #-}
-		{-# INLINE gm11 #-}
-		{-# INLINE gm9 #-}
-		gm14 a = V.unsafeIndex gmtab14 $ fromIntegral a
-		gm13 a = V.unsafeIndex gmtab13 $ fromIntegral a
-		gm11 a = V.unsafeIndex gmtab11 $ fromIntegral a
-		gm9 a  = V.unsafeIndex gmtab9 $ fromIntegral a
-
-{-# INLINE r8 #-}
-r8 :: AESState -> Int -> IO Word8
-r8 = readByteArray
-
-{-# INLINE w8 #-}
-w8 :: AESState -> Int -> Word8 -> IO ()
-w8 = writeByteArray
-
-{-# INLINE r32 #-}
-r32 :: AESState -> Int -> IO Word32
-r32 = readByteArray
-
-{-# INLINE w32 #-}
-w32 :: AESState -> Int -> Word32 -> IO ()
-w32 = writeByteArray
-
-msbox32 :: Word32 -> Word32
-msbox32 w = sbox4 a .|. sbox3 b .|. sbox2 c .|. sbox1 d
-	where
-		a = fromIntegral (w `shiftR` 24)
-		b = fromIntegral (w `shiftR` 16)
-		c = fromIntegral (w `shiftR` 8)
-		d = fromIntegral w
-
-mrsbox32 :: Word32 -> Word32
-mrsbox32 w = fromIntegral (rsbox a) `shiftL` 24 .|.
-             fromIntegral (rsbox b) `shiftL` 16 .|.
-             fromIntegral (rsbox c) `shiftL` 8  .|.
-             fromIntegral (rsbox d)
-	where
-		a = fromIntegral (w `shiftR` 24)
-		b = fromIntegral (w `shiftR` 16)
-		c = fromIntegral (w `shiftR` 8)
-		d = fromIntegral w
-
-
-{-# INLINE swapBlock #-}
-swapBlock :: ByteString -> AESState -> IO ()
-swapBlock b blk = do -- V.generate 16 (\i -> B.unsafeIndex b $ swapIndex i)
-	forM_ [0..15] $ \i -> w8 blk i $ B.unsafeIndex b $ swapIndex i
-
-{-# INLINE swapBlockInv #-}
-swapBlockInv :: AESState -> Ptr Word8 -> IO ()
-swapBlockInv blk ptr = forM_ [0..15] $ \i -> r8 blk (swapIndex i) >>= pokeByteOff ptr i
-
-{-# INLINE mRcon #-}
-mRcon :: Int -> Word8
-mRcon i = V.unsafeIndex rcon (i `mod` len)
-	where len = V.length rcon
-
-{-# INLINE sbox #-}
-sbox :: Word8 -> Word8
-sbox = V.unsafeIndex tab . fromIntegral
-	where tab = V.fromList
-		[ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
-		, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
-		, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
-		, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
-		, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
-		, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
-		, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
-		, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
-		, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
-		, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
-		, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
-		, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
-		, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
-		, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
-		, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
-		, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
-		, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
-		, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
-		, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
-		, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
-		, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
-		, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
-		, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
-		, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
-		, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
-		, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
-		, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
-		, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
-		, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
-		, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
-		, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
-		, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
-		]
-
-sbox1, sbox2, sbox3, sbox4 :: Word8 -> Word32
-
-sbox1 = V.unsafeIndex tab . fromIntegral
-	where tab = V.fromList
-		[ 0x00000063, 0x0000007c, 0x00000077, 0x0000007b
-		, 0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5
-		, 0x00000030, 0x00000001, 0x00000067, 0x0000002b
-		, 0x000000fe, 0x000000d7, 0x000000ab, 0x00000076
-		, 0x000000ca, 0x00000082, 0x000000c9, 0x0000007d
-		, 0x000000fa, 0x00000059, 0x00000047, 0x000000f0
-		, 0x000000ad, 0x000000d4, 0x000000a2, 0x000000af
-		, 0x0000009c, 0x000000a4, 0x00000072, 0x000000c0
-		, 0x000000b7, 0x000000fd, 0x00000093, 0x00000026
-		, 0x00000036, 0x0000003f, 0x000000f7, 0x000000cc
-		, 0x00000034, 0x000000a5, 0x000000e5, 0x000000f1
-		, 0x00000071, 0x000000d8, 0x00000031, 0x00000015
-		, 0x00000004, 0x000000c7, 0x00000023, 0x000000c3
-		, 0x00000018, 0x00000096, 0x00000005, 0x0000009a
-		, 0x00000007, 0x00000012, 0x00000080, 0x000000e2
-		, 0x000000eb, 0x00000027, 0x000000b2, 0x00000075
-		, 0x00000009, 0x00000083, 0x0000002c, 0x0000001a
-		, 0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0
-		, 0x00000052, 0x0000003b, 0x000000d6, 0x000000b3
-		, 0x00000029, 0x000000e3, 0x0000002f, 0x00000084
-		, 0x00000053, 0x000000d1, 0x00000000, 0x000000ed
-		, 0x00000020, 0x000000fc, 0x000000b1, 0x0000005b
-		, 0x0000006a, 0x000000cb, 0x000000be, 0x00000039
-		, 0x0000004a, 0x0000004c, 0x00000058, 0x000000cf
-		, 0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb
-		, 0x00000043, 0x0000004d, 0x00000033, 0x00000085
-		, 0x00000045, 0x000000f9, 0x00000002, 0x0000007f
-		, 0x00000050, 0x0000003c, 0x0000009f, 0x000000a8
-		, 0x00000051, 0x000000a3, 0x00000040, 0x0000008f
-		, 0x00000092, 0x0000009d, 0x00000038, 0x000000f5
-		, 0x000000bc, 0x000000b6, 0x000000da, 0x00000021
-		, 0x00000010, 0x000000ff, 0x000000f3, 0x000000d2
-		, 0x000000cd, 0x0000000c, 0x00000013, 0x000000ec
-		, 0x0000005f, 0x00000097, 0x00000044, 0x00000017
-		, 0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d
-		, 0x00000064, 0x0000005d, 0x00000019, 0x00000073
-		, 0x00000060, 0x00000081, 0x0000004f, 0x000000dc
-		, 0x00000022, 0x0000002a, 0x00000090, 0x00000088
-		, 0x00000046, 0x000000ee, 0x000000b8, 0x00000014
-		, 0x000000de, 0x0000005e, 0x0000000b, 0x000000db
-		, 0x000000e0, 0x00000032, 0x0000003a, 0x0000000a
-		, 0x00000049, 0x00000006, 0x00000024, 0x0000005c
-		, 0x000000c2, 0x000000d3, 0x000000ac, 0x00000062
-		, 0x00000091, 0x00000095, 0x000000e4, 0x00000079
-		, 0x000000e7, 0x000000c8, 0x00000037, 0x0000006d
-		, 0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9
-		, 0x0000006c, 0x00000056, 0x000000f4, 0x000000ea
-		, 0x00000065, 0x0000007a, 0x000000ae, 0x00000008
-		, 0x000000ba, 0x00000078, 0x00000025, 0x0000002e
-		, 0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6
-		, 0x000000e8, 0x000000dd, 0x00000074, 0x0000001f
-		, 0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a
-		, 0x00000070, 0x0000003e, 0x000000b5, 0x00000066
-		, 0x00000048, 0x00000003, 0x000000f6, 0x0000000e
-		, 0x00000061, 0x00000035, 0x00000057, 0x000000b9
-		, 0x00000086, 0x000000c1, 0x0000001d, 0x0000009e
-		, 0x000000e1, 0x000000f8, 0x00000098, 0x00000011
-		, 0x00000069, 0x000000d9, 0x0000008e, 0x00000094
-		, 0x0000009b, 0x0000001e, 0x00000087, 0x000000e9
-		, 0x000000ce, 0x00000055, 0x00000028, 0x000000df
-		, 0x0000008c, 0x000000a1, 0x00000089, 0x0000000d
-		, 0x000000bf, 0x000000e6, 0x00000042, 0x00000068
-		, 0x00000041, 0x00000099, 0x0000002d, 0x0000000f
-		, 0x000000b0, 0x00000054, 0x000000bb, 0x00000016
-		]
-
-sbox2 = V.unsafeIndex tab . fromIntegral
-	where tab = V.fromList
-		[ 0x00006300, 0x00007c00, 0x00007700, 0x00007b00
-		, 0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500
-		, 0x00003000, 0x00000100, 0x00006700, 0x00002b00
-		, 0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600
-		, 0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00
-		, 0x0000fa00, 0x00005900, 0x00004700, 0x0000f000
-		, 0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00
-		, 0x00009c00, 0x0000a400, 0x00007200, 0x0000c000
-		, 0x0000b700, 0x0000fd00, 0x00009300, 0x00002600
-		, 0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00
-		, 0x00003400, 0x0000a500, 0x0000e500, 0x0000f100
-		, 0x00007100, 0x0000d800, 0x00003100, 0x00001500
-		, 0x00000400, 0x0000c700, 0x00002300, 0x0000c300
-		, 0x00001800, 0x00009600, 0x00000500, 0x00009a00
-		, 0x00000700, 0x00001200, 0x00008000, 0x0000e200
-		, 0x0000eb00, 0x00002700, 0x0000b200, 0x00007500
-		, 0x00000900, 0x00008300, 0x00002c00, 0x00001a00
-		, 0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000
-		, 0x00005200, 0x00003b00, 0x0000d600, 0x0000b300
-		, 0x00002900, 0x0000e300, 0x00002f00, 0x00008400
-		, 0x00005300, 0x0000d100, 0x00000000, 0x0000ed00
-		, 0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00
-		, 0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900
-		, 0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00
-		, 0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00
-		, 0x00004300, 0x00004d00, 0x00003300, 0x00008500
-		, 0x00004500, 0x0000f900, 0x00000200, 0x00007f00
-		, 0x00005000, 0x00003c00, 0x00009f00, 0x0000a800
-		, 0x00005100, 0x0000a300, 0x00004000, 0x00008f00
-		, 0x00009200, 0x00009d00, 0x00003800, 0x0000f500
-		, 0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100
-		, 0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200
-		, 0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00
-		, 0x00005f00, 0x00009700, 0x00004400, 0x00001700
-		, 0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00
-		, 0x00006400, 0x00005d00, 0x00001900, 0x00007300
-		, 0x00006000, 0x00008100, 0x00004f00, 0x0000dc00
-		, 0x00002200, 0x00002a00, 0x00009000, 0x00008800
-		, 0x00004600, 0x0000ee00, 0x0000b800, 0x00001400
-		, 0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00
-		, 0x0000e000, 0x00003200, 0x00003a00, 0x00000a00
-		, 0x00004900, 0x00000600, 0x00002400, 0x00005c00
-		, 0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200
-		, 0x00009100, 0x00009500, 0x0000e400, 0x00007900
-		, 0x0000e700, 0x0000c800, 0x00003700, 0x00006d00
-		, 0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900
-		, 0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00
-		, 0x00006500, 0x00007a00, 0x0000ae00, 0x00000800
-		, 0x0000ba00, 0x00007800, 0x00002500, 0x00002e00
-		, 0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600
-		, 0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00
-		, 0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00
-		, 0x00007000, 0x00003e00, 0x0000b500, 0x00006600
-		, 0x00004800, 0x00000300, 0x0000f600, 0x00000e00
-		, 0x00006100, 0x00003500, 0x00005700, 0x0000b900
-		, 0x00008600, 0x0000c100, 0x00001d00, 0x00009e00
-		, 0x0000e100, 0x0000f800, 0x00009800, 0x00001100
-		, 0x00006900, 0x0000d900, 0x00008e00, 0x00009400
-		, 0x00009b00, 0x00001e00, 0x00008700, 0x0000e900
-		, 0x0000ce00, 0x00005500, 0x00002800, 0x0000df00
-		, 0x00008c00, 0x0000a100, 0x00008900, 0x00000d00
-		, 0x0000bf00, 0x0000e600, 0x00004200, 0x00006800
-		, 0x00004100, 0x00009900, 0x00002d00, 0x00000f00
-		, 0x0000b000, 0x00005400, 0x0000bb00, 0x00001600
-		]
-
-sbox3 = V.unsafeIndex tab . fromIntegral
-	where tab = V.fromList
-		[ 0x00630000, 0x007c0000, 0x00770000, 0x007b0000
-		, 0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000
-		, 0x00300000, 0x00010000, 0x00670000, 0x002b0000
-		, 0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000
-		, 0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000
-		, 0x00fa0000, 0x00590000, 0x00470000, 0x00f00000
-		, 0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000
-		, 0x009c0000, 0x00a40000, 0x00720000, 0x00c00000
-		, 0x00b70000, 0x00fd0000, 0x00930000, 0x00260000
-		, 0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000
-		, 0x00340000, 0x00a50000, 0x00e50000, 0x00f10000
-		, 0x00710000, 0x00d80000, 0x00310000, 0x00150000
-		, 0x00040000, 0x00c70000, 0x00230000, 0x00c30000
-		, 0x00180000, 0x00960000, 0x00050000, 0x009a0000
-		, 0x00070000, 0x00120000, 0x00800000, 0x00e20000
-		, 0x00eb0000, 0x00270000, 0x00b20000, 0x00750000
-		, 0x00090000, 0x00830000, 0x002c0000, 0x001a0000
-		, 0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000
-		, 0x00520000, 0x003b0000, 0x00d60000, 0x00b30000
-		, 0x00290000, 0x00e30000, 0x002f0000, 0x00840000
-		, 0x00530000, 0x00d10000, 0x00000000, 0x00ed0000
-		, 0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000
-		, 0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000
-		, 0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000
-		, 0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000
-		, 0x00430000, 0x004d0000, 0x00330000, 0x00850000
-		, 0x00450000, 0x00f90000, 0x00020000, 0x007f0000
-		, 0x00500000, 0x003c0000, 0x009f0000, 0x00a80000
-		, 0x00510000, 0x00a30000, 0x00400000, 0x008f0000
-		, 0x00920000, 0x009d0000, 0x00380000, 0x00f50000
-		, 0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000
-		, 0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000
-		, 0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000
-		, 0x005f0000, 0x00970000, 0x00440000, 0x00170000
-		, 0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000
-		, 0x00640000, 0x005d0000, 0x00190000, 0x00730000
-		, 0x00600000, 0x00810000, 0x004f0000, 0x00dc0000
-		, 0x00220000, 0x002a0000, 0x00900000, 0x00880000
-		, 0x00460000, 0x00ee0000, 0x00b80000, 0x00140000
-		, 0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000
-		, 0x00e00000, 0x00320000, 0x003a0000, 0x000a0000
-		, 0x00490000, 0x00060000, 0x00240000, 0x005c0000
-		, 0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000
-		, 0x00910000, 0x00950000, 0x00e40000, 0x00790000
-		, 0x00e70000, 0x00c80000, 0x00370000, 0x006d0000
-		, 0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000
-		, 0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000
-		, 0x00650000, 0x007a0000, 0x00ae0000, 0x00080000
-		, 0x00ba0000, 0x00780000, 0x00250000, 0x002e0000
-		, 0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000
-		, 0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000
-		, 0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000
-		, 0x00700000, 0x003e0000, 0x00b50000, 0x00660000
-		, 0x00480000, 0x00030000, 0x00f60000, 0x000e0000
-		, 0x00610000, 0x00350000, 0x00570000, 0x00b90000
-		, 0x00860000, 0x00c10000, 0x001d0000, 0x009e0000
-		, 0x00e10000, 0x00f80000, 0x00980000, 0x00110000
-		, 0x00690000, 0x00d90000, 0x008e0000, 0x00940000
-		, 0x009b0000, 0x001e0000, 0x00870000, 0x00e90000
-		, 0x00ce0000, 0x00550000, 0x00280000, 0x00df0000
-		, 0x008c0000, 0x00a10000, 0x00890000, 0x000d0000
-		, 0x00bf0000, 0x00e60000, 0x00420000, 0x00680000
-		, 0x00410000, 0x00990000, 0x002d0000, 0x000f0000
-		, 0x00b00000, 0x00540000, 0x00bb0000, 0x00160000
-		]
-
-sbox4 = V.unsafeIndex tab . fromIntegral
-	where tab = V.fromList
-		[ 0x63000000, 0x7c000000, 0x77000000, 0x7b000000
-		, 0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000
-		, 0x30000000, 0x01000000, 0x67000000, 0x2b000000
-		, 0xfe000000, 0xd7000000, 0xab000000, 0x76000000
-		, 0xca000000, 0x82000000, 0xc9000000, 0x7d000000
-		, 0xfa000000, 0x59000000, 0x47000000, 0xf0000000
-		, 0xad000000, 0xd4000000, 0xa2000000, 0xaf000000
-		, 0x9c000000, 0xa4000000, 0x72000000, 0xc0000000
-		, 0xb7000000, 0xfd000000, 0x93000000, 0x26000000
-		, 0x36000000, 0x3f000000, 0xf7000000, 0xcc000000
-		, 0x34000000, 0xa5000000, 0xe5000000, 0xf1000000
-		, 0x71000000, 0xd8000000, 0x31000000, 0x15000000
-		, 0x04000000, 0xc7000000, 0x23000000, 0xc3000000
-		, 0x18000000, 0x96000000, 0x05000000, 0x9a000000
-		, 0x07000000, 0x12000000, 0x80000000, 0xe2000000
-		, 0xeb000000, 0x27000000, 0xb2000000, 0x75000000
-		, 0x09000000, 0x83000000, 0x2c000000, 0x1a000000
-		, 0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000
-		, 0x52000000, 0x3b000000, 0xd6000000, 0xb3000000
-		, 0x29000000, 0xe3000000, 0x2f000000, 0x84000000
-		, 0x53000000, 0xd1000000, 0x00000000, 0xed000000
-		, 0x20000000, 0xfc000000, 0xb1000000, 0x5b000000
-		, 0x6a000000, 0xcb000000, 0xbe000000, 0x39000000
-		, 0x4a000000, 0x4c000000, 0x58000000, 0xcf000000
-		, 0xd0000000, 0xef000000, 0xaa000000, 0xfb000000
-		, 0x43000000, 0x4d000000, 0x33000000, 0x85000000
-		, 0x45000000, 0xf9000000, 0x02000000, 0x7f000000
-		, 0x50000000, 0x3c000000, 0x9f000000, 0xa8000000
-		, 0x51000000, 0xa3000000, 0x40000000, 0x8f000000
-		, 0x92000000, 0x9d000000, 0x38000000, 0xf5000000
-		, 0xbc000000, 0xb6000000, 0xda000000, 0x21000000
-		, 0x10000000, 0xff000000, 0xf3000000, 0xd2000000
-		, 0xcd000000, 0x0c000000, 0x13000000, 0xec000000
-		, 0x5f000000, 0x97000000, 0x44000000, 0x17000000
-		, 0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000
-		, 0x64000000, 0x5d000000, 0x19000000, 0x73000000
-		, 0x60000000, 0x81000000, 0x4f000000, 0xdc000000
-		, 0x22000000, 0x2a000000, 0x90000000, 0x88000000
-		, 0x46000000, 0xee000000, 0xb8000000, 0x14000000
-		, 0xde000000, 0x5e000000, 0x0b000000, 0xdb000000
-		, 0xe0000000, 0x32000000, 0x3a000000, 0x0a000000
-		, 0x49000000, 0x06000000, 0x24000000, 0x5c000000
-		, 0xc2000000, 0xd3000000, 0xac000000, 0x62000000
-		, 0x91000000, 0x95000000, 0xe4000000, 0x79000000
-		, 0xe7000000, 0xc8000000, 0x37000000, 0x6d000000
-		, 0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000
-		, 0x6c000000, 0x56000000, 0xf4000000, 0xea000000
-		, 0x65000000, 0x7a000000, 0xae000000, 0x08000000
-		, 0xba000000, 0x78000000, 0x25000000, 0x2e000000
-		, 0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000
-		, 0xe8000000, 0xdd000000, 0x74000000, 0x1f000000
-		, 0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000
-		, 0x70000000, 0x3e000000, 0xb5000000, 0x66000000
-		, 0x48000000, 0x03000000, 0xf6000000, 0x0e000000
-		, 0x61000000, 0x35000000, 0x57000000, 0xb9000000
-		, 0x86000000, 0xc1000000, 0x1d000000, 0x9e000000
-		, 0xe1000000, 0xf8000000, 0x98000000, 0x11000000
-		, 0x69000000, 0xd9000000, 0x8e000000, 0x94000000
-		, 0x9b000000, 0x1e000000, 0x87000000, 0xe9000000
-		, 0xce000000, 0x55000000, 0x28000000, 0xdf000000
-		, 0x8c000000, 0xa1000000, 0x89000000, 0x0d000000
-		, 0xbf000000, 0xe6000000, 0x42000000, 0x68000000
-		, 0x41000000, 0x99000000, 0x2d000000, 0x0f000000
-		, 0xb0000000, 0x54000000, 0xbb000000, 0x16000000
-		]
-
-{-# INLINE rsbox #-}
-rsbox :: Word8 -> Word8
-rsbox = V.unsafeIndex tab . fromIntegral
-	where tab = V.fromList
-		[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
-		, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
-		, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
-		, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
-		, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
-		, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
-		, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
-		, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
-		, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
-		, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
-		, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
-		, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
-		, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
-		, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
-		, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
-		, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
-		, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
-		, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
-		, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
-		, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
-		, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
-		, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
-		, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
-		, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
-		, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
-		, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
-		, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
-		, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
-		, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
-		, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
-		, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
-		, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
-		]
-
-rcon :: Vector Word8
-rcon = V.fromList
-	[ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40
-	, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a
-	, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a
-	, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39
-	, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25
-	, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a
-	, 0x74, 0xe8, 0xcb
-	]
-
-gmtab2, gmtab3, gmtab9, gmtab11, gmtab13, gmtab14 :: Vector Word8
-gmtab2 = V.fromList
-	[ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e
-	, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e
-	, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e
-	, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e
-	, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e
-	, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e
-	, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e
-	, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e
-	, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e
-	, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e
-	, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae
-	, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe
-	, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce
-	, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde
-	, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee
-	, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe
-	, 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15
-	, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05
-	, 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35
-	, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25
-	, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55
-	, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45
-	, 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75
-	, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65
-	, 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95
-	, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85
-	, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5
-	, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5
-	, 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5
-	, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5
-	, 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5
-	, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
-	]
-
-gmtab3 = V.fromList
-	[ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09
-	, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11
-	, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39
-	, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21
-	, 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69
-	, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71
-	, 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59
-	, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41
-	, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9
-	, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1
-	, 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9
-	, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1
-	, 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9
-	, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1
-	, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99
-	, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81
-	, 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92
-	, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a
-	, 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2
-	, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba
-	, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2
-	, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea
-	, 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2
-	, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda
-	, 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52
-	, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a
-	, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62
-	, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a
-	, 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32
-	, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a
-	, 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02
-	, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
-	]
-
-gmtab9 = V.fromList
-	[ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f
-	, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77
-	, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf
-	, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7
-	, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04
-	, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c
-	, 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94
-	, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc
-	, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49
-	, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01
-	, 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9
-	, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91
-	, 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72
-	, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a
-	, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2
-	, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa
-	, 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3
-	, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b
-	, 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43
-	, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b
-	, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8
-	, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0
-	, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78
-	, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30
-	, 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5
-	, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed
-	, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35
-	, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d
-	, 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e
-	, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6
-	, 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e
-	, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
-	]
-
-gmtab11 = V.fromList
-	[ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31
-	, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69
-	, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81
-	, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9
-	, 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a
-	, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12
-	, 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa
-	, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2
-	, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7
-	, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f
-	, 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77
-	, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f
-	, 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc
-	, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4
-	, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c
-	, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54
-	, 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6
-	, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e
-	, 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76
-	, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e
-	, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd
-	, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5
-	, 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d
-	, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55
-	, 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30
-	, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68
-	, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80
-	, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8
-	, 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b
-	, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13
-	, 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb
-	, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
-	]
-
-gmtab13 = V.fromList
-	[ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23
-	, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b
-	, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3
-	, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b
-	, 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98
-	, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0
-	, 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48
-	, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20
-	, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e
-	, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26
-	, 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e
-	, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6
-	, 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5
-	, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d
-	, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25
-	, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d
-	, 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9
-	, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91
-	, 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29
-	, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41
-	, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42
-	, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a
-	, 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92
-	, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa
-	, 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94
-	, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc
-	, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44
-	, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c
-	, 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f
-	, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47
-	, 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff
-	, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
-	]
-
-gmtab14 = V.fromList
-	[ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a
-	, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a
-	, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca
-	, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba
-	, 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1
-	, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81
-	, 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11
-	, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61
-	, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87
-	, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7
-	, 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67
-	, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17
-	, 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c
-	, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c
-	, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc
-	, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc
-	, 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b
-	, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b
-	, 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b
-	, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb
-	, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0
-	, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0
-	, 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50
-	, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20
-	, 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6
-	, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6
-	, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26
-	, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56
-	, 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d
-	, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d
-	, 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd
-	, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
-	]
+{-# LANGUAGE MagicHash #-}
+-- |
+-- Module      : Crypto.Cipher.AES
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+
+module Crypto.Cipher.AES
+	( Key
+	, IV
+	-- * Basic encryption and decryption
+	, encrypt
+	, decrypt
+	-- * CBC encryption and decryption
+	, encryptCBC
+	, decryptCBC
+	-- * key building mechanism
+	, initKey128
+	, initKey192
+	, initKey256
+	-- * Wrappers for "crypto-api" instances
+	, AES128
+	, AES192
+	, AES256
+	) where
+
+import Data.Word
+import Data.Vector.Unboxed (Vector)
+import qualified Data.Vector.Unboxed as V
+import Data.Bits
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Unsafe as B
+import qualified Data.ByteString.Internal as B
+
+import GHC.Prim (indexWord8OffAddr#, indexWord32OffAddr#, word2Int#, Addr#, remInt#)
+import GHC.Word
+import GHC.Types
+
+import Foreign.Ptr
+import Foreign.Storable
+
+import Data.Tagged (Tagged(..))
+import Crypto.Classes (BlockCipher(..))
+import Data.Serialize (Serialize(..), getByteString, putByteString)
+
+import Control.Monad (forM_)
+import Control.Monad.Primitive
+
+import Data.Primitive.ByteArray
+
+import System.Endian (littleEndian)
+
+newtype AES128 = A128 { unA128 :: Key }
+newtype AES192 = A192 { unA192 :: Key }
+newtype AES256 = A256 { unA256 :: Key }
+
+instance BlockCipher AES128 where
+	blockSize    = Tagged 128
+	encryptBlock = encrypt . unA128
+	decryptBlock = decrypt . unA128
+	buildKey b   = either (const Nothing) (Just . A128) $ initKey128 b
+	keyLength    = Tagged 128
+
+instance BlockCipher AES192 where
+	blockSize    = Tagged 128
+	encryptBlock = encrypt . unA192
+	decryptBlock = decrypt . unA192
+	buildKey b   = either (const Nothing) (Just . A192) $ initKey192 b
+	keyLength    = Tagged 192
+
+instance BlockCipher AES256 where
+	blockSize    = Tagged 128
+	encryptBlock = encrypt . unA256
+	decryptBlock = decrypt . unA256
+	buildKey b   = either (const Nothing) (Just . A256) $ initKey256 b
+	keyLength    = Tagged 256
+
+serializeKey :: Key -> ByteString
+serializeKey (Key v)
+	| V.length v == 176 = B.pack $ map (V.unsafeIndex v) [0..15]
+	| V.length v == 208 = B.pack $ map (V.unsafeIndex v) [0..23]
+	| otherwise         = B.pack $ map (V.unsafeIndex v) [0..31]
+
+instance Serialize AES128 where
+	put = putByteString . serializeKey . unA128
+	get = do
+		raw <- getByteString (128 `div` 8)
+		case buildKey raw of
+			Nothing -> fail "Invalid raw key material."
+			Just k  -> return k
+
+instance Serialize AES192 where
+	put = putByteString . serializeKey . unA192
+	get = do
+		raw <- getByteString (192 `div` 8)
+		case buildKey raw of
+			Nothing -> fail "Invalid raw key material."
+			Just k  -> return k
+
+instance Serialize AES256 where
+	put = putByteString . serializeKey . unA256
+	get = do
+		raw <- getByteString (256 `div` 8)
+		case buildKey raw of
+			Nothing -> fail "Invalid raw key material."
+			Just k  -> return k
+
+data Key = Key (Vector Word8)
+	deriving (Show,Eq)
+
+type IV = B.ByteString
+
+type AESState = MutableByteArray RealWorld
+
+{- | encrypt using CBC mode
+ - IV need to be 16 bytes and the data to encrypt a multiple of 16 bytes -}
+encryptCBC :: Key -> IV -> B.ByteString -> B.ByteString
+encryptCBC key iv b
+	| B.length iv /= 16        = error "invalid IV length"
+	| B.length b `mod` 16 /= 0 = error "invalid data length"
+	| otherwise                = B.concat $ encryptIter iv (makeChunks b)
+		where
+			encryptIter _   []     = []
+			encryptIter iv' (x:xs) =
+				let r = coreEncrypt key $ B.pack $ B.zipWith xor iv' x in
+				r : encryptIter r xs
+
+{- | encrypt using simple EBC mode -}
+encrypt :: Key -> B.ByteString -> B.ByteString
+encrypt key b
+	| B.length b `mod` 16 /= 0 = error "invalid data length"
+	| otherwise                = B.concat $ doChunks (coreEncrypt key) b
+
+{- | decrypt using CBC mode
+ - IV need to be 16 bytes and the data to decrypt a multiple of 16 bytes -}
+decryptCBC :: Key -> IV -> B.ByteString -> B.ByteString
+decryptCBC key iv b
+	| B.length iv /= 16        = error "invalid IV length"
+	| B.length b `mod` 16 /= 0 = error "invalid data length"
+	| otherwise                = B.concat $ decryptIter iv (makeChunks b)
+		where
+			decryptIter _   []     = []
+			decryptIter iv' (x:xs) =
+				let r = B.pack $ B.zipWith xor iv' $ coreDecrypt key x in
+				r : decryptIter x xs
+
+{- | decrypt using simple EBC mode -}
+decrypt :: Key -> B.ByteString -> B.ByteString
+decrypt key b
+	| B.length b `mod` 16 /= 0 = error "invalid data length"
+	| otherwise                = B.concat $ doChunks (coreDecrypt key) b
+
+doChunks :: (B.ByteString -> B.ByteString) -> B.ByteString -> [B.ByteString]
+doChunks f b =
+	let (x, rest) = B.splitAt 16 b in
+	if B.length rest >= 16
+		then f x : doChunks f rest
+		else [ f x ]
+
+makeChunks :: B.ByteString -> [B.ByteString]
+makeChunks = doChunks id
+
+newAESState :: IO AESState
+newAESState = newAlignedPinnedByteArray 16 16
+
+coreEncrypt :: Key -> ByteString -> ByteString
+coreEncrypt key input = B.unsafeCreate (B.length input) $ \ptr -> do
+	st <- newAESState
+	swapBlock input st
+	aesMain (getNbr key) key st
+	swapBlockInv st ptr
+
+coreDecrypt :: Key -> ByteString -> ByteString
+coreDecrypt key input = B.unsafeCreate (B.length input) $ \ptr -> do
+	st <- newAESState
+	swapBlock input st
+	aesMainInv (getNbr key) key st
+	swapBlockInv st ptr
+
+getNbr :: Key -> Int
+getNbr (Key v)
+	| V.length v == 176 = 10
+	| V.length v == 208 = 12
+	| otherwise         = 14
+
+initKey128, initKey192, initKey256 :: ByteString -> Either String Key
+
+initKey128 = initKey 16
+initKey192 = initKey 24
+initKey256 = initKey 32
+
+initKey :: Int -> ByteString -> Either String Key
+initKey sz b
+	| B.length b == sz = Right $ coreExpandKey (V.generate sz $ B.unsafeIndex b)
+	| otherwise        = Left "wrong key size"
+
+aesMain :: Int -> Key -> AESState -> IO ()
+aesMain nbr key blk = do
+	addRoundKey key 0 blk
+	forM_ [1..nbr-1] $ \i -> do
+		shiftRows blk >> mixColumns blk >> addRoundKey key i blk
+	shiftRows blk >> addRoundKey key nbr blk
+
+aesMainInv :: Int -> Key -> AESState -> IO ()
+aesMainInv nbr key blk = do
+	addRoundKey key nbr blk
+	forM_ (reverse [1..nbr-1]) $ \i -> do
+		shiftRowsInv blk >> addRoundKey key i blk >> mixColumnsInv blk
+	shiftRowsInv blk >> addRoundKey key 0 blk
+
+{-# INLINE swapIndex #-}
+swapIndex :: Int -> Int
+swapIndex 0 = 0
+swapIndex 1 = 4
+swapIndex 2 = 8
+swapIndex 3 = 12
+swapIndex 4 = 1
+swapIndex 5 = 5
+swapIndex 6 = 9
+swapIndex 7 = 13
+swapIndex 8 = 2
+swapIndex 9 = 6
+swapIndex 10 = 10
+swapIndex 11 = 14
+swapIndex 12 = 3
+swapIndex 13 = 7
+swapIndex 14 = 11
+swapIndex 15 = 15
+swapIndex _  = 0
+
+coreExpandKey :: Vector Word8 -> Key
+coreExpandKey vkey
+	| V.length vkey == 16 = Key (V.concat (ek0 : ekN16))
+	| V.length vkey == 24 = Key (V.concat (ek0 : ekN24))
+	| V.length vkey == 32 = Key (V.concat (ek0 : ekN32))
+	| otherwise           = Key (V.empty)
+	where
+		ek0 = vkey
+		ekN16 = reverse $ snd $ foldl (generateFold generate16) (ek0, []) [1..10]
+
+		ekN24 =
+			let (lk, acc) = foldl (generateFold generate24) (ek0, []) [1..7] in
+			let nk = generate16 lk 8 in
+			reverse (nk : acc)
+
+		ekN32 =
+			let (lk, acc) = foldl (generateFold generate32) (ek0, []) [1..6] in
+			let nk = generate16 lk 7 in
+			reverse (nk : acc)
+
+		generateFold gen (prevk, accK) it = let nk = gen prevk it in (nk, nk : accK)
+
+		generate16 prevk it =
+			let len = V.length prevk in
+			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)
+			                (V.unsafeIndex prevk $ len - 3)
+			                (V.unsafeIndex prevk $ len - 2)
+			                (V.unsafeIndex prevk $ len - 1) in
+			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in
+			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in
+			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in
+			let     (e12,e13,e14,e15) = xorVector prevk 12 eg2 in
+			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15]
+
+		generate24 prevk it =
+			let len = V.length prevk in
+			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)
+			                (V.unsafeIndex prevk $ len - 3)
+			                (V.unsafeIndex prevk $ len - 2)
+			                (V.unsafeIndex prevk $ len - 1) in
+			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in
+			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in
+			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in
+			let eg3@(e12,e13,e14,e15) = xorVector prevk 12 eg2 in
+			let eg4@(e16,e17,e18,e19) = xorVector prevk 16 eg3 in
+			let     (e20,e21,e22,e23) = xorVector prevk 20 eg4 in
+			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15,e16,e17,e18,e19,e20,e21,e22,e23]
+
+		generate32 prevk it =
+			let len = V.length prevk in
+			let v0 = cR0 it (V.unsafeIndex prevk $ len - 4)
+			                (V.unsafeIndex prevk $ len - 3)
+			                (V.unsafeIndex prevk $ len - 2)
+			                (V.unsafeIndex prevk $ len - 1) in
+			let eg0@(e0,e1,e2,e3)     = xorVector prevk 0 v0   in
+			let eg1@(e4,e5,e6,e7)     = xorVector prevk 4 eg0  in
+			let eg2@(e8,e9,e10,e11)   = xorVector prevk 8 eg1  in
+			let eg3@(e12,e13,e14,e15) = xorVector prevk 12 eg2 in
+			let eg4@(e16,e17,e18,e19) = xorSboxVector prevk 16 eg3 in
+			let eg5@(e20,e21,e22,e23) = xorVector prevk 20 eg4 in
+			let eg6@(e24,e25,e26,e27) = xorVector prevk 24 eg5 in
+			let     (e28,e29,e30,e31) = xorVector prevk 28 eg6 in
+			V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15,e16
+			           ,e17,e18,e19,e20,e21,e22,e23,e24,e25,e26,e27,e28,e29,e30,e31]
+
+		xorVector k i (t0,t1,t2,t3) =
+			( V.unsafeIndex k (i+0) `xor` t0
+			, V.unsafeIndex k (i+1) `xor` t1
+			, V.unsafeIndex k (i+2) `xor` t2
+			, V.unsafeIndex k (i+3) `xor` t3
+			)
+
+		xorSboxVector k i (t0,t1,t2,t3) =
+			( V.unsafeIndex k (i+0) `xor` sbox t0
+			, V.unsafeIndex k (i+1) `xor` sbox t1
+			, V.unsafeIndex k (i+2) `xor` sbox t2
+			, V.unsafeIndex k (i+3) `xor` sbox t3
+			)
+
+		cR0 it r0 r1 r2 r3 =
+			(sbox r1 `xor` rcon it, sbox r2, sbox r3, sbox r0)
+
+{-# INLINE shiftRows #-}
+shiftRows :: AESState -> IO ()
+shiftRows blk = do
+	r32 blk 0 >>= w32 blk 0 . msbox32
+	r32 blk 1 >>= \t1 -> w32 blk 1 $ rotateR (msbox32 t1) 8
+	r32 blk 2 >>= \t2 -> w32 blk 2 $ rotateR (msbox32 t2) 16
+	r32 blk 3 >>= \t3 -> w32 blk 3 $ rotateR (msbox32 t3) 24
+
+{-# INLINE addRoundKey #-}
+addRoundKey :: Key -> Int -> AESState -> IO ()
+addRoundKey (Key key) i blk = forM_ [0..15] $ \n -> do
+	r8 blk n >>= \v1 -> w8 blk n $ v1 `xor` V.unsafeIndex key (16 * i + swapIndex n)
+
+{-# INLINE mixColumns #-}
+mixColumns :: AESState -> IO ()
+mixColumns state = pr 0 >> pr 1 >> pr 2 >> pr 3
+	where
+		{-# INLINE pr #-}
+		pr i = do
+			cpy0 <- r8 state (0 * 4 + i)
+			cpy1 <- r8 state (1 * 4 + i)
+			cpy2 <- r8 state (2 * 4 + i)
+			cpy3 <- r8 state (3 * 4 + i)
+
+			let state0 = gm2 cpy0 `xor` gm1 cpy3 `xor` gm1 cpy2 `xor` gm3 cpy1
+			let state4 = gm2 cpy1 `xor` gm1 cpy0 `xor` gm1 cpy3 `xor` gm3 cpy2
+			let state8 = gm2 cpy2 `xor` gm1 cpy1 `xor` gm1 cpy0 `xor` gm3 cpy3
+			let state12 = gm2 cpy3 `xor` gm1 cpy2 `xor` gm1 cpy1 `xor` gm3 cpy0
+
+			w8 state (0 * 4 + i) state0
+			w8 state (1 * 4 + i) state4
+			w8 state (2 * 4 + i) state8
+			w8 state (3 * 4 + i) state12
+		{-# INLINE gm1 #-}
+		gm1 a = a
+
+{-# INLINE shiftRowsInv #-}
+shiftRowsInv :: AESState -> IO ()
+shiftRowsInv blk = do
+	r32 blk 0 >>= w32 blk 0 . mrsbox32
+	r32 blk 1 >>= \t1 -> w32 blk 1 $ mrsbox32 $ rotateL t1 8
+	r32 blk 2 >>= \t2 -> w32 blk 2 $ mrsbox32 $ rotateL t2 16
+	r32 blk 3 >>= \t3 -> w32 blk 3 $ mrsbox32 $ rotateL t3 24
+
+{-# INLINE mixColumnsInv #-}
+mixColumnsInv :: AESState -> IO ()
+mixColumnsInv state = pr 0 >> pr 1 >> pr 2 >> pr 3
+	where
+		{-# INLINE pr #-}
+		pr i = do
+			cpy0 <- r8 state (0 * 4 + i)
+			cpy1 <- r8 state (1 * 4 + i)
+			cpy2 <- r8 state (2 * 4 + i)
+			cpy3 <- r8 state (3 * 4 + i)
+
+			let state0  = gm14 cpy0 `xor` gm9 cpy3 `xor` gm13 cpy2 `xor` gm11 cpy1
+			let state4  = gm14 cpy1 `xor` gm9 cpy0 `xor` gm13 cpy3 `xor` gm11 cpy2
+			let state8  = gm14 cpy2 `xor` gm9 cpy1 `xor` gm13 cpy0 `xor` gm11 cpy3
+			let state12 = gm14 cpy3 `xor` gm9 cpy2 `xor` gm13 cpy1 `xor` gm11 cpy0
+
+			w8 state (0 * 4 + i) state0
+			w8 state (1 * 4 + i) state4
+			w8 state (2 * 4 + i) state8
+			w8 state (3 * 4 + i) state12
+
+{-# INLINE r8 #-}
+r8 :: AESState -> Int -> IO Word8
+r8 = readByteArray
+
+{-# INLINE w8 #-}
+w8 :: AESState -> Int -> Word8 -> IO ()
+w8 = writeByteArray
+
+{-# INLINE r32 #-}
+r32 :: AESState -> Int -> IO Word32
+r32 = readByteArray
+
+{-# INLINE w32 #-}
+w32 :: AESState -> Int -> Word32 -> IO ()
+w32 = writeByteArray
+
+msbox32 :: Word32 -> Word32
+msbox32 w = sbox4 a .|. sbox3 b .|. sbox2 c .|. sbox1 d
+	where
+		a = fromIntegral (w `shiftR` 24)
+		b = fromIntegral (w `shiftR` 16)
+		c = fromIntegral (w `shiftR` 8)
+		d = fromIntegral w
+
+mrsbox32 :: Word32 -> Word32
+mrsbox32 w = fromIntegral (rsbox a) `shiftL` 24 .|.
+             fromIntegral (rsbox b) `shiftL` 16 .|.
+             fromIntegral (rsbox c) `shiftL` 8  .|.
+             fromIntegral (rsbox d)
+	where
+		a = fromIntegral (w `shiftR` 24)
+		b = fromIntegral (w `shiftR` 16)
+		c = fromIntegral (w `shiftR` 8)
+		d = fromIntegral w
+
+
+{-# INLINE swapBlock #-}
+swapBlock :: ByteString -> AESState -> IO ()
+swapBlock b blk = do -- V.generate 16 (\i -> B.unsafeIndex b $ swapIndex i)
+	forM_ [0..15] $ \i -> w8 blk i $ B.unsafeIndex b $ swapIndex i
+
+{-# INLINE swapBlockInv #-}
+swapBlockInv :: AESState -> Ptr Word8 -> IO ()
+swapBlockInv blk ptr = forM_ [0..15] $ \i -> r8 blk (swapIndex i) >>= pokeByteOff ptr i
+
+{-# INLINE sbox #-}
+sbox :: Word8 -> Word8
+sbox (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x63\x7c\x77\x7b\xf2\x6b\x6f\xc5\
+		\\x30\x01\x67\x2b\xfe\xd7\xab\x76\
+		\\xca\x82\xc9\x7d\xfa\x59\x47\xf0\
+		\\xad\xd4\xa2\xaf\x9c\xa4\x72\xc0\
+		\\xb7\xfd\x93\x26\x36\x3f\xf7\xcc\
+		\\x34\xa5\xe5\xf1\x71\xd8\x31\x15\
+		\\x04\xc7\x23\xc3\x18\x96\x05\x9a\
+		\\x07\x12\x80\xe2\xeb\x27\xb2\x75\
+		\\x09\x83\x2c\x1a\x1b\x6e\x5a\xa0\
+		\\x52\x3b\xd6\xb3\x29\xe3\x2f\x84\
+		\\x53\xd1\x00\xed\x20\xfc\xb1\x5b\
+		\\x6a\xcb\xbe\x39\x4a\x4c\x58\xcf\
+		\\xd0\xef\xaa\xfb\x43\x4d\x33\x85\
+		\\x45\xf9\x02\x7f\x50\x3c\x9f\xa8\
+		\\x51\xa3\x40\x8f\x92\x9d\x38\xf5\
+		\\xbc\xb6\xda\x21\x10\xff\xf3\xd2\
+		\\xcd\x0c\x13\xec\x5f\x97\x44\x17\
+		\\xc4\xa7\x7e\x3d\x64\x5d\x19\x73\
+		\\x60\x81\x4f\xdc\x22\x2a\x90\x88\
+		\\x46\xee\xb8\x14\xde\x5e\x0b\xdb\
+		\\xe0\x32\x3a\x0a\x49\x06\x24\x5c\
+		\\xc2\xd3\xac\x62\x91\x95\xe4\x79\
+		\\xe7\xc8\x37\x6d\x8d\xd5\x4e\xa9\
+		\\x6c\x56\xf4\xea\x65\x7a\xae\x08\
+		\\xba\x78\x25\x2e\x1c\xa6\xb4\xc6\
+		\\xe8\xdd\x74\x1f\x4b\xbd\x8b\x8a\
+		\\x70\x3e\xb5\x66\x48\x03\xf6\x0e\
+		\\x61\x35\x57\xb9\x86\xc1\x1d\x9e\
+		\\xe1\xf8\x98\x11\x69\xd9\x8e\x94\
+		\\x9b\x1e\x87\xe9\xce\x55\x28\xdf\
+		\\x8c\xa1\x89\x0d\xbf\xe6\x42\x68\
+		\\x41\x99\x2d\x0f\xb0\x54\xbb\x16"#
+
+{-# INLINE sbox1 #-}
+{-# INLINE sbox2 #-}
+{-# INLINE sbox3 #-}
+{-# INLINE sbox4 #-}
+sbox1, sbox2, sbox3, sbox4 :: Word8 -> Word32
+sbox1 (W8# w) = W32# (indexWord32OffAddr# table (word2Int# w))
+	where !(Table table) = sbox1Tab
+sbox2 (W8# w) = W32# (indexWord32OffAddr# table (word2Int# w))
+	where !(Table table) = sbox2Tab
+sbox3 (W8# w) = W32# (indexWord32OffAddr# table (word2Int# w))
+	where !(Table table) = sbox3Tab
+sbox4 (W8# w) = W32# (indexWord32OffAddr# table (word2Int# w))
+	where !(Table table) = sbox4Tab
+
+sbox1Tab, sbox2Tab, sbox3Tab, sbox4Tab :: Table
+sbox1Tab = if littleEndian then sbox_x000 else sbox_000x
+sbox2Tab = if littleEndian then sbox_0x00 else sbox_00x0
+sbox3Tab = if littleEndian then sbox_00x0 else sbox_0x00
+sbox4Tab = if littleEndian then sbox_000x else sbox_x000
+
+data Table = Table !Addr#
+
+sbox_000x, sbox_00x0, sbox_0x00, sbox_x000 :: Table
+sbox_000x = Table
+		"\x00\x00\x00\x63\x00\x00\x00\x7c\x00\x00\x00\x77\x00\x00\x00\x7b\
+		\\x00\x00\x00\xf2\x00\x00\x00\x6b\x00\x00\x00\x6f\x00\x00\x00\xc5\
+		\\x00\x00\x00\x30\x00\x00\x00\x01\x00\x00\x00\x67\x00\x00\x00\x2b\
+		\\x00\x00\x00\xfe\x00\x00\x00\xd7\x00\x00\x00\xab\x00\x00\x00\x76\
+		\\x00\x00\x00\xca\x00\x00\x00\x82\x00\x00\x00\xc9\x00\x00\x00\x7d\
+		\\x00\x00\x00\xfa\x00\x00\x00\x59\x00\x00\x00\x47\x00\x00\x00\xf0\
+		\\x00\x00\x00\xad\x00\x00\x00\xd4\x00\x00\x00\xa2\x00\x00\x00\xaf\
+		\\x00\x00\x00\x9c\x00\x00\x00\xa4\x00\x00\x00\x72\x00\x00\x00\xc0\
+		\\x00\x00\x00\xb7\x00\x00\x00\xfd\x00\x00\x00\x93\x00\x00\x00\x26\
+		\\x00\x00\x00\x36\x00\x00\x00\x3f\x00\x00\x00\xf7\x00\x00\x00\xcc\
+		\\x00\x00\x00\x34\x00\x00\x00\xa5\x00\x00\x00\xe5\x00\x00\x00\xf1\
+		\\x00\x00\x00\x71\x00\x00\x00\xd8\x00\x00\x00\x31\x00\x00\x00\x15\
+		\\x00\x00\x00\x04\x00\x00\x00\xc7\x00\x00\x00\x23\x00\x00\x00\xc3\
+		\\x00\x00\x00\x18\x00\x00\x00\x96\x00\x00\x00\x05\x00\x00\x00\x9a\
+		\\x00\x00\x00\x07\x00\x00\x00\x12\x00\x00\x00\x80\x00\x00\x00\xe2\
+		\\x00\x00\x00\xeb\x00\x00\x00\x27\x00\x00\x00\xb2\x00\x00\x00\x75\
+		\\x00\x00\x00\x09\x00\x00\x00\x83\x00\x00\x00\x2c\x00\x00\x00\x1a\
+		\\x00\x00\x00\x1b\x00\x00\x00\x6e\x00\x00\x00\x5a\x00\x00\x00\xa0\
+		\\x00\x00\x00\x52\x00\x00\x00\x3b\x00\x00\x00\xd6\x00\x00\x00\xb3\
+		\\x00\x00\x00\x29\x00\x00\x00\xe3\x00\x00\x00\x2f\x00\x00\x00\x84\
+		\\x00\x00\x00\x53\x00\x00\x00\xd1\x00\x00\x00\x00\x00\x00\x00\xed\
+		\\x00\x00\x00\x20\x00\x00\x00\xfc\x00\x00\x00\xb1\x00\x00\x00\x5b\
+		\\x00\x00\x00\x6a\x00\x00\x00\xcb\x00\x00\x00\xbe\x00\x00\x00\x39\
+		\\x00\x00\x00\x4a\x00\x00\x00\x4c\x00\x00\x00\x58\x00\x00\x00\xcf\
+		\\x00\x00\x00\xd0\x00\x00\x00\xef\x00\x00\x00\xaa\x00\x00\x00\xfb\
+		\\x00\x00\x00\x43\x00\x00\x00\x4d\x00\x00\x00\x33\x00\x00\x00\x85\
+		\\x00\x00\x00\x45\x00\x00\x00\xf9\x00\x00\x00\x02\x00\x00\x00\x7f\
+		\\x00\x00\x00\x50\x00\x00\x00\x3c\x00\x00\x00\x9f\x00\x00\x00\xa8\
+		\\x00\x00\x00\x51\x00\x00\x00\xa3\x00\x00\x00\x40\x00\x00\x00\x8f\
+		\\x00\x00\x00\x92\x00\x00\x00\x9d\x00\x00\x00\x38\x00\x00\x00\xf5\
+		\\x00\x00\x00\xbc\x00\x00\x00\xb6\x00\x00\x00\xda\x00\x00\x00\x21\
+		\\x00\x00\x00\x10\x00\x00\x00\xff\x00\x00\x00\xf3\x00\x00\x00\xd2\
+		\\x00\x00\x00\xcd\x00\x00\x00\x0c\x00\x00\x00\x13\x00\x00\x00\xec\
+		\\x00\x00\x00\x5f\x00\x00\x00\x97\x00\x00\x00\x44\x00\x00\x00\x17\
+		\\x00\x00\x00\xc4\x00\x00\x00\xa7\x00\x00\x00\x7e\x00\x00\x00\x3d\
+		\\x00\x00\x00\x64\x00\x00\x00\x5d\x00\x00\x00\x19\x00\x00\x00\x73\
+		\\x00\x00\x00\x60\x00\x00\x00\x81\x00\x00\x00\x4f\x00\x00\x00\xdc\
+		\\x00\x00\x00\x22\x00\x00\x00\x2a\x00\x00\x00\x90\x00\x00\x00\x88\
+		\\x00\x00\x00\x46\x00\x00\x00\xee\x00\x00\x00\xb8\x00\x00\x00\x14\
+		\\x00\x00\x00\xde\x00\x00\x00\x5e\x00\x00\x00\x0b\x00\x00\x00\xdb\
+		\\x00\x00\x00\xe0\x00\x00\x00\x32\x00\x00\x00\x3a\x00\x00\x00\x0a\
+		\\x00\x00\x00\x49\x00\x00\x00\x06\x00\x00\x00\x24\x00\x00\x00\x5c\
+		\\x00\x00\x00\xc2\x00\x00\x00\xd3\x00\x00\x00\xac\x00\x00\x00\x62\
+		\\x00\x00\x00\x91\x00\x00\x00\x95\x00\x00\x00\xe4\x00\x00\x00\x79\
+		\\x00\x00\x00\xe7\x00\x00\x00\xc8\x00\x00\x00\x37\x00\x00\x00\x6d\
+		\\x00\x00\x00\x8d\x00\x00\x00\xd5\x00\x00\x00\x4e\x00\x00\x00\xa9\
+		\\x00\x00\x00\x6c\x00\x00\x00\x56\x00\x00\x00\xf4\x00\x00\x00\xea\
+		\\x00\x00\x00\x65\x00\x00\x00\x7a\x00\x00\x00\xae\x00\x00\x00\x08\
+		\\x00\x00\x00\xba\x00\x00\x00\x78\x00\x00\x00\x25\x00\x00\x00\x2e\
+		\\x00\x00\x00\x1c\x00\x00\x00\xa6\x00\x00\x00\xb4\x00\x00\x00\xc6\
+		\\x00\x00\x00\xe8\x00\x00\x00\xdd\x00\x00\x00\x74\x00\x00\x00\x1f\
+		\\x00\x00\x00\x4b\x00\x00\x00\xbd\x00\x00\x00\x8b\x00\x00\x00\x8a\
+		\\x00\x00\x00\x70\x00\x00\x00\x3e\x00\x00\x00\xb5\x00\x00\x00\x66\
+		\\x00\x00\x00\x48\x00\x00\x00\x03\x00\x00\x00\xf6\x00\x00\x00\x0e\
+		\\x00\x00\x00\x61\x00\x00\x00\x35\x00\x00\x00\x57\x00\x00\x00\xb9\
+		\\x00\x00\x00\x86\x00\x00\x00\xc1\x00\x00\x00\x1d\x00\x00\x00\x9e\
+		\\x00\x00\x00\xe1\x00\x00\x00\xf8\x00\x00\x00\x98\x00\x00\x00\x11\
+		\\x00\x00\x00\x69\x00\x00\x00\xd9\x00\x00\x00\x8e\x00\x00\x00\x94\
+		\\x00\x00\x00\x9b\x00\x00\x00\x1e\x00\x00\x00\x87\x00\x00\x00\xe9\
+		\\x00\x00\x00\xce\x00\x00\x00\x55\x00\x00\x00\x28\x00\x00\x00\xdf\
+		\\x00\x00\x00\x8c\x00\x00\x00\xa1\x00\x00\x00\x89\x00\x00\x00\x0d\
+		\\x00\x00\x00\xbf\x00\x00\x00\xe6\x00\x00\x00\x42\x00\x00\x00\x68\
+		\\x00\x00\x00\x41\x00\x00\x00\x99\x00\x00\x00\x2d\x00\x00\x00\x0f\
+		\\x00\x00\x00\xb0\x00\x00\x00\x54\x00\x00\x00\xbb\x00\x00\x00\x16"#
+
+sbox_00x0 = Table
+		"\x00\x00\x63\x00\x00\x00\x7c\x00\x00\x00\x77\x00\x00\x00\x7b\x00\
+		\\x00\x00\xf2\x00\x00\x00\x6b\x00\x00\x00\x6f\x00\x00\x00\xc5\x00\
+		\\x00\x00\x30\x00\x00\x00\x01\x00\x00\x00\x67\x00\x00\x00\x2b\x00\
+		\\x00\x00\xfe\x00\x00\x00\xd7\x00\x00\x00\xab\x00\x00\x00\x76\x00\
+		\\x00\x00\xca\x00\x00\x00\x82\x00\x00\x00\xc9\x00\x00\x00\x7d\x00\
+		\\x00\x00\xfa\x00\x00\x00\x59\x00\x00\x00\x47\x00\x00\x00\xf0\x00\
+		\\x00\x00\xad\x00\x00\x00\xd4\x00\x00\x00\xa2\x00\x00\x00\xaf\x00\
+		\\x00\x00\x9c\x00\x00\x00\xa4\x00\x00\x00\x72\x00\x00\x00\xc0\x00\
+		\\x00\x00\xb7\x00\x00\x00\xfd\x00\x00\x00\x93\x00\x00\x00\x26\x00\
+		\\x00\x00\x36\x00\x00\x00\x3f\x00\x00\x00\xf7\x00\x00\x00\xcc\x00\
+		\\x00\x00\x34\x00\x00\x00\xa5\x00\x00\x00\xe5\x00\x00\x00\xf1\x00\
+		\\x00\x00\x71\x00\x00\x00\xd8\x00\x00\x00\x31\x00\x00\x00\x15\x00\
+		\\x00\x00\x04\x00\x00\x00\xc7\x00\x00\x00\x23\x00\x00\x00\xc3\x00\
+		\\x00\x00\x18\x00\x00\x00\x96\x00\x00\x00\x05\x00\x00\x00\x9a\x00\
+		\\x00\x00\x07\x00\x00\x00\x12\x00\x00\x00\x80\x00\x00\x00\xe2\x00\
+		\\x00\x00\xeb\x00\x00\x00\x27\x00\x00\x00\xb2\x00\x00\x00\x75\x00\
+		\\x00\x00\x09\x00\x00\x00\x83\x00\x00\x00\x2c\x00\x00\x00\x1a\x00\
+		\\x00\x00\x1b\x00\x00\x00\x6e\x00\x00\x00\x5a\x00\x00\x00\xa0\x00\
+		\\x00\x00\x52\x00\x00\x00\x3b\x00\x00\x00\xd6\x00\x00\x00\xb3\x00\
+		\\x00\x00\x29\x00\x00\x00\xe3\x00\x00\x00\x2f\x00\x00\x00\x84\x00\
+		\\x00\x00\x53\x00\x00\x00\xd1\x00\x00\x00\x00\x00\x00\x00\xed\x00\
+		\\x00\x00\x20\x00\x00\x00\xfc\x00\x00\x00\xb1\x00\x00\x00\x5b\x00\
+		\\x00\x00\x6a\x00\x00\x00\xcb\x00\x00\x00\xbe\x00\x00\x00\x39\x00\
+		\\x00\x00\x4a\x00\x00\x00\x4c\x00\x00\x00\x58\x00\x00\x00\xcf\x00\
+		\\x00\x00\xd0\x00\x00\x00\xef\x00\x00\x00\xaa\x00\x00\x00\xfb\x00\
+		\\x00\x00\x43\x00\x00\x00\x4d\x00\x00\x00\x33\x00\x00\x00\x85\x00\
+		\\x00\x00\x45\x00\x00\x00\xf9\x00\x00\x00\x02\x00\x00\x00\x7f\x00\
+		\\x00\x00\x50\x00\x00\x00\x3c\x00\x00\x00\x9f\x00\x00\x00\xa8\x00\
+		\\x00\x00\x51\x00\x00\x00\xa3\x00\x00\x00\x40\x00\x00\x00\x8f\x00\
+		\\x00\x00\x92\x00\x00\x00\x9d\x00\x00\x00\x38\x00\x00\x00\xf5\x00\
+		\\x00\x00\xbc\x00\x00\x00\xb6\x00\x00\x00\xda\x00\x00\x00\x21\x00\
+		\\x00\x00\x10\x00\x00\x00\xff\x00\x00\x00\xf3\x00\x00\x00\xd2\x00\
+		\\x00\x00\xcd\x00\x00\x00\x0c\x00\x00\x00\x13\x00\x00\x00\xec\x00\
+		\\x00\x00\x5f\x00\x00\x00\x97\x00\x00\x00\x44\x00\x00\x00\x17\x00\
+		\\x00\x00\xc4\x00\x00\x00\xa7\x00\x00\x00\x7e\x00\x00\x00\x3d\x00\
+		\\x00\x00\x64\x00\x00\x00\x5d\x00\x00\x00\x19\x00\x00\x00\x73\x00\
+		\\x00\x00\x60\x00\x00\x00\x81\x00\x00\x00\x4f\x00\x00\x00\xdc\x00\
+		\\x00\x00\x22\x00\x00\x00\x2a\x00\x00\x00\x90\x00\x00\x00\x88\x00\
+		\\x00\x00\x46\x00\x00\x00\xee\x00\x00\x00\xb8\x00\x00\x00\x14\x00\
+		\\x00\x00\xde\x00\x00\x00\x5e\x00\x00\x00\x0b\x00\x00\x00\xdb\x00\
+		\\x00\x00\xe0\x00\x00\x00\x32\x00\x00\x00\x3a\x00\x00\x00\x0a\x00\
+		\\x00\x00\x49\x00\x00\x00\x06\x00\x00\x00\x24\x00\x00\x00\x5c\x00\
+		\\x00\x00\xc2\x00\x00\x00\xd3\x00\x00\x00\xac\x00\x00\x00\x62\x00\
+		\\x00\x00\x91\x00\x00\x00\x95\x00\x00\x00\xe4\x00\x00\x00\x79\x00\
+		\\x00\x00\xe7\x00\x00\x00\xc8\x00\x00\x00\x37\x00\x00\x00\x6d\x00\
+		\\x00\x00\x8d\x00\x00\x00\xd5\x00\x00\x00\x4e\x00\x00\x00\xa9\x00\
+		\\x00\x00\x6c\x00\x00\x00\x56\x00\x00\x00\xf4\x00\x00\x00\xea\x00\
+		\\x00\x00\x65\x00\x00\x00\x7a\x00\x00\x00\xae\x00\x00\x00\x08\x00\
+		\\x00\x00\xba\x00\x00\x00\x78\x00\x00\x00\x25\x00\x00\x00\x2e\x00\
+		\\x00\x00\x1c\x00\x00\x00\xa6\x00\x00\x00\xb4\x00\x00\x00\xc6\x00\
+		\\x00\x00\xe8\x00\x00\x00\xdd\x00\x00\x00\x74\x00\x00\x00\x1f\x00\
+		\\x00\x00\x4b\x00\x00\x00\xbd\x00\x00\x00\x8b\x00\x00\x00\x8a\x00\
+		\\x00\x00\x70\x00\x00\x00\x3e\x00\x00\x00\xb5\x00\x00\x00\x66\x00\
+		\\x00\x00\x48\x00\x00\x00\x03\x00\x00\x00\xf6\x00\x00\x00\x0e\x00\
+		\\x00\x00\x61\x00\x00\x00\x35\x00\x00\x00\x57\x00\x00\x00\xb9\x00\
+		\\x00\x00\x86\x00\x00\x00\xc1\x00\x00\x00\x1d\x00\x00\x00\x9e\x00\
+		\\x00\x00\xe1\x00\x00\x00\xf8\x00\x00\x00\x98\x00\x00\x00\x11\x00\
+		\\x00\x00\x69\x00\x00\x00\xd9\x00\x00\x00\x8e\x00\x00\x00\x94\x00\
+		\\x00\x00\x9b\x00\x00\x00\x1e\x00\x00\x00\x87\x00\x00\x00\xe9\x00\
+		\\x00\x00\xce\x00\x00\x00\x55\x00\x00\x00\x28\x00\x00\x00\xdf\x00\
+		\\x00\x00\x8c\x00\x00\x00\xa1\x00\x00\x00\x89\x00\x00\x00\x0d\x00\
+		\\x00\x00\xbf\x00\x00\x00\xe6\x00\x00\x00\x42\x00\x00\x00\x68\x00\
+		\\x00\x00\x41\x00\x00\x00\x99\x00\x00\x00\x2d\x00\x00\x00\x0f\x00\
+		\\x00\x00\xb0\x00\x00\x00\x54\x00\x00\x00\xbb\x00\x00\x00\x16\x00"#
+
+sbox_0x00 = Table
+		"\x00\x63\x00\x00\x00\x7c\x00\x00\x00\x77\x00\x00\x00\x7b\x00\x00\
+		\\x00\xf2\x00\x00\x00\x6b\x00\x00\x00\x6f\x00\x00\x00\xc5\x00\x00\
+		\\x00\x30\x00\x00\x00\x01\x00\x00\x00\x67\x00\x00\x00\x2b\x00\x00\
+		\\x00\xfe\x00\x00\x00\xd7\x00\x00\x00\xab\x00\x00\x00\x76\x00\x00\
+		\\x00\xca\x00\x00\x00\x82\x00\x00\x00\xc9\x00\x00\x00\x7d\x00\x00\
+		\\x00\xfa\x00\x00\x00\x59\x00\x00\x00\x47\x00\x00\x00\xf0\x00\x00\
+		\\x00\xad\x00\x00\x00\xd4\x00\x00\x00\xa2\x00\x00\x00\xaf\x00\x00\
+		\\x00\x9c\x00\x00\x00\xa4\x00\x00\x00\x72\x00\x00\x00\xc0\x00\x00\
+		\\x00\xb7\x00\x00\x00\xfd\x00\x00\x00\x93\x00\x00\x00\x26\x00\x00\
+		\\x00\x36\x00\x00\x00\x3f\x00\x00\x00\xf7\x00\x00\x00\xcc\x00\x00\
+		\\x00\x34\x00\x00\x00\xa5\x00\x00\x00\xe5\x00\x00\x00\xf1\x00\x00\
+		\\x00\x71\x00\x00\x00\xd8\x00\x00\x00\x31\x00\x00\x00\x15\x00\x00\
+		\\x00\x04\x00\x00\x00\xc7\x00\x00\x00\x23\x00\x00\x00\xc3\x00\x00\
+		\\x00\x18\x00\x00\x00\x96\x00\x00\x00\x05\x00\x00\x00\x9a\x00\x00\
+		\\x00\x07\x00\x00\x00\x12\x00\x00\x00\x80\x00\x00\x00\xe2\x00\x00\
+		\\x00\xeb\x00\x00\x00\x27\x00\x00\x00\xb2\x00\x00\x00\x75\x00\x00\
+		\\x00\x09\x00\x00\x00\x83\x00\x00\x00\x2c\x00\x00\x00\x1a\x00\x00\
+		\\x00\x1b\x00\x00\x00\x6e\x00\x00\x00\x5a\x00\x00\x00\xa0\x00\x00\
+		\\x00\x52\x00\x00\x00\x3b\x00\x00\x00\xd6\x00\x00\x00\xb3\x00\x00\
+		\\x00\x29\x00\x00\x00\xe3\x00\x00\x00\x2f\x00\x00\x00\x84\x00\x00\
+		\\x00\x53\x00\x00\x00\xd1\x00\x00\x00\x00\x00\x00\x00\xed\x00\x00\
+		\\x00\x20\x00\x00\x00\xfc\x00\x00\x00\xb1\x00\x00\x00\x5b\x00\x00\
+		\\x00\x6a\x00\x00\x00\xcb\x00\x00\x00\xbe\x00\x00\x00\x39\x00\x00\
+		\\x00\x4a\x00\x00\x00\x4c\x00\x00\x00\x58\x00\x00\x00\xcf\x00\x00\
+		\\x00\xd0\x00\x00\x00\xef\x00\x00\x00\xaa\x00\x00\x00\xfb\x00\x00\
+		\\x00\x43\x00\x00\x00\x4d\x00\x00\x00\x33\x00\x00\x00\x85\x00\x00\
+		\\x00\x45\x00\x00\x00\xf9\x00\x00\x00\x02\x00\x00\x00\x7f\x00\x00\
+		\\x00\x50\x00\x00\x00\x3c\x00\x00\x00\x9f\x00\x00\x00\xa8\x00\x00\
+		\\x00\x51\x00\x00\x00\xa3\x00\x00\x00\x40\x00\x00\x00\x8f\x00\x00\
+		\\x00\x92\x00\x00\x00\x9d\x00\x00\x00\x38\x00\x00\x00\xf5\x00\x00\
+		\\x00\xbc\x00\x00\x00\xb6\x00\x00\x00\xda\x00\x00\x00\x21\x00\x00\
+		\\x00\x10\x00\x00\x00\xff\x00\x00\x00\xf3\x00\x00\x00\xd2\x00\x00\
+		\\x00\xcd\x00\x00\x00\x0c\x00\x00\x00\x13\x00\x00\x00\xec\x00\x00\
+		\\x00\x5f\x00\x00\x00\x97\x00\x00\x00\x44\x00\x00\x00\x17\x00\x00\
+		\\x00\xc4\x00\x00\x00\xa7\x00\x00\x00\x7e\x00\x00\x00\x3d\x00\x00\
+		\\x00\x64\x00\x00\x00\x5d\x00\x00\x00\x19\x00\x00\x00\x73\x00\x00\
+		\\x00\x60\x00\x00\x00\x81\x00\x00\x00\x4f\x00\x00\x00\xdc\x00\x00\
+		\\x00\x22\x00\x00\x00\x2a\x00\x00\x00\x90\x00\x00\x00\x88\x00\x00\
+		\\x00\x46\x00\x00\x00\xee\x00\x00\x00\xb8\x00\x00\x00\x14\x00\x00\
+		\\x00\xde\x00\x00\x00\x5e\x00\x00\x00\x0b\x00\x00\x00\xdb\x00\x00\
+		\\x00\xe0\x00\x00\x00\x32\x00\x00\x00\x3a\x00\x00\x00\x0a\x00\x00\
+		\\x00\x49\x00\x00\x00\x06\x00\x00\x00\x24\x00\x00\x00\x5c\x00\x00\
+		\\x00\xc2\x00\x00\x00\xd3\x00\x00\x00\xac\x00\x00\x00\x62\x00\x00\
+		\\x00\x91\x00\x00\x00\x95\x00\x00\x00\xe4\x00\x00\x00\x79\x00\x00\
+		\\x00\xe7\x00\x00\x00\xc8\x00\x00\x00\x37\x00\x00\x00\x6d\x00\x00\
+		\\x00\x8d\x00\x00\x00\xd5\x00\x00\x00\x4e\x00\x00\x00\xa9\x00\x00\
+		\\x00\x6c\x00\x00\x00\x56\x00\x00\x00\xf4\x00\x00\x00\xea\x00\x00\
+		\\x00\x65\x00\x00\x00\x7a\x00\x00\x00\xae\x00\x00\x00\x08\x00\x00\
+		\\x00\xba\x00\x00\x00\x78\x00\x00\x00\x25\x00\x00\x00\x2e\x00\x00\
+		\\x00\x1c\x00\x00\x00\xa6\x00\x00\x00\xb4\x00\x00\x00\xc6\x00\x00\
+		\\x00\xe8\x00\x00\x00\xdd\x00\x00\x00\x74\x00\x00\x00\x1f\x00\x00\
+		\\x00\x4b\x00\x00\x00\xbd\x00\x00\x00\x8b\x00\x00\x00\x8a\x00\x00\
+		\\x00\x70\x00\x00\x00\x3e\x00\x00\x00\xb5\x00\x00\x00\x66\x00\x00\
+		\\x00\x48\x00\x00\x00\x03\x00\x00\x00\xf6\x00\x00\x00\x0e\x00\x00\
+		\\x00\x61\x00\x00\x00\x35\x00\x00\x00\x57\x00\x00\x00\xb9\x00\x00\
+		\\x00\x86\x00\x00\x00\xc1\x00\x00\x00\x1d\x00\x00\x00\x9e\x00\x00\
+		\\x00\xe1\x00\x00\x00\xf8\x00\x00\x00\x98\x00\x00\x00\x11\x00\x00\
+		\\x00\x69\x00\x00\x00\xd9\x00\x00\x00\x8e\x00\x00\x00\x94\x00\x00\
+		\\x00\x9b\x00\x00\x00\x1e\x00\x00\x00\x87\x00\x00\x00\xe9\x00\x00\
+		\\x00\xce\x00\x00\x00\x55\x00\x00\x00\x28\x00\x00\x00\xdf\x00\x00\
+		\\x00\x8c\x00\x00\x00\xa1\x00\x00\x00\x89\x00\x00\x00\x0d\x00\x00\
+		\\x00\xbf\x00\x00\x00\xe6\x00\x00\x00\x42\x00\x00\x00\x68\x00\x00\
+		\\x00\x41\x00\x00\x00\x99\x00\x00\x00\x2d\x00\x00\x00\x0f\x00\x00\
+		\\x00\xb0\x00\x00\x00\x54\x00\x00\x00\xbb\x00\x00\x00\x16\x00\x00"#
+
+sbox_x000 = Table
+		"\x63\x00\x00\x00\x7c\x00\x00\x00\x77\x00\x00\x00\x7b\x00\x00\x00\
+		\\xf2\x00\x00\x00\x6b\x00\x00\x00\x6f\x00\x00\x00\xc5\x00\x00\x00\
+		\\x30\x00\x00\x00\x01\x00\x00\x00\x67\x00\x00\x00\x2b\x00\x00\x00\
+		\\xfe\x00\x00\x00\xd7\x00\x00\x00\xab\x00\x00\x00\x76\x00\x00\x00\
+		\\xca\x00\x00\x00\x82\x00\x00\x00\xc9\x00\x00\x00\x7d\x00\x00\x00\
+		\\xfa\x00\x00\x00\x59\x00\x00\x00\x47\x00\x00\x00\xf0\x00\x00\x00\
+		\\xad\x00\x00\x00\xd4\x00\x00\x00\xa2\x00\x00\x00\xaf\x00\x00\x00\
+		\\x9c\x00\x00\x00\xa4\x00\x00\x00\x72\x00\x00\x00\xc0\x00\x00\x00\
+		\\xb7\x00\x00\x00\xfd\x00\x00\x00\x93\x00\x00\x00\x26\x00\x00\x00\
+		\\x36\x00\x00\x00\x3f\x00\x00\x00\xf7\x00\x00\x00\xcc\x00\x00\x00\
+		\\x34\x00\x00\x00\xa5\x00\x00\x00\xe5\x00\x00\x00\xf1\x00\x00\x00\
+		\\x71\x00\x00\x00\xd8\x00\x00\x00\x31\x00\x00\x00\x15\x00\x00\x00\
+		\\x04\x00\x00\x00\xc7\x00\x00\x00\x23\x00\x00\x00\xc3\x00\x00\x00\
+		\\x18\x00\x00\x00\x96\x00\x00\x00\x05\x00\x00\x00\x9a\x00\x00\x00\
+		\\x07\x00\x00\x00\x12\x00\x00\x00\x80\x00\x00\x00\xe2\x00\x00\x00\
+		\\xeb\x00\x00\x00\x27\x00\x00\x00\xb2\x00\x00\x00\x75\x00\x00\x00\
+		\\x09\x00\x00\x00\x83\x00\x00\x00\x2c\x00\x00\x00\x1a\x00\x00\x00\
+		\\x1b\x00\x00\x00\x6e\x00\x00\x00\x5a\x00\x00\x00\xa0\x00\x00\x00\
+		\\x52\x00\x00\x00\x3b\x00\x00\x00\xd6\x00\x00\x00\xb3\x00\x00\x00\
+		\\x29\x00\x00\x00\xe3\x00\x00\x00\x2f\x00\x00\x00\x84\x00\x00\x00\
+		\\x53\x00\x00\x00\xd1\x00\x00\x00\x00\x00\x00\x00\xed\x00\x00\x00\
+		\\x20\x00\x00\x00\xfc\x00\x00\x00\xb1\x00\x00\x00\x5b\x00\x00\x00\
+		\\x6a\x00\x00\x00\xcb\x00\x00\x00\xbe\x00\x00\x00\x39\x00\x00\x00\
+		\\x4a\x00\x00\x00\x4c\x00\x00\x00\x58\x00\x00\x00\xcf\x00\x00\x00\
+		\\xd0\x00\x00\x00\xef\x00\x00\x00\xaa\x00\x00\x00\xfb\x00\x00\x00\
+		\\x43\x00\x00\x00\x4d\x00\x00\x00\x33\x00\x00\x00\x85\x00\x00\x00\
+		\\x45\x00\x00\x00\xf9\x00\x00\x00\x02\x00\x00\x00\x7f\x00\x00\x00\
+		\\x50\x00\x00\x00\x3c\x00\x00\x00\x9f\x00\x00\x00\xa8\x00\x00\x00\
+		\\x51\x00\x00\x00\xa3\x00\x00\x00\x40\x00\x00\x00\x8f\x00\x00\x00\
+		\\x92\x00\x00\x00\x9d\x00\x00\x00\x38\x00\x00\x00\xf5\x00\x00\x00\
+		\\xbc\x00\x00\x00\xb6\x00\x00\x00\xda\x00\x00\x00\x21\x00\x00\x00\
+		\\x10\x00\x00\x00\xff\x00\x00\x00\xf3\x00\x00\x00\xd2\x00\x00\x00\
+		\\xcd\x00\x00\x00\x0c\x00\x00\x00\x13\x00\x00\x00\xec\x00\x00\x00\
+		\\x5f\x00\x00\x00\x97\x00\x00\x00\x44\x00\x00\x00\x17\x00\x00\x00\
+		\\xc4\x00\x00\x00\xa7\x00\x00\x00\x7e\x00\x00\x00\x3d\x00\x00\x00\
+		\\x64\x00\x00\x00\x5d\x00\x00\x00\x19\x00\x00\x00\x73\x00\x00\x00\
+		\\x60\x00\x00\x00\x81\x00\x00\x00\x4f\x00\x00\x00\xdc\x00\x00\x00\
+		\\x22\x00\x00\x00\x2a\x00\x00\x00\x90\x00\x00\x00\x88\x00\x00\x00\
+		\\x46\x00\x00\x00\xee\x00\x00\x00\xb8\x00\x00\x00\x14\x00\x00\x00\
+		\\xde\x00\x00\x00\x5e\x00\x00\x00\x0b\x00\x00\x00\xdb\x00\x00\x00\
+		\\xe0\x00\x00\x00\x32\x00\x00\x00\x3a\x00\x00\x00\x0a\x00\x00\x00\
+		\\x49\x00\x00\x00\x06\x00\x00\x00\x24\x00\x00\x00\x5c\x00\x00\x00\
+		\\xc2\x00\x00\x00\xd3\x00\x00\x00\xac\x00\x00\x00\x62\x00\x00\x00\
+		\\x91\x00\x00\x00\x95\x00\x00\x00\xe4\x00\x00\x00\x79\x00\x00\x00\
+		\\xe7\x00\x00\x00\xc8\x00\x00\x00\x37\x00\x00\x00\x6d\x00\x00\x00\
+		\\x8d\x00\x00\x00\xd5\x00\x00\x00\x4e\x00\x00\x00\xa9\x00\x00\x00\
+		\\x6c\x00\x00\x00\x56\x00\x00\x00\xf4\x00\x00\x00\xea\x00\x00\x00\
+		\\x65\x00\x00\x00\x7a\x00\x00\x00\xae\x00\x00\x00\x08\x00\x00\x00\
+		\\xba\x00\x00\x00\x78\x00\x00\x00\x25\x00\x00\x00\x2e\x00\x00\x00\
+		\\x1c\x00\x00\x00\xa6\x00\x00\x00\xb4\x00\x00\x00\xc6\x00\x00\x00\
+		\\xe8\x00\x00\x00\xdd\x00\x00\x00\x74\x00\x00\x00\x1f\x00\x00\x00\
+		\\x4b\x00\x00\x00\xbd\x00\x00\x00\x8b\x00\x00\x00\x8a\x00\x00\x00\
+		\\x70\x00\x00\x00\x3e\x00\x00\x00\xb5\x00\x00\x00\x66\x00\x00\x00\
+		\\x48\x00\x00\x00\x03\x00\x00\x00\xf6\x00\x00\x00\x0e\x00\x00\x00\
+		\\x61\x00\x00\x00\x35\x00\x00\x00\x57\x00\x00\x00\xb9\x00\x00\x00\
+		\\x86\x00\x00\x00\xc1\x00\x00\x00\x1d\x00\x00\x00\x9e\x00\x00\x00\
+		\\xe1\x00\x00\x00\xf8\x00\x00\x00\x98\x00\x00\x00\x11\x00\x00\x00\
+		\\x69\x00\x00\x00\xd9\x00\x00\x00\x8e\x00\x00\x00\x94\x00\x00\x00\
+		\\x9b\x00\x00\x00\x1e\x00\x00\x00\x87\x00\x00\x00\xe9\x00\x00\x00\
+		\\xce\x00\x00\x00\x55\x00\x00\x00\x28\x00\x00\x00\xdf\x00\x00\x00\
+		\\x8c\x00\x00\x00\xa1\x00\x00\x00\x89\x00\x00\x00\x0d\x00\x00\x00\
+		\\xbf\x00\x00\x00\xe6\x00\x00\x00\x42\x00\x00\x00\x68\x00\x00\x00\
+		\\x41\x00\x00\x00\x99\x00\x00\x00\x2d\x00\x00\x00\x0f\x00\x00\x00\
+		\\xb0\x00\x00\x00\x54\x00\x00\x00\xbb\x00\x00\x00\x16\x00\x00\x00"#
+
+
+{-# INLINE rsbox #-}
+rsbox :: Word8 -> Word8
+rsbox (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x52\x09\x6a\xd5\x30\x36\xa5\x38\
+		\\xbf\x40\xa3\x9e\x81\xf3\xd7\xfb\
+		\\x7c\xe3\x39\x82\x9b\x2f\xff\x87\
+		\\x34\x8e\x43\x44\xc4\xde\xe9\xcb\
+		\\x54\x7b\x94\x32\xa6\xc2\x23\x3d\
+		\\xee\x4c\x95\x0b\x42\xfa\xc3\x4e\
+		\\x08\x2e\xa1\x66\x28\xd9\x24\xb2\
+		\\x76\x5b\xa2\x49\x6d\x8b\xd1\x25\
+		\\x72\xf8\xf6\x64\x86\x68\x98\x16\
+		\\xd4\xa4\x5c\xcc\x5d\x65\xb6\x92\
+		\\x6c\x70\x48\x50\xfd\xed\xb9\xda\
+		\\x5e\x15\x46\x57\xa7\x8d\x9d\x84\
+		\\x90\xd8\xab\x00\x8c\xbc\xd3\x0a\
+		\\xf7\xe4\x58\x05\xb8\xb3\x45\x06\
+		\\xd0\x2c\x1e\x8f\xca\x3f\x0f\x02\
+		\\xc1\xaf\xbd\x03\x01\x13\x8a\x6b\
+		\\x3a\x91\x11\x41\x4f\x67\xdc\xea\
+		\\x97\xf2\xcf\xce\xf0\xb4\xe6\x73\
+		\\x96\xac\x74\x22\xe7\xad\x35\x85\
+		\\xe2\xf9\x37\xe8\x1c\x75\xdf\x6e\
+		\\x47\xf1\x1a\x71\x1d\x29\xc5\x89\
+		\\x6f\xb7\x62\x0e\xaa\x18\xbe\x1b\
+		\\xfc\x56\x3e\x4b\xc6\xd2\x79\x20\
+		\\x9a\xdb\xc0\xfe\x78\xcd\x5a\xf4\
+		\\x1f\xdd\xa8\x33\x88\x07\xc7\x31\
+		\\xb1\x12\x10\x59\x27\x80\xec\x5f\
+		\\x60\x51\x7f\xa9\x19\xb5\x4a\x0d\
+		\\x2d\xe5\x7a\x9f\x93\xc9\x9c\xef\
+		\\xa0\xe0\x3b\x4d\xae\x2a\xf5\xb0\
+		\\xc8\xeb\xbb\x3c\x83\x53\x99\x61\
+		\\x17\x2b\x04\x7e\xba\x77\xd6\x26\
+		\\xe1\x69\x14\x63\x55\x21\x0c\x7d"#
+
+{-# INLINE rcon #-}
+rcon :: Int -> Word8
+rcon (I# i) = W8# (indexWord8OffAddr# table (i `remInt#` 51#))
+	where !table =
+		"\x8d\x01\x02\x04\x08\x10\x20\x40\
+		\\x80\x1b\x36\x6c\xd8\xab\x4d\x9a\
+		\\x2f\x5e\xbc\x63\xc6\x97\x35\x6a\
+		\\xd4\xb3\x7d\xfa\xef\xc5\x91\x39\
+		\\x72\xe4\xd3\xbd\x61\xc2\x9f\x25\
+		\\x4a\x94\x33\x66\xcc\x83\x1d\x3a\
+		\\x74\xe8\xcb"#
+
+{-# INLINE gm2 #-}
+{-# INLINE gm3 #-}
+{-# INLINE gm9 #-}
+{-# INLINE gm11 #-}
+{-# INLINE gm13 #-}
+{-# INLINE gm14 #-}
+gm2, gm3, gm9, gm11, gm13, gm14 :: Word8 -> Word8
+gm2 (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x00\x02\x04\x06\x08\x0a\x0c\x0e\
+		\\x10\x12\x14\x16\x18\x1a\x1c\x1e\
+		\\x20\x22\x24\x26\x28\x2a\x2c\x2e\
+		\\x30\x32\x34\x36\x38\x3a\x3c\x3e\
+		\\x40\x42\x44\x46\x48\x4a\x4c\x4e\
+		\\x50\x52\x54\x56\x58\x5a\x5c\x5e\
+		\\x60\x62\x64\x66\x68\x6a\x6c\x6e\
+		\\x70\x72\x74\x76\x78\x7a\x7c\x7e\
+		\\x80\x82\x84\x86\x88\x8a\x8c\x8e\
+		\\x90\x92\x94\x96\x98\x9a\x9c\x9e\
+		\\xa0\xa2\xa4\xa6\xa8\xaa\xac\xae\
+		\\xb0\xb2\xb4\xb6\xb8\xba\xbc\xbe\
+		\\xc0\xc2\xc4\xc6\xc8\xca\xcc\xce\
+		\\xd0\xd2\xd4\xd6\xd8\xda\xdc\xde\
+		\\xe0\xe2\xe4\xe6\xe8\xea\xec\xee\
+		\\xf0\xf2\xf4\xf6\xf8\xfa\xfc\xfe\
+		\\x1b\x19\x1f\x1d\x13\x11\x17\x15\
+		\\x0b\x09\x0f\x0d\x03\x01\x07\x05\
+		\\x3b\x39\x3f\x3d\x33\x31\x37\x35\
+		\\x2b\x29\x2f\x2d\x23\x21\x27\x25\
+		\\x5b\x59\x5f\x5d\x53\x51\x57\x55\
+		\\x4b\x49\x4f\x4d\x43\x41\x47\x45\
+		\\x7b\x79\x7f\x7d\x73\x71\x77\x75\
+		\\x6b\x69\x6f\x6d\x63\x61\x67\x65\
+		\\x9b\x99\x9f\x9d\x93\x91\x97\x95\
+		\\x8b\x89\x8f\x8d\x83\x81\x87\x85\
+		\\xbb\xb9\xbf\xbd\xb3\xb1\xb7\xb5\
+		\\xab\xa9\xaf\xad\xa3\xa1\xa7\xa5\
+		\\xdb\xd9\xdf\xdd\xd3\xd1\xd7\xd5\
+		\\xcb\xc9\xcf\xcd\xc3\xc1\xc7\xc5\
+		\\xfb\xf9\xff\xfd\xf3\xf1\xf7\xf5\
+		\\xeb\xe9\xef\xed\xe3\xe1\xe7\xe5"#
+
+gm3 (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x00\x03\x06\x05\x0c\x0f\x0a\x09\
+		\\x18\x1b\x1e\x1d\x14\x17\x12\x11\
+		\\x30\x33\x36\x35\x3c\x3f\x3a\x39\
+		\\x28\x2b\x2e\x2d\x24\x27\x22\x21\
+		\\x60\x63\x66\x65\x6c\x6f\x6a\x69\
+		\\x78\x7b\x7e\x7d\x74\x77\x72\x71\
+		\\x50\x53\x56\x55\x5c\x5f\x5a\x59\
+		\\x48\x4b\x4e\x4d\x44\x47\x42\x41\
+		\\xc0\xc3\xc6\xc5\xcc\xcf\xca\xc9\
+		\\xd8\xdb\xde\xdd\xd4\xd7\xd2\xd1\
+		\\xf0\xf3\xf6\xf5\xfc\xff\xfa\xf9\
+		\\xe8\xeb\xee\xed\xe4\xe7\xe2\xe1\
+		\\xa0\xa3\xa6\xa5\xac\xaf\xaa\xa9\
+		\\xb8\xbb\xbe\xbd\xb4\xb7\xb2\xb1\
+		\\x90\x93\x96\x95\x9c\x9f\x9a\x99\
+		\\x88\x8b\x8e\x8d\x84\x87\x82\x81\
+		\\x9b\x98\x9d\x9e\x97\x94\x91\x92\
+		\\x83\x80\x85\x86\x8f\x8c\x89\x8a\
+		\\xab\xa8\xad\xae\xa7\xa4\xa1\xa2\
+		\\xb3\xb0\xb5\xb6\xbf\xbc\xb9\xba\
+		\\xfb\xf8\xfd\xfe\xf7\xf4\xf1\xf2\
+		\\xe3\xe0\xe5\xe6\xef\xec\xe9\xea\
+		\\xcb\xc8\xcd\xce\xc7\xc4\xc1\xc2\
+		\\xd3\xd0\xd5\xd6\xdf\xdc\xd9\xda\
+		\\x5b\x58\x5d\x5e\x57\x54\x51\x52\
+		\\x43\x40\x45\x46\x4f\x4c\x49\x4a\
+		\\x6b\x68\x6d\x6e\x67\x64\x61\x62\
+		\\x73\x70\x75\x76\x7f\x7c\x79\x7a\
+		\\x3b\x38\x3d\x3e\x37\x34\x31\x32\
+		\\x23\x20\x25\x26\x2f\x2c\x29\x2a\
+		\\x0b\x08\x0d\x0e\x07\x04\x01\x02\
+		\\x13\x10\x15\x16\x1f\x1c\x19\x1a"#
+
+gm9 (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x00\x09\x12\x1b\x24\x2d\x36\x3f\
+		\\x48\x41\x5a\x53\x6c\x65\x7e\x77\
+		\\x90\x99\x82\x8b\xb4\xbd\xa6\xaf\
+		\\xd8\xd1\xca\xc3\xfc\xf5\xee\xe7\
+		\\x3b\x32\x29\x20\x1f\x16\x0d\x04\
+		\\x73\x7a\x61\x68\x57\x5e\x45\x4c\
+		\\xab\xa2\xb9\xb0\x8f\x86\x9d\x94\
+		\\xe3\xea\xf1\xf8\xc7\xce\xd5\xdc\
+		\\x76\x7f\x64\x6d\x52\x5b\x40\x49\
+		\\x3e\x37\x2c\x25\x1a\x13\x08\x01\
+		\\xe6\xef\xf4\xfd\xc2\xcb\xd0\xd9\
+		\\xae\xa7\xbc\xb5\x8a\x83\x98\x91\
+		\\x4d\x44\x5f\x56\x69\x60\x7b\x72\
+		\\x05\x0c\x17\x1e\x21\x28\x33\x3a\
+		\\xdd\xd4\xcf\xc6\xf9\xf0\xeb\xe2\
+		\\x95\x9c\x87\x8e\xb1\xb8\xa3\xaa\
+		\\xec\xe5\xfe\xf7\xc8\xc1\xda\xd3\
+		\\xa4\xad\xb6\xbf\x80\x89\x92\x9b\
+		\\x7c\x75\x6e\x67\x58\x51\x4a\x43\
+		\\x34\x3d\x26\x2f\x10\x19\x02\x0b\
+		\\xd7\xde\xc5\xcc\xf3\xfa\xe1\xe8\
+		\\x9f\x96\x8d\x84\xbb\xb2\xa9\xa0\
+		\\x47\x4e\x55\x5c\x63\x6a\x71\x78\
+		\\x0f\x06\x1d\x14\x2b\x22\x39\x30\
+		\\x9a\x93\x88\x81\xbe\xb7\xac\xa5\
+		\\xd2\xdb\xc0\xc9\xf6\xff\xe4\xed\
+		\\x0a\x03\x18\x11\x2e\x27\x3c\x35\
+		\\x42\x4b\x50\x59\x66\x6f\x74\x7d\
+		\\xa1\xa8\xb3\xba\x85\x8c\x97\x9e\
+		\\xe9\xe0\xfb\xf2\xcd\xc4\xdf\xd6\
+		\\x31\x38\x23\x2a\x15\x1c\x07\x0e\
+		\\x79\x70\x6b\x62\x5d\x54\x4f\x46"#
+
+gm11 (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x00\x0b\x16\x1d\x2c\x27\x3a\x31\
+		\\x58\x53\x4e\x45\x74\x7f\x62\x69\
+		\\xb0\xbb\xa6\xad\x9c\x97\x8a\x81\
+		\\xe8\xe3\xfe\xf5\xc4\xcf\xd2\xd9\
+		\\x7b\x70\x6d\x66\x57\x5c\x41\x4a\
+		\\x23\x28\x35\x3e\x0f\x04\x19\x12\
+		\\xcb\xc0\xdd\xd6\xe7\xec\xf1\xfa\
+		\\x93\x98\x85\x8e\xbf\xb4\xa9\xa2\
+		\\xf6\xfd\xe0\xeb\xda\xd1\xcc\xc7\
+		\\xae\xa5\xb8\xb3\x82\x89\x94\x9f\
+		\\x46\x4d\x50\x5b\x6a\x61\x7c\x77\
+		\\x1e\x15\x08\x03\x32\x39\x24\x2f\
+		\\x8d\x86\x9b\x90\xa1\xaa\xb7\xbc\
+		\\xd5\xde\xc3\xc8\xf9\xf2\xef\xe4\
+		\\x3d\x36\x2b\x20\x11\x1a\x07\x0c\
+		\\x65\x6e\x73\x78\x49\x42\x5f\x54\
+		\\xf7\xfc\xe1\xea\xdb\xd0\xcd\xc6\
+		\\xaf\xa4\xb9\xb2\x83\x88\x95\x9e\
+		\\x47\x4c\x51\x5a\x6b\x60\x7d\x76\
+		\\x1f\x14\x09\x02\x33\x38\x25\x2e\
+		\\x8c\x87\x9a\x91\xa0\xab\xb6\xbd\
+		\\xd4\xdf\xc2\xc9\xf8\xf3\xee\xe5\
+		\\x3c\x37\x2a\x21\x10\x1b\x06\x0d\
+		\\x64\x6f\x72\x79\x48\x43\x5e\x55\
+		\\x01\x0a\x17\x1c\x2d\x26\x3b\x30\
+		\\x59\x52\x4f\x44\x75\x7e\x63\x68\
+		\\xb1\xba\xa7\xac\x9d\x96\x8b\x80\
+		\\xe9\xe2\xff\xf4\xc5\xce\xd3\xd8\
+		\\x7a\x71\x6c\x67\x56\x5d\x40\x4b\
+		\\x22\x29\x34\x3f\x0e\x05\x18\x13\
+		\\xca\xc1\xdc\xd7\xe6\xed\xf0\xfb\
+		\\x92\x99\x84\x8f\xbe\xb5\xa8\xa3"#
+
+gm13 (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x00\x0d\x1a\x17\x34\x39\x2e\x23\
+		\\x68\x65\x72\x7f\x5c\x51\x46\x4b\
+		\\xd0\xdd\xca\xc7\xe4\xe9\xfe\xf3\
+		\\xb8\xb5\xa2\xaf\x8c\x81\x96\x9b\
+		\\xbb\xb6\xa1\xac\x8f\x82\x95\x98\
+		\\xd3\xde\xc9\xc4\xe7\xea\xfd\xf0\
+		\\x6b\x66\x71\x7c\x5f\x52\x45\x48\
+		\\x03\x0e\x19\x14\x37\x3a\x2d\x20\
+		\\x6d\x60\x77\x7a\x59\x54\x43\x4e\
+		\\x05\x08\x1f\x12\x31\x3c\x2b\x26\
+		\\xbd\xb0\xa7\xaa\x89\x84\x93\x9e\
+		\\xd5\xd8\xcf\xc2\xe1\xec\xfb\xf6\
+		\\xd6\xdb\xcc\xc1\xe2\xef\xf8\xf5\
+		\\xbe\xb3\xa4\xa9\x8a\x87\x90\x9d\
+		\\x06\x0b\x1c\x11\x32\x3f\x28\x25\
+		\\x6e\x63\x74\x79\x5a\x57\x40\x4d\
+		\\xda\xd7\xc0\xcd\xee\xe3\xf4\xf9\
+		\\xb2\xbf\xa8\xa5\x86\x8b\x9c\x91\
+		\\x0a\x07\x10\x1d\x3e\x33\x24\x29\
+		\\x62\x6f\x78\x75\x56\x5b\x4c\x41\
+		\\x61\x6c\x7b\x76\x55\x58\x4f\x42\
+		\\x09\x04\x13\x1e\x3d\x30\x27\x2a\
+		\\xb1\xbc\xab\xa6\x85\x88\x9f\x92\
+		\\xd9\xd4\xc3\xce\xed\xe0\xf7\xfa\
+		\\xb7\xba\xad\xa0\x83\x8e\x99\x94\
+		\\xdf\xd2\xc5\xc8\xeb\xe6\xf1\xfc\
+		\\x67\x6a\x7d\x70\x53\x5e\x49\x44\
+		\\x0f\x02\x15\x18\x3b\x36\x21\x2c\
+		\\x0c\x01\x16\x1b\x38\x35\x22\x2f\
+		\\x64\x69\x7e\x73\x50\x5d\x4a\x47\
+		\\xdc\xd1\xc6\xcb\xe8\xe5\xf2\xff\
+		\\xb4\xb9\xae\xa3\x80\x8d\x9a\x97"#
+
+gm14 (W8# w) = W8# (indexWord8OffAddr# table (word2Int# w))
+	where !table =
+		"\x00\x0e\x1c\x12\x38\x36\x24\x2a\
+		\\x70\x7e\x6c\x62\x48\x46\x54\x5a\
+		\\xe0\xee\xfc\xf2\xd8\xd6\xc4\xca\
+		\\x90\x9e\x8c\x82\xa8\xa6\xb4\xba\
+		\\xdb\xd5\xc7\xc9\xe3\xed\xff\xf1\
+		\\xab\xa5\xb7\xb9\x93\x9d\x8f\x81\
+		\\x3b\x35\x27\x29\x03\x0d\x1f\x11\
+		\\x4b\x45\x57\x59\x73\x7d\x6f\x61\
+		\\xad\xa3\xb1\xbf\x95\x9b\x89\x87\
+		\\xdd\xd3\xc1\xcf\xe5\xeb\xf9\xf7\
+		\\x4d\x43\x51\x5f\x75\x7b\x69\x67\
+		\\x3d\x33\x21\x2f\x05\x0b\x19\x17\
+		\\x76\x78\x6a\x64\x4e\x40\x52\x5c\
+		\\x06\x08\x1a\x14\x3e\x30\x22\x2c\
+		\\x96\x98\x8a\x84\xae\xa0\xb2\xbc\
+		\\xe6\xe8\xfa\xf4\xde\xd0\xc2\xcc\
+		\\x41\x4f\x5d\x53\x79\x77\x65\x6b\
+		\\x31\x3f\x2d\x23\x09\x07\x15\x1b\
+		\\xa1\xaf\xbd\xb3\x99\x97\x85\x8b\
+		\\xd1\xdf\xcd\xc3\xe9\xe7\xf5\xfb\
+		\\x9a\x94\x86\x88\xa2\xac\xbe\xb0\
+		\\xea\xe4\xf6\xf8\xd2\xdc\xce\xc0\
+		\\x7a\x74\x66\x68\x42\x4c\x5e\x50\
+		\\x0a\x04\x16\x18\x32\x3c\x2e\x20\
+		\\xec\xe2\xf0\xfe\xd4\xda\xc8\xc6\
+		\\x9c\x92\x80\x8e\xa4\xaa\xb8\xb6\
+		\\x0c\x02\x10\x1e\x34\x3a\x28\x26\
+		\\x7c\x72\x60\x6e\x44\x4a\x58\x56\
+		\\x37\x39\x2b\x25\x0f\x01\x13\x1d\
+		\\x47\x49\x5b\x55\x7f\x71\x63\x6d\
+		\\xd7\xd9\xcb\xc5\xef\xe1\xf3\xfd\
+		\\xa7\xa9\xbb\xb5\x9f\x91\x83\x8d"#
diff --git a/Number/Basic.hs b/Number/Basic.hs
--- a/Number/Basic.hs
+++ b/Number/Basic.hs
@@ -1,4 +1,11 @@
 {-# LANGUAGE BangPatterns #-}
+-- |
+-- Module      : Number.Basic
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+
 module Number.Basic
 	( sqrti
 	, gcde
diff --git a/Number/Generate.hs b/Number/Generate.hs
--- a/Number/Generate.hs
+++ b/Number/Generate.hs
@@ -1,3 +1,10 @@
+-- |
+-- Module      : Number.Generate
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+
 module Number.Generate
 	( generateMax
 	, generateBetween
@@ -12,7 +19,7 @@
 -- | generate a positive integer between 0 and m.
 -- using as many bytes as necessary to the same size as m, that are converted to integer.
 generateMax :: CryptoRandomGen g => g -> Integer -> Either GenError (Integer, g)
-generateMax rng m = case genBytes (logiBytes m) rng of
+generateMax rng m = case genBytes (lengthBytes m) rng of
 	Left err         -> Left err
 	Right (bs, rng') -> Right (os2ip bs `mod` m, rng')
 
@@ -29,8 +36,3 @@
 generateOfSize rng bits = case genBytes (bits `div` 8) rng of
 	Left err         -> Left err
 	Right (bs, rng') -> Right (os2ip $ snd $ B.mapAccumL (\acc w -> (0, w .|. acc)) 0xc0 bs, rng')
-
-logiBytes :: Integer -> Int
-logiBytes n
-	| n < 256   = 1
-	| otherwise = 1 + logiBytes (n `div` 256)
diff --git a/Number/ModArithmetic.hs b/Number/ModArithmetic.hs
--- a/Number/ModArithmetic.hs
+++ b/Number/ModArithmetic.hs
@@ -1,4 +1,11 @@
 {-# LANGUAGE BangPatterns #-}
+-- |
+-- Module      : Number.ModArithmetic
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+
 module Number.ModArithmetic
 	( exponantiation_rtl_binary
 	, inverse
diff --git a/Number/Polynomial.hs b/Number/Polynomial.hs
new file mode 100644
--- /dev/null
+++ b/Number/Polynomial.hs
@@ -0,0 +1,122 @@
+{-# LANGUAGE BangPatterns #-}
+-- |
+-- Module      : Number.Polynomial
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+
+module Number.Polynomial
+	( Monomial(..)
+	-- * polynomial operations
+	, Polynomial
+	, toList
+	, fromList
+	, addPoly
+	, subPoly
+	, mulPoly
+	, squarePoly
+	, expPoly
+	, divPoly
+	, negPoly
+	) where
+
+import Data.List (intercalate, sort)
+import Data.Vector ((!), Vector)
+import qualified Data.Vector as V
+import Control.Arrow (first)
+
+data Monomial = Monomial {-# UNPACK #-} !Int !Integer
+	deriving (Eq)
+
+data Polynomial = Polynomial (Vector Monomial)
+	deriving (Eq)
+
+instance Ord Monomial where
+	compare (Monomial w1 v1) (Monomial w2 v2) =
+		case compare w1 w2 of
+			EQ -> compare v1 v2
+			r  -> r
+
+instance Show Monomial where
+	show (Monomial w v) = show v ++ "x^" ++ show w
+
+instance Show Polynomial where
+	show (Polynomial p) = intercalate "+" $ map show $ V.toList p
+
+toList (Polynomial p) = V.toList p
+
+fromList = Polynomial . V.fromList . reverse . sort . filterZero
+	where
+		filterZero = filter (\(Monomial _ v) -> v /= 0)
+
+getWeight (Polynomial p) n = look 0
+	where
+		plen = V.length p
+		look !i
+			| i >= plen = Nothing
+			| otherwise =
+				let (Monomial w v) = p ! i in
+				case compare w n of
+					LT -> Nothing
+					EQ -> Just v
+					GT -> look (i+1)
+		
+
+mergePoly f (Polynomial p1) (Polynomial p2) = fromList $ loop 0 0
+	where
+		l1 = V.length p1
+		l2 = V.length p2
+		loop !i1 !i2
+			| i1 == l1 && i2 == l2 = []
+			| i1 == l1             = (p2 ! i2) : loop i1 (i2+1)
+			| i2 == l2             = (p1 ! i1) : loop (i1+1) i2
+			| otherwise            =
+				let (coef, i1inc, i2inc) = addCoef (p1 ! i1) (p2 ! i2) in
+				coef : loop (i1+i1inc) (i2+i2inc)
+		addCoef m1@(Monomial w1 v1) m2@(Monomial w2 v2) =
+			case compare w1 w2 of
+				LT -> (Monomial w2 (f 0 v2), 0, 1)
+				EQ -> (Monomial w1 (f v1 v2), 1, 1)
+				GT -> (m1, 1, 0)
+
+addPoly = mergePoly (+)
+subPoly = mergePoly (-)
+
+negPoly (Polynomial p) = Polynomial $ V.map negateMonomial p
+	where negateMonomial (Monomial w v) = Monomial w (-v)
+
+mulPoly p1@(Polynomial v1) p2@(Polynomial v2) =
+	fromList $ filter (\(Monomial _ v) -> v /= 0) $ map (\i -> Monomial i (c i)) $ reverse [0..(m+n)]
+	where
+		(Monomial m _) = v1 ! 0
+		(Monomial n _) = v2 ! 0
+		c r = foldl (\acc i -> (b $ r-i) * (a $ i) + acc) 0 [0..r]
+			where
+				a = maybe 0 id . getWeight p1
+				b = maybe 0 id . getWeight p2
+
+squarePoly p = p `mulPoly` p
+
+expPoly p e = loop e
+	where
+		loop t 0 = t
+		loop t n = loop (squarePoly t) (n-1)
+
+divPoly :: Polynomial -> Polynomial -> (Polynomial, Polynomial)
+divPoly p1 p2@(Polynomial pp2) = first fromList $ divLoop p1
+	where divLoop d1@(Polynomial pp1)
+		| V.null pp1 = ([], d1)
+		| otherwise  =
+			let (Monomial w1 v1) = pp1 ! 0 in
+			let (Monomial w2 v2) = pp2 ! 0 in
+			let w = w1 - w2 in
+			let (v,r) = v1 `divMod` v2 in
+			if w >= 0 && r == 0
+				then
+					let mono = (Monomial w v) in
+					let remain = d1 `subPoly` (p2 `mulPoly` (fromList [mono])) in
+					let (l, finalRem) = divLoop remain in
+					(mono : l, finalRem)
+				else
+					([], d1)
diff --git a/Number/Prime.hs b/Number/Prime.hs
--- a/Number/Prime.hs
+++ b/Number/Prime.hs
@@ -1,3 +1,11 @@
+{-# LANGUAGE BangPatterns #-}
+-- |
+-- Module      : Number.Prime
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : Good
+
 module Number.Prime
 	( generatePrime
 	, generateSafePrime
@@ -5,7 +13,6 @@
 	, findPrimeFrom
 	, findPrimeFromWith
 	, primalityTestNaive
-	-- , primalityTestAKS
 	, primalityTestMillerRabin
 	, isCoprime
 	) where
@@ -20,7 +27,7 @@
 -- first a list of small primes are implicitely tested for divisibility,
 -- then the Miller Rabin algorithm is used with an accuracy of 30 recursions
 isProbablyPrime :: CryptoRandomGen g => g -> Integer -> Either GenError (Bool, g)
-isProbablyPrime rng n
+isProbablyPrime rng !n
 	| any (\p -> p `divides` n) (filter (< n) smallPrimes) = Right (False, rng)
 	| otherwise                                            = primalityTestMillerRabin rng 30 n
 
@@ -31,7 +38,7 @@
 	Right (sp, rng') -> findPrimeFrom rng' sp
 
 -- | generate a prime number of the form 2p+1 where p is also prime.
--- it is also know as a Sophie Germaine prime or safe prime.
+-- it is also knowed as a Sophie Germaine prime or safe prime.
 --
 -- The number of safe prime is significantly smaller to the number of prime,
 -- as such it shouldn't be used if this number is supposed to be kept safe.
@@ -44,7 +51,7 @@
 
 -- | find a prime from a starting point where the property hold.
 findPrimeFromWith :: CryptoRandomGen g => g -> (g -> Integer -> Either GenError (Bool,g)) -> Integer -> Either GenError (Integer, g)
-findPrimeFromWith rng prop n
+findPrimeFromWith rng prop !n
 	| even n        = findPrimeFromWith rng prop (n+1)
 	| otherwise     = case isProbablyPrime rng n of
 		Left err               -> Left err
@@ -62,52 +69,32 @@
 -- | Miller Rabin algorithm return if the number is probably prime or composite.
 -- the tries parameter is the number of recursion, that determines the accuracy of the test.
 primalityTestMillerRabin :: CryptoRandomGen g => g -> Int -> Integer -> Either GenError (Bool, g)
-primalityTestMillerRabin rng tries n
+primalityTestMillerRabin rng tries !n
 	| n <= 3     = error "Miller-Rabin requires tested value to be > 3"
 	| even n     = Right (False, rng)
 	| tries <= 0 = error "Miller-Rabin tries need to be > 0"
 	| otherwise  = loop rng (factorise 0 (n-1)) tries where
 		-- factorise n-1 into the form 2^s*d
 		factorise :: Integer -> Integer -> (Integer, Integer)
-		factorise s v
+		factorise !s !v
 			| v `testBit` 0 = (s, v)
 			| otherwise     = factorise (s+1) (v `shiftR` 1)
 		expmod = exponantiation_rtl_binary
 		-- when iteration reach zero, we have a probable prime
-		loop g _     0 = Right (True, g)
-		loop g (s,d) k = case generateBetween g 2 (n-2) of
+		loop g _       0 = Right (True, g)
+		loop g t@(_,d) k = case generateBetween g 2 (n-2) of
 			Left err      -> Left err
 			Right (a, g') ->
 				let x = expmod a d n in
 				if x == (1 :: Integer) || x == (n-1)
-					then loop g' (s,d) (k-1)
-					else loop' g' (s,d) (k-1) ((x*x) `mod` n) 1
+					then loop g' t (k-1)
+					else loop' g' t (k-1) ((x*x) `mod` n) 1
 		-- loop from 1 to s-1. if we reach the end then it's composite
-		loop' g o@(s,_) km1 x2 r
+		loop' g t@(s,_) km1 !x2 !r
 			| r == s      = Right (False, g)
 			| x2 == 1     = Right (False, g)
-			| x2 /= (n-1) = loop' g o km1 ((x2*x2) `mod` n) (r+1)
-			| otherwise   = loop g o km1
-			
--- | AKS primality test return if the number is prime or composite
--- it uses the following algorithm:
---   Input: integer n > 1.
---   If n = ab for integers a > 0 and b > 1, output composite.
---   Find the smallest r such that o_r(n) > log2(n).
---   If 1 < gcd(a,n) < n for some a ≤ r, output composite.
---   If n <= r, output prime.
---   For a = 1 to lower-bound(sqrt(phi(n)) * log2(n)) do
---     if (X+a)n ≠ Xn+a (mod Xr − 1,n), output composite;
---   Output prime.
-primalityTestAKS :: Integer -> Bool
-primalityTestAKS n = undefined
-	where
-		-- for p prime, the euler totient (# of coprime to n) is clearly n -1
-		totient = n-1
-		ubound = (fst $ sqrti totient) * (logi n)
-		logi z
-			| z == 0    = 0
-			| otherwise = 1 + logi (z `shiftR` 1)
+			| x2 /= (n-1) = loop' g t km1 ((x2*x2) `mod` n) (r+1)
+			| otherwise   = loop g t km1
 
 -- | Test naively is integer is prime.
 -- while naive, we skip even number and stop iteration at i > sqrt(n)
diff --git a/Number/Serialize.hs b/Number/Serialize.hs
--- a/Number/Serialize.hs
+++ b/Number/Serialize.hs
@@ -1,6 +1,7 @@
 module Number.Serialize
 	( i2osp
 	, os2ip
+	, lengthBytes
 	) where
 
 import Data.ByteString (ByteString)
@@ -17,3 +18,9 @@
 	where
 		divMod256 0 = Nothing
 		divMod256 n = Just (fromIntegral a,b) where (b,a) = n `divMod` 256
+
+-- | returns the number of bytes to store an integer with i2osp
+lengthBytes :: Integer -> Int
+lengthBytes n
+	| n < 256   = 1
+	| otherwise = 1 + lengthBytes (n `div` 256)
diff --git a/System/Endian.hs b/System/Endian.hs
new file mode 100644
--- /dev/null
+++ b/System/Endian.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE CPP #-}
+module System.Endian (littleEndian) where
+
+
+#ifdef BIG_ENDIAN
+littleEndian :: Bool
+littleEndian = False
+#elif defined(LITTLE_ENDIAN)
+littleEndian :: Bool
+littleEndian = True
+#else
+
+import System.Info (arch)
+
+littleEndian :: Bool
+littleEndian = arch /= "sparc" && arch /= "ppc"
+#endif
diff --git a/cryptocipher.cabal b/cryptocipher.cabal
--- a/cryptocipher.cabal
+++ b/cryptocipher.cabal
@@ -1,5 +1,5 @@
 Name:                cryptocipher
-Version:             0.2.12
+Version:             0.2.13
 Description:         Symmetrical Block, Stream and PubKey Ciphers
 License:             BSD3
 License-file:        LICENSE
@@ -24,6 +24,7 @@
   Build-Depends:     base >= 4 && < 5
                    , bytestring
                    , vector >= 0.7
+                   , ghc-prim
                    , primitive
                    , crypto-api >= 0.5
                    , tagged
@@ -38,8 +39,14 @@
                      Number.Serialize
                      Number.Generate
                      Number.Basic
+                     Number.Polynomial
                      Number.Prime
+                     System.Endian
   ghc-options:       -Wall
+  if arch(ppc) || arch(sparc)
+    cpp-options: -DBIG_ENDIAN
+  else
+    cpp-options: -DLITTLE_ENDIAN
 
 Executable           Tests
   Main-Is:           Tests.hs
@@ -52,6 +59,10 @@
                    , QuickCheck >= 2
   else
     Buildable:       False
+  if arch(ppc) || arch(sparc)
+    cpp-options: -DBIG_ENDIAN
+  else
+    cpp-options: -DLITTLE_ENDIAN
 
 Executable           Benchmarks
   Main-Is:           Benchmarks.hs
@@ -62,6 +73,10 @@
                    , mtl
   else
     Buildable:       False
+  if arch(ppc) || arch(sparc)
+    cpp-options: -DBIG_ENDIAN
+  else
+    cpp-options: -DLITTLE_ENDIAN
 
 source-repository head
   type:     git
