-----------------------------------------------------------------------------
-- |
-- Module      :  Codec.Encryption.TEA
-- Copyright   :  (c) John Meacham 2008
-- License     :  BSD-style (see the file ReadMe.tex)
--
-- Stability   :  experimental
-- Portability :  portable
--
-- Implementation of the TEA tiny encryption algorithm
--
-----------------------------------------------------------------------------

module Codec.Encryption.TEA(
    TEAKey(TEAKey),
    encrypt,
    decrypt
    ) where

import Data.Bits
import Data.Word

-- We don't use LargeKey for both efficiency and practical reasons.

data TEAKey = TEAKey {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32


delta :: Word32
delta :: Word32
delta = Word32
0x9e3779b9

rounds :: Integer
rounds = Integer
32

encrypt ::  TEAKey -> Word64 -> Word64
encrypt :: TEAKey -> Word64 -> Word64
encrypt (TEAKey Word32
k0 Word32
k1 Word32
k2 Word32
k3) Word64
v = forall {a} {t}.
(Bits a, Num t, Num a, Eq t) =>
t -> Word32 -> Word32 -> Word32 -> a
f Integer
rounds Word32
0 Word32
v0 Word32
v1 where
    v0,v1 :: Word32
    v0 :: Word32
v0 = forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
v
    v1 :: Word32
v1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Word64
v forall a. Bits a => a -> Int -> a
`shiftR` Int
32
    f :: t -> Word32 -> Word32 -> Word32 -> a
f t
a Word32
b Word32
c Word32
d | t
a seq :: forall a b. a -> b -> b
`seq` Word32
b seq :: forall a b. a -> b -> b
`seq` Word32
c seq :: forall a b. a -> b -> b
`seq` Word32
d seq :: forall a b. a -> b -> b
`seq` Bool
False = forall a. HasCallStack => a
undefined
    f t
0 Word32
_   Word32
v0 Word32
v1 = (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
v1 forall a. Bits a => a -> Int -> a
`shiftL` Int
32) forall a. Bits a => a -> a -> a
.|. (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
v0 forall a. Bits a => a -> a -> a
.&. a
0xffffffff)
    f t
n Word32
sum Word32
v0 Word32
v1 = t -> Word32 -> Word32 -> Word32 -> a
f (t
n forall a. Num a => a -> a -> a
- t
1) Word32
sum' Word32
v0' Word32
v1' where
        sum' :: Word32
sum' = Word32
sum forall a. Num a => a -> a -> a
+ Word32
delta
        v0' :: Word32
v0' = (Word32
v0 forall a. Num a => a -> a -> a
+ (((Word32
v1 forall a. Bits a => a -> Int -> a
`shiftL` Int
4) forall a. Num a => a -> a -> a
+ Word32
k0) forall a. Bits a => a -> a -> a
`xor` (Word32
v1 forall a. Num a => a -> a -> a
+ Word32
sum') forall a. Bits a => a -> a -> a
`xor` ((Word32
v1 forall a. Bits a => a -> Int -> a
`shiftR` Int
5) forall a. Num a => a -> a -> a
+ Word32
k1)))
        v1' :: Word32
v1' = (Word32
v1 forall a. Num a => a -> a -> a
+ (((Word32
v0' forall a. Bits a => a -> Int -> a
`shiftL` Int
4) forall a. Num a => a -> a -> a
+ Word32
k2) forall a. Bits a => a -> a -> a
`xor` (Word32
v0' forall a. Num a => a -> a -> a
+ Word32
sum') forall a. Bits a => a -> a -> a
`xor` ((Word32
v0' forall a. Bits a => a -> Int -> a
`shiftR` Int
5) forall a. Num a => a -> a -> a
+ Word32
k3)))


decrypt ::  TEAKey -> Word64 -> Word64
decrypt :: TEAKey -> Word64 -> Word64
decrypt (TEAKey Word32
k0 Word32
k1 Word32
k2 Word32
k3) Word64
v = forall {a} {t}.
(Bits a, Num t, Num a, Eq t) =>
t -> Word32 -> Word32 -> Word32 -> a
f Integer
rounds Word32
0xC6EF3720 Word32
v0 Word32
v1 where
    v0,v1 :: Word32
    v0 :: Word32
v0 = forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
v
    v1 :: Word32
v1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Word64
v forall a. Bits a => a -> Int -> a
`shiftR` Int
32
    f :: t -> Word32 -> Word32 -> Word32 -> a
f t
a Word32
b Word32
c Word32
d | t
a seq :: forall a b. a -> b -> b
`seq` Word32
b seq :: forall a b. a -> b -> b
`seq` Word32
c seq :: forall a b. a -> b -> b
`seq` Word32
d seq :: forall a b. a -> b -> b
`seq` Bool
False = forall a. HasCallStack => a
undefined
    f t
0 Word32
_   Word32
v0 Word32
v1 = (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
v1 forall a. Bits a => a -> Int -> a
`shiftL` Int
32) forall a. Bits a => a -> a -> a
.|. (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
v0  forall a. Bits a => a -> a -> a
.&. a
0xFFFFFFFF)
    f t
n Word32
sum Word32
v0 Word32
v1 = t -> Word32 -> Word32 -> Word32 -> a
f (t
n forall a. Num a => a -> a -> a
- t
1) (Word32
sum forall a. Num a => a -> a -> a
- Word32
delta) Word32
v0' Word32
v1' where
        v1' :: Word32
v1' = (Word32
v1 forall a. Num a => a -> a -> a
- (((Word32
v0 forall a. Bits a => a -> Int -> a
`shiftL` Int
4) forall a. Num a => a -> a -> a
+ Word32
k2) forall a. Bits a => a -> a -> a
`xor` (Word32
v0 forall a. Num a => a -> a -> a
+ Word32
sum) forall a. Bits a => a -> a -> a
`xor` ((Word32
v0 forall a. Bits a => a -> Int -> a
`shiftR` Int
5) forall a. Num a => a -> a -> a
+ Word32
k3)))
        v0' :: Word32
v0' = (Word32
v0 forall a. Num a => a -> a -> a
- (((Word32
v1' forall a. Bits a => a -> Int -> a
`shiftL` Int
4) forall a. Num a => a -> a -> a
+ Word32
k0) forall a. Bits a => a -> a -> a
`xor` (Word32
v1' forall a. Num a => a -> a -> a
+ Word32
sum) forall a. Bits a => a -> a -> a
`xor` ((Word32
v1' forall a. Bits a => a -> Int -> a
`shiftR` Int
5) forall a. Num a => a -> a -> a
+ Word32
k1)))



{-
 void encrypt (unsigned long* v, unsigned long* k) {
    unsigned long v0=v[0], v1=v[1], sum=0, i;           /* set up */
    unsigned long delta=0x9e3779b9;                     /* a key schedule constant */
    unsigned long k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i < 32; i++) {                            /* basic cycle start */
        sum += delta;
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  /* end cycle */
    }
    v[0]=v0; v[1]=v1;
}

void decrypt (unsigned long* v, unsigned long* k) {
    unsigned long v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
    unsigned long delta=0x9e3779b9;                     /* a key schedule constant */
    unsigned long k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<32; i++) {                              /* basic cycle start */
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;                                   /* end cycle */
    }
    v[0]=v0; v[1]=v1;
}

-}