diff --git a/COPYING b/COPYING
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (c) 20[11..12], Marcel Fourné
+Copyright (c) 20[11..13], Marcel Fourné
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,49 +1,2 @@
-ECC
----
-
-RSA just doesn't cut it anymore for fast public-key crypto. Keys are large for reasonable security making it quite slow...
-Enter elliptic curves: smaller numbers are necessary and everything is faster. Maybe this library is not for embedded system usage, but now people can experiment with ECC for those use-cases where some form of RSA would be chosen otherwise.
-
-
-Hecc.Base
------------
-
-This is the Haskell-Elliptic-Curve-Cryptography-library, or maybe more appropriately atm it is only the basic math for many ECC-algorithms the user of this library may wish to implement.
-As an example the EC-variant of the Diffie-Hellman key-exchange is included which shows how the values can be computed with this library (a better variant will follow, this is just an example).
-Also included is a basic speed-benchmarking-file (point multiplication) for example on the NIST Curve P-256 (the author wants some usage results and performance-numbers... so...).
-
-
-The API
--------
-
-...is not stable right now. If anybody wants to use the library in its current state for serious cryptographic uses, then by all means contact the author!
-
-The Code began as a prototyped script and has since been polished, but this is best-effort work in progress.
-
-
-pmul
-----
-
-Point multiplication can be done by this library using one of two algorithms: double-and-add and mongomery ladder. The latter is the default and is intended to be mostly resistant to timing attacks, the former may be faster, depending on the number it multiplies by.
-
-
-Timing Attack Resistance
-------------------------
-The point multiplication uses the montgomery ladder algorithm which should be timing attack resistant, but when mul by a number in binary form 1000..0 the operation gets strangely fast (us instead of ms) and 1000..0001 it is strangely slow (1.5 times), which hints to something fishy going on. More research will follow, but sidechannel-resistance is not totally out-of-focus. 
-Testing has given me the idea that the following-zeroes-case massively benefits from branch-prediction and the trailing-one-case throws it totally off (will have to check that on other CPUs). "More natural" numbers are safer (tested), but I wouldn't dare to say that the matter is resolved.
-P.S.: 2^N-1 does not show the cache-problem, only long rows of zeroes.
-
-
-Plan
-----
-
-Some algorithms using these primitives will likely follow (ECDH, maybe ECDSA; also: better versions of the primitives).
-Speed is a good goal, may have some more improvements in the future.
-Testing is on the list.
-Hyperelliptic Curves... maybe.
-The upcoming Integer/GMP switch... haven't decided whether side to take... GMP-bindings or pure Haskell.
-
-Motivation
-----------
-
-This is a side-project from which other people may benefit. Due to time-constraints, I can't work as much on it as I would like. If you use/like it or want to make some criticism heard, please write me an email.
+This library was created as an offspring to hecc, the Haskell library for Elliptic Curve Cryptography, but it should be more general than that.
+The aim is to have one (pure, Haskell) implementation for (binary) finite field arithmetic which is suitable for practical use in most cases.
diff --git a/hF2.cabal b/hF2.cabal
--- a/hF2.cabal
+++ b/hF2.cabal
@@ -1,12 +1,13 @@
 Name:                hF2
-Version:             0.1
+Version:             0.2
 Synopsis:	     F(2^e) math for cryptography
-Description:         A timing attack resistant F(2^e) backend, all operations on little-endian data in unboxed bit vectors
+Description:         This library implements polynomials on Binary Fields F(2^e), a subform of Finite Fields F(p^n) also known as Galois Fields GF(p^n).
+		     It is intended as a backend for cryptographic use and the code should be timing attack resistant.
 License:             BSD3
 License-file:        COPYING
-Copyright:	     (c) Marcel Fourné, 2011-2012
+Copyright:	     (c) Marcel Fourné, 2011-2013
 Author:              Marcel Fourné
-Maintainer:          Marcel Fourné (hF2@bitrot.dyndns.org)
+Maintainer:          Marcel Fourné (mail@marcelfourne.de)
 Category:	     Cryptography
 Stability:	     alpha
 Build-Type:          Simple
@@ -17,9 +18,9 @@
   src
  Build-Depends:
   base >= 4 && < 5,
-  bitvec,
-  vector
+  vector,
+  cereal
  Exposed-modules:
   Data.F2
  ghc-options:
-  -Wall -fllvm -feager-blackholing -O2
+  -Wall
diff --git a/src/Data/F2.hs b/src/Data/F2.hs
--- a/src/Data/F2.hs
+++ b/src/Data/F2.hs
@@ -1,156 +1,248 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Data.F2
--- Copyright   :  (c) Marcel Fourné 2011-2012
+-- Copyright   :  (c) Marcel Fourné 2011-2013
 -- License     :  BSD3
--- Maintainer  :  Marcel Fourné (hecc@bitrot.dyndns.org)
+-- Maintainer  :  Marcel Fourné (mail@marcelfourne.de)
+-- Stability   :  experimental
+-- Portability :  Good
 --
--- A timing attack resistant F(2^e) backend, all operations on little-endian data in unboxed bit vectors
+-- A hopefully timing attack resistant F(2^e) backend, 
+-- i.e. binary representation polynomial arithmetic
+-- The presented interface is Big Endian, like Data.Bits
+-- All indices are [0 .. (length - 1)]
+-- TODO: further optimization
 --
 -----------------------------------------------------------------------------
 
+{-# OPTIONS_GHC -O2 -fllvm -optlo-O3 -feager-blackholing #-}
+{-# LANGUAGE BangPatterns #-}
+
 module Data.F2 (
-  Data.F2.F2,
-  Data.F2.add,
-  Data.F2.shift,
-  Data.F2.mul,
-  Data.F2.reduceBy,
-  Data.F2.pow,
-  Data.F2.fromInteger,
-  Data.F2.toInteger,
-  Data.F2.length,
-  Data.F2.even,
-  Data.F2.odd,
-  Data.F2.div,
-  Data.F2.bininv
-  )
-       where
+  F2,
+  pow,
+  toInteger,
+  even,
+  odd,
+  mod,
+  div,
+  bininv
+  ) where
 
-import Numeric
-import Data.Char
-import Data.Maybe
-import qualified Data.List(map)
-import qualified Data.Vector.Unboxed as V
-import qualified Data.Bits as B
-import qualified Data.Bit as Bit
-import qualified Data.Vector.Unboxed.Bit as VB
+import Prelude hiding ((^),fromInteger,toInteger,even,odd,div,mod)
+import qualified Prelude as P ((^),fromInteger,toInteger,even,odd,div,mod)
+import qualified Numeric as N (showIntAtBase)
+import qualified Data.Char as C (intToDigit)
+import qualified Data.Bits as B (Bits,bit,bitSize,complement,isSigned,popCount,rotate,shift,testBit,xor,(.|.),(.&.))
+import qualified Data.Vector.Unboxed as V (Vector,reverse,dropWhile,length,singleton,last,mapM_,fromList,replicate,(++),zipWith,head,tail,take,map,drop,(!),foldl')
+import qualified Data.Word as W (Word)
+import Data.Serialize as S (Serialize,put,get)
+import Control.Monad (replicateM)
 
-type F2 = V.Vector Bit.Bit
+-- internal helper definitions
+wordMaxF2 :: Integer
+wordMaxF2 = P.toInteger (maxBound::W.Word)
+wordSizeF2 :: Int
+wordSizeF2 = B.bitSize (0::W.Word)
 
--- |the binary representation of an Integer
-binary :: Integer -> [Char]
-binary = flip (showIntAtBase (2::Integer) intToDigit) []
+-- | the binary representation of an Integer, as a list
+binary :: (Integral a, Show a) => a -> [Char]
+binary = flip (N.showIntAtBase 2 C.intToDigit) []
 
--- |binary addition of @a@ and @b@
-add :: F2 -> F2 -> F2
-add a b = let l1 = V.length a
-              l2 = V.length b
-          in if l1 <= l2 then VB.zipWords (B.xor) (VB.pad l2 a) b
-             else VB.zipWords (B.xor) a (VB.pad l1 b)
+-- | helper function to shorten unnecesary long representations
+shorten :: F2 -> F2
+shorten !(F2 _ !va) = let vn = V.reverse $ V.dropWhile (== 0) $ V.reverse va
+                          vnew = if V.length vn == 0 
+                                 then V.singleton 0
+                                 else vn
+                          indexnew i | i >= 0 = if B.testBit (V.last vnew) i == True 
+                                                then i + ((V.length vnew) - 1) * wordSizeF2 + 1
+                                                else indexnew (i - 1)
+                                     | otherwise = 1
+                      in F2 (indexnew wordSizeF2) vnew
 
--- |a simple bitshift where @n@ shifts right, a negative @n@ shifts left
-shift :: F2 -> Int -> F2
-shift a n = if n == 0 then a
-            else if n > 0 then V.replicate n (Bit.fromBool False) V.++ a
-                 else V.take ((V.length a) + n) a
+-- Be careful with those indices! The usage of quotRem with them has caused some headache.
+-- | F2 consist of an exact length of meaningful bits an a representation of those bits in a possibly larger Vector of Words, Note: The vectors use small to large indices, but the Data.Word endianness is of no concern as it is hidden by Data.Bits
+data F2 = F2 {-# UNPACK #-} !Int !(V.Vector W.Word) 
+        deriving (Show) -- Note: Ord, Enum do not make sense for F2, but perhaps by translation to Integer, what about Real?
 
--- |binary multiplication of @a@ and @b@
-mul :: F2 -> F2 -> F2
-mul a b = let l1 = V.length a
-              l2 = V.length b
-              len = l1 + l2
-              nullen = V.replicate len (Bit.fromBool False)
-              pseudo = V.replicate l2 (Bit.fromBool False)
-              fun a1 b1 | not $ V.null a1 = let ltemp = (V.length a1) - 1
-                                            in if V.last a1 == Bit.fromBool True 
-                                            -- real branch
-                                            then fun (V.take ltemp a1) (add b1 (shift b ltemp))
-                                            -- for timing-attack-resistance xor with 0s
-                                            else fun (V.take ltemp a1) (add b1 (shift pseudo ltemp))
-                        | otherwise = b1
-          in elimFalses $ fun a nullen
+-- TODO: more thought on (==), timing-attack resistance
+instance Eq F2 where
+  (==) !a !b = (toInteger a) == (toInteger b)
 
--- |polynomial reduction of @a@ via @r@             
-reduceBy :: F2 -> F2 -> F2
-reduceBy a r | V.length r == 1 && V.head r == VB.fromBool True = V.singleton $ VB.fromBool False
-             | V.length r == 1 && V.head r == VB.fromBool False = a
-             | otherwise = let lr = V.length r
-                               pseudo = V.replicate lr (Bit.fromBool False)
-                               fun z | V.length z >= lr = let ltemp = (V.length z) - 1
-                                                          in if V.last z == Bit.fromBool True
-                                                             -- real branch
-                                                             then fun (V.take ltemp $ add z (shift r (ltemp - lr)))
-                                                             -- for timing-attack-resistance xor with 0s
-                                                             else fun (V.take ltemp $ add z (shift pseudo (ltemp - lr)))
-                                     | otherwise = z
-                           in elimFalses $ fun a
+instance Serialize F2 where
+  put !a = let (F2 l v) = shorten a
+           in S.put l >> V.mapM_ (S.put) v
+  get = do
+    l <- S.get
+    let len = let (d,r) = quotRem l wordSizeF2
+              in if r == 0 then d else d + 1
+    w <- replicateM len (S.get)
+    return $ (F2) l $ V.fromList w
 
--- | the power function, @b@ ^ @k@, using Montgomery ladder and some low-@k@ hardcoding against overheads
-pow :: F2 -> F2 -> F2
-pow b k | k == Data.F2.fromInteger 0 = V.singleton $ Bit.fromBool True
-        | k == Data.F2.fromInteger 1 = b
-        | k == Data.F2.fromInteger 2 = mul b b
-        | k == Data.F2.fromInteger 3 = mul b $ mul b b
-        | otherwise = let power2 a = mul a a
-                          ex p1 p2 i
-                            | i < 0 = p1
-                            | not $ Bit.toBool $ k V.! i = ex (power2 p1) (mul p1 p2) (i - 1)
-                            | otherwise = ex (mul p1 p2) (power2 p2) (i - 1)
-                      in ex b (power2 b) ((V.length k) - 2)
+instance Num F2 where 
+  (+) = B.xor
+  -- The timing attack resistance for (*) looks brittle, needs more careful thought
+  (*) !a@(F2 !la !va) !b@(F2 !lb !vb) = 
+    let vl1 = V.length va
+        vl2 = V.length vb
+        nullen = F2 la $ V.replicate vl1 0
+        pseudo = F2 lb $ V.replicate vl2 0
+        fun i b1 | i < la = if B.testBit a i
+                            -- real branch
+                            then fun (i + 1) (b1 `B.xor` (B.shift b i))
+                            -- for timing-attack-resistance xor with 0s
+                            else fun (i + 1) (b1 `B.xor` (B.shift pseudo i))
+                 | otherwise = b1
+    in fun 0 nullen
+  -- always abs
+  abs !a = a
+  -- always unsigned
+  signum _ = 1
+  fromInteger !i = 
+    if i >= 0 
+    then let bin = binary i
+             helper a = 
+               if a <= wordMaxF2 then V.singleton $ P.fromInteger a
+               else let (d,rest) = quotRem a (wordMaxF2 + 1)
+                    in  (V.singleton $ P.fromInteger rest) V.++ (helper d)
+         in F2 (length bin) (helper i)
+    else error "F2 are only defined for non-negative Integers"
 
--- | a helper function to shorten @a@ to length @n@
-shortenTo :: F2 -> Int -> F2
-shortenTo a n = V.take n a
-                
--- | a helper function to shorten all MSB-leading "0" from @a@, this shortens unreduced results from multiplications
-elimFalses :: F2 -> F2
-elimFalses a = let i = V.length a
-                   r = V.reverse a
-                   find = VB.first (Bit.fromBool True) r
-               in if find == Nothing then V.singleton $ VB.fromBool False
-                  else shortenTo a $ i - (fromJust find)
+instance B.Bits F2 where
+  (.&.) !(F2 !la !va) !(F2 !lb !vb) = 
+    let vl1 = V.length va
+        vl2 = V.length vb
+        vdiff = abs $ vl1 - vl2
+    in if vl1 == vl2 then F2 (if la >= lb then la else lb) $ V.zipWith (B..&.) va vb
+       else if vl1 > vl2 
+            then F2 la $ V.zipWith (B..&.) va $ V.replicate vdiff 0 V.++ vb
+            else F2 lb $ V.zipWith (B..&.) (V.replicate vdiff 0 V.++ va) vb
+  (.|.) !(F2 !la !va) !(F2 !lb !vb) = 
+    let vl1 = V.length va
+        vl2 = V.length vb
+        vdiff = abs $ vl1 - vl2
+    in if vl1 == vl2 then F2 (if la >= lb then la else lb) $ V.zipWith (B..|.) va vb
+       else if vl1 > vl2 
+            then F2 la $ V.zipWith (B..|.) va $ V.replicate vdiff 0 V.++ vb
+            else F2 lb $ V.zipWith (B..|.) (V.replicate vdiff 0 V.++ va) vb
+  xor !(F2 !la !va) !(F2 !lb !vb) = 
+    let vl1 = V.length va
+        vl2 = V.length vb
+        vdiff = abs $ vl1 - vl2
+    in if vl1 == vl2 then F2 (if la >= lb then la else lb) $ V.zipWith (B.xor) va vb
+       else if vl1 > vl2 
+            then F2 la $ V.zipWith (B.xor) va $ V.replicate vdiff 0 V.++ vb
+            else F2 lb $ V.zipWith (B.xor) (V.replicate vdiff 0 V.++ va) vb
+  complement !(F2 !la !va) = F2 la $ V.map (B.complement) va
+  -- Big Endian on Words! Machine Endianness should not be important, Data.Bits handles it.
+  -- The timing attack resistance for shift looks fishy at best! 
+  -- Prime target for optimization
+  shift !a@(F2 !la !va) !i = 
+    if i == 0 then a
+    else let newlen = la + i
+             newlenword = let (w,r) = newlen `quotRem` (wordSizeF2)
+                          in if r > 0 then w + 1 else w
+             realshift = i `rem` wordSizeF2
+             veclendiff = newlenword - (V.length va)
+             svec = if veclendiff >= 0 
+                    then if realshift > 0 
+                         then V.replicate (veclendiff - 1) 0 V.++ (V.map (flip B.shift realshift) va) V.++ V.singleton 0
+                         else V.replicate veclendiff 0 V.++ V.map (flip B.shift realshift) va
+                    else V.drop (abs veclendiff) (V.map (flip B.shift (realshift)) va)
+             svecr = if veclendiff >= 0 
+                     then V.replicate veclendiff 0 V.++ V.map (flip B.shift (realshift - wordSizeF2)) va
+                     else V.drop (abs veclendiff) (V.map (flip B.shift (wordSizeF2 + realshift)) va)
+         in if newlen >= 1 then F2 newlen $ V.zipWith (B.xor) svec svecr
+            else F2 1 $ V.singleton 0
+  rotate !a !i = B.shift a i
+  bitSize !(F2 !l _)= l
+  isSigned _ = False
+  bit !i = P.fromInteger $ 2 P.^ i
+  testBit !(F2 !la !va) !i = 
+    if i >= 0 
+    then if i < wordSizeF2 
+         then flip B.testBit i $ V.head va
+         else if i < la 
+              then let (index1,index2) = i `quotRem` wordSizeF2
+                   in flip B.testBit index2 $ (V.!) va index1
+              else False
+    else False
+  popCount !(F2 _ !va) = V.foldl' (+) 0 $ V.map B.popCount va
 
--- |conversion helper function
-fromInteger :: Integer -> F2
-fromInteger z = let helper a = if a == '1' then Bit.fromBool True
-                               else Bit.fromBool False
-                    bin = binary z
-                in V.reverse $ V.fromList $ Data.List.map helper bin
+-- instance Real F2 where -- TODO?
 
--- |conversion helper function
+-- instance Integral F2 where -- TODO?
+
+-- |conversion to Integer
 toInteger :: F2 -> Integer
-toInteger z = let helper a = if a == Bit.fromBool True then 1
-                             else 0
-                  it rest n = let len = V.length rest
-                              in if len > 0 then let el = V.last rest
-                                                 in it (V.take (len - 1) rest) (n + (helper el)*2^(len-1))
-                                 else n
-              in it z 0
+toInteger !(F2 !la !va) = 
+  if la <= wordSizeF2
+  then rem (P.toInteger $ V.head va) $ 2 P.^ (P.toInteger la)
+  else let len = V.length va
+           helper r z i = 
+             if i > 1
+             then helper (V.tail r) (z + (B.shift (P.toInteger $ V.head r) ((len - i) * wordSizeF2))) (i - 1)
+             else z + (B.shift (P.toInteger $ V.head r) ((len - i) * wordSizeF2))
+       in helper va 0 len
 
--- | the length of an F(2^e)
-length :: F2 -> Int
-length z = V.length z
+-- | Polynomial reduction, a.k.a. modulo on polynomials
+mod :: F2 -- ^ a
+       -> F2 -- ^ b
+       -> F2 -- ^ a `mod` b
+mod !a@(F2 !la _) !b@(F2 !lb !vb) 
+  | b == (P.fromInteger 0) = a
+  | b == (P.fromInteger 1) = P.fromInteger 0
+  | otherwise = let lbv = V.length vb
+                    pseudo = F2 lbv $ V.replicate lbv 0
+                    fun !z@(F2 _ !v) i | i >= lb = if B.testBit z (i - 1)
+                                                   -- real branch
+                                                   then fun (z + (B.shift b (i - lb))) (i - 1)
+                                                   -- for timing-attack-resistance xor with 0s
+                                                   else fun (z + (B.shift pseudo (i - lb))) (i - 1)
+                                       | otherwise = F2 i $ V.take ((i `quot` wordSizeF2) + 1) v -- shortening
+                in fun a $ la
 
--- | is the number even? The last bit decides...
+-- |The power function on F2
+pow :: F2 -- ^ a
+       -> Integer -- ^ k
+       -> F2 -- ^ a^k
+pow !a !k | k < 0 = error "negative exponent for the power function on F2"
+          | k == 0 = P.fromInteger 1
+          | k == 1 = a
+          | k == 2 = a * a
+          | k == 3 = a * a * a
+          | otherwise = let power2 z = z * z
+                            ex p1 p2 i
+                              | i < 0 = p1
+                              | B.testBit k i == False = ex (power2 p1) (p1 * p2) (i - 1)
+                              | otherwise = ex (p1 * p2) (power2 p2) (i - 1)
+                        in ex a (power2 a) ((length $ binary k) - 2)
+
+-- | O(1), a simple Test for the LSB
 even :: F2 -> Bool
-even a = not $ Data.F2.odd a
+even !(F2 _ !v) = B.testBit (V.head v) 0 == False
 
--- | is the number odd? The last bit decides...
+-- | O(1), a simple Test for the LSB
 odd :: F2 -> Bool
-odd a = Bit.toBool $ V.last a
-
--- | computing @k@/@f@ mod @m@ by binary inversion of @f@ in @m@
-div :: F2 -> F2 -> F2 -> F2
-div k f m = mul k $ bininv f m
+odd !(F2 _ !v) = B.testBit (V.head v) 0 == True
 
--- | computing the modular inverse of "@f@ `mod` @m@"
-bininv :: F2 -> F2 -> F2
-bininv f m = let helper u v g1 g2 | u == Data.F2.fromInteger 1 = g1
-                                  | otherwise = let j = (V.length u) - (V.length v)
-                                                in if j < 0 
-                                                   then helper (elimFalses (v `add` (shift u (-j)))) u (elimFalses (g2 `add` (shift g1 (-j)))) g1
-                                                   else helper (elimFalses (u `add` (shift v j))) v (elimFalses (g1 `add` (shift g2 j))) g2
-             in helper f m (Data.F2.fromInteger 1) (Data.F2.fromInteger 0)                          
-                
--- add (mul (Data.F2.fromInteger 371) (Data.F2.fromInteger 1794)) (mul (Data.F2.fromInteger 203) (Data.F2.fromInteger 2053))
--- Data.F2.toInteger $ bininv (Data.F2.fromInteger 371) (Data.F2.fromInteger 2053)
+-- | Polynomial division, needs 3 parameters instead of 2, computing k/f mod m by binary inversion of f in m
+div :: F2 -- ^ k
+       -> F2 -- ^ f
+       -> F2 -- ^ m
+       -> F2 -- ^ k/f `mod` m
+div !k !f !m = ((*) k $ bininv f m) `mod` m
+                         
+-- | binary inversion of f in m
+bininv :: F2 -- ^ f
+          -> F2 -- ^ m
+          -> F2 -- the binary inverse of f in m
+bininv !f !m = let helper :: F2 -> F2 -> F2 -> F2 -> F2
+                   helper !u@(F2 lu _) !v@(F2 lv _) !g1 !g2 
+                     | u == (P.fromInteger 1) = g1
+                     | otherwise = let j = (lu) - (lv)
+                                   in if j < 0 
+                                      then helper (shorten $ v + (B.shift u (-j))) u (shorten $ g2 + (B.shift g1 (-j))) g1
+                                      else helper (shorten $ u + (B.shift v j))    v (shorten $ g1 + (B.shift g2 j))    g2
+               in helper f m (P.fromInteger 1) (P.fromInteger 0) 
