diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+The following license covers this documentation, and the source code, except
+where otherwise indicated.
+
+Copyright 2011, Robin KAY. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/OddWord.cabal b/OddWord.cabal
new file mode 100644
--- /dev/null
+++ b/OddWord.cabal
@@ -0,0 +1,37 @@
+name:               OddWord
+version:            1.0.0
+license:            BSD3
+license-file:       LICENSE
+copyright:          (c) 2011 Robin KAY
+author:             Robin KAY
+maintainer:         Robin KAY <komadori@gekkou.co.uk>
+synopsis:           Provides a wrapper for deriving word types with fewer bits.
+category:           Data
+stability:          Stable
+cabal-version:      >= 1.10
+build-type:         Simple
+extra-source-files: test/*.hs
+homepage:           http://www.gekkou.co.uk/
+description:
+    Provdes the 'OddWord' type, which wraps an existing integer type and
+    exposes a subset of its bits as a new narrower word type. Includes
+    predefined type synonyms for all the odd sized words up to 63 bits.
+
+Library
+    hs-source-dirs:   src
+    exposed-modules:  Data.Word.Odd
+    default-language: Haskell2010
+    other-extensions: ScopedTypeVariables
+    build-depends:
+        base >= 4 && < 5
+
+Test-Suite oddword-tests
+    type:             exitcode-stdio-1.0
+    hs-source-dirs:   test
+    main-is:          Main.hs
+    default-language: Haskell2010
+    other-extensions: ScopedTypeVariables
+    build-depends:
+        base       >= 4   && < 5,
+        QuickCheck >= 2.4 && < 2.5,
+        OddWord    >= 1.0 && < 1.1
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Data/Word/Odd.hs b/src/Data/Word/Odd.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Word/Odd.hs
@@ -0,0 +1,211 @@
+{-# LANGUAGE Haskell2010, ScopedTypeVariables #-}
+
+module Data.Word.Odd (
+    -- * Odd Word Wrapper
+    OddWord,
+
+    -- * Type Numbers
+    TypeNum,
+    One,
+    Zero,
+
+    -- * Predefined Odd Words
+    Word1, Word2, Word3, Word4, Word5, Word6, Word7,
+    Word9,  Word10, Word11, Word12, Word13, Word14, Word15,
+    Word17, Word18, Word19, Word20, Word21, Word22, Word23, Word24,
+    Word25, Word26, Word27, Word28, Word29, Word30, Word31,
+    Word33, Word34, Word35, Word36, Word37, Word38, Word39, Word40,
+    Word41, Word42, Word43, Word44, Word45, Word46, Word47, Word48,
+    Word49, Word50, Word51, Word52, Word53, Word54, Word55, Word56,
+    Word57, Word58, Word59, Word60, Word61, Word62, Word63
+) where
+
+import Data.Bits
+import Data.Word
+import Data.Function
+
+-- | OddWord wraps the integer type specified in the first type parameter and
+-- exposes a subset of the available bits as an unsigned word. The number of
+-- bits to expose is encoded into the second type parameter.
+--
+-- The predefined word types provided by this module give some examples.
+newtype OddWord a n = OW {unOW :: a} deriving (Eq, Ord)
+
+data TypeNumBuilder a = TypeNumBuilder Int Int
+
+fromTypeNum :: TypeNumBuilder a -> Int
+fromTypeNum (TypeNumBuilder x _) = x
+
+-- | Intances of 'TypeNum' represent type-level numbers.
+class TypeNum a where
+    typeNum :: TypeNumBuilder a
+
+-- | Represents a type-level number with a leading one bit followed by the
+-- string of digits specified by a.
+data One a
+
+-- | Represents a type-level number with a placeholder zero bit followed by the
+-- string of digits specified by a.
+data Zero a
+
+instance TypeNum () where
+    typeNum = TypeNumBuilder 0 0
+
+instance (TypeNum a) => TypeNum (One a) where
+    typeNum = let (TypeNumBuilder n m) = (typeNum :: TypeNumBuilder a)
+              in TypeNumBuilder (n+bit m) (m+1)
+
+instance (TypeNum a) => TypeNum (Zero a) where
+    typeNum = let (TypeNumBuilder n m) = (typeNum :: TypeNumBuilder a)
+              in TypeNumBuilder (n) (m+1)
+
+pairOW :: (a, a) -> (OddWord a n, OddWord a n)
+pairOW = uncurry ((,) `on` OW)
+
+owMask :: forall a n. (Bits a, TypeNum n) => OddWord a n
+owMask = OW $ (flip (-) 1) $ bit $ fromTypeNum (typeNum :: TypeNumBuilder n)
+
+mapFst :: (a -> b) -> [(a, c)] -> [(b, c)]
+mapFst f xs = map (\(a,c) -> (f a,c)) xs
+
+instance (Show a) => Show (OddWord a n) where
+    showsPrec p (OW x) s = showsPrec p x s
+    show (OW x)          = show x
+    showList xs          = showList $ map unOW xs 
+
+instance (Read a) => Read (OddWord a n) where
+    readsPrec p s = mapFst OW $ readsPrec p s
+    readList s    = mapFst (map OW) $ readList s
+
+instance (Num a, Bits a, TypeNum n) => Num (OddWord a n) where
+    (OW l) + (OW r) = OW $ (l + r)  .&. unOW (owMask :: OddWord a n)
+    (OW l) * (OW r) = OW $ (l * r)  .&. unOW (owMask :: OddWord a n)
+    (OW l) - (OW r) = OW $ (l - r)  .&. unOW (owMask :: OddWord a n)
+    negate (OW x)   = OW $ negate x .&. unOW (owMask :: OddWord a n)
+    abs w = w
+    signum (OW x) | x == 0    = 0
+                  | otherwise = 1
+    fromInteger i = OW $ fromInteger i .&. unOW (owMask :: OddWord a n) 
+
+instance (Real a, Bits a, TypeNum n) => Real (OddWord a n) where
+    toRational (OW x) = toRational x
+
+instance (Num a, Bits a, TypeNum n) => Bounded (OddWord a n) where
+    minBound = 0
+    maxBound = owMask
+
+instance (Enum a, Ord a, Num a, Bits a, TypeNum n) => Enum (OddWord a n) where
+    succ x = x + 1
+    pred x = x - 1
+    toEnum i | i >= 0 && fromIntegral i <= (owMask :: OddWord a n)
+             = OW $ toEnum i
+             | otherwise = error "OddWord: toEnum: Out of range."
+    fromEnum (OW x) = fromEnum x
+    enumFrom x = enumFromTo x owMask
+    enumFromThen x1 x2 = enumFromThenTo x1 x2 bound
+                         where bound | x2 >= x1 = owMask
+                                     | otherwise = 0
+    enumFromTo (OW x) (OW y) = map OW $ enumFromTo x y
+    enumFromThenTo (OW x1) (OW x2) (OW y) = map OW $ enumFromThenTo x1 x2 y
+
+instance (Integral a, Bits a, TypeNum n) => Integral (OddWord a n) where
+    quot (OW n) (OW d) = OW $ quot n d
+    rem  (OW n) (OW d) = OW $ rem n d
+    div  (OW n) (OW d) = OW $ div n d
+    mod  (OW n) (OW d) = OW $ mod n d
+    quotRem (OW n) (OW d) = pairOW $ quotRem n d
+    divMod  (OW n) (OW d) = pairOW $ divMod n d
+    toInteger (OW x) = toInteger x
+
+instance (Bits a, TypeNum n) => Bits (OddWord a n) where
+    (OW l) .&. (OW r) = OW $ l .&. r
+    (OW l) .|. (OW r) = OW $ l .|. r
+    xor (OW l) (OW r) = OW $ xor l r
+    complement (OW x) = OW $ complement x .&. unOW (owMask :: OddWord a n)
+    bit n | n < fromTypeNum (typeNum :: TypeNumBuilder n)
+          = OW $ bit n
+          | otherwise = OW 0
+    setBit (OW x) n | n < fromTypeNum (typeNum :: TypeNumBuilder n)
+                    = OW $ setBit x n
+                    | otherwise = OW x
+    clearBit (OW x) n = OW $ clearBit x n
+    complementBit (OW x) n | n < fromTypeNum (typeNum :: TypeNumBuilder n)
+                           = OW $ complementBit x n
+                           | otherwise = OW x
+    testBit (OW x) n = testBit x n
+    bitSize _  = fromTypeNum (typeNum :: TypeNumBuilder n)
+    isSigned _ = False 
+    shiftL (OW x) n = OW $ shiftL x n .&. unOW (owMask :: OddWord a n)
+    shiftR (OW x) n = OW $ shiftR x n
+    rotateL (OW x) n = OW $
+        (shiftL x n' .&. unOW (owMask :: OddWord a n)) .|. shiftR x (w-n')
+        where n' = n `mod` w
+              w = fromTypeNum (typeNum :: TypeNumBuilder n)
+    rotateR (OW x) n = OW $
+        shiftR x n' .|. (shiftL x (w-n') .&. unOW (owMask :: OddWord a n))
+        where n' = n `mod` w
+              w  = fromTypeNum (typeNum :: TypeNumBuilder n)
+
+type Word1  = OddWord Word8             (One  ())
+type Word2  = OddWord Word8        (One (Zero ()))
+type Word3  = OddWord Word8        (One (One  ()))
+type Word4  = OddWord Word8  (One (Zero (Zero ())))
+type Word5  = OddWord Word8  (One (Zero (One  ())))
+type Word6  = OddWord Word8  (One (One  (Zero ())))
+type Word7  = OddWord Word8  (One (One  (One  ())))
+--type Word8
+type Word9  = OddWord Word16 (One (Zero (Zero (One  ()))))
+type Word10 = OddWord Word16 (One (Zero (Zero (Zero ()))))
+type Word11 = OddWord Word16 (One (Zero (One  (One  ()))))
+type Word12 = OddWord Word16 (One (Zero (One  (Zero ()))))
+type Word13 = OddWord Word16 (One (One  (Zero (One  ()))))
+type Word14 = OddWord Word16 (One (One  (Zero (Zero ()))))
+type Word15 = OddWord Word16 (One (One  (One  (One  ()))))
+--type Word16
+type Word17 = OddWord Word32 (One (Zero (Zero (Zero (One  ())))))
+type Word18 = OddWord Word32 (One (Zero (Zero (One  (Zero ())))))
+type Word19 = OddWord Word32 (One (Zero (Zero (One  (One  ())))))
+type Word20 = OddWord Word32 (One (Zero (One  (Zero (Zero ())))))
+type Word21 = OddWord Word32 (One (Zero (One  (Zero (One  ())))))
+type Word22 = OddWord Word32 (One (Zero (One  (One  (Zero ())))))
+type Word23 = OddWord Word32 (One (Zero (One  (One  (One  ())))))
+type Word24 = OddWord Word32 (One (One  (Zero (Zero (Zero ())))))
+type Word25 = OddWord Word32 (One (One  (Zero (Zero (One  ())))))
+type Word26 = OddWord Word32 (One (One  (Zero (One  (Zero ())))))
+type Word27 = OddWord Word32 (One (One  (Zero (One  (One  ())))))
+type Word28 = OddWord Word32 (One (One  (One  (Zero (Zero ())))))
+type Word29 = OddWord Word32 (One (One  (One  (Zero (One  ())))))
+type Word30 = OddWord Word32 (One (One  (One  (One  (Zero ())))))
+type Word31 = OddWord Word32 (One (One  (One  (One  (One  ())))))
+--type Word32
+type Word33 = OddWord Word64 (One (Zero (Zero (Zero (Zero (One  ()))))))
+type Word34 = OddWord Word64 (One (Zero (Zero (Zero (One  (Zero ()))))))
+type Word35 = OddWord Word64 (One (Zero (Zero (Zero (One  (One  ()))))))
+type Word36 = OddWord Word64 (One (Zero (Zero (One  (Zero (Zero ()))))))
+type Word37 = OddWord Word64 (One (Zero (Zero (One  (Zero (One  ()))))))
+type Word38 = OddWord Word64 (One (Zero (Zero (One  (One  (Zero ()))))))
+type Word39 = OddWord Word64 (One (Zero (Zero (One  (One  (One  ()))))))
+type Word40 = OddWord Word64 (One (Zero (One  (Zero (Zero (Zero ()))))))
+type Word41 = OddWord Word64 (One (Zero (One  (Zero (Zero (One  ()))))))
+type Word42 = OddWord Word64 (One (Zero (One  (Zero (One  (Zero ()))))))
+type Word43 = OddWord Word64 (One (Zero (One  (Zero (One  (One  ()))))))
+type Word44 = OddWord Word64 (One (Zero (One  (One  (Zero (Zero ()))))))
+type Word45 = OddWord Word64 (One (Zero (One  (One  (Zero (One  ()))))))
+type Word46 = OddWord Word64 (One (Zero (One  (One  (One  (Zero ()))))))
+type Word47 = OddWord Word64 (One (Zero (One  (One  (One  (One  ()))))))
+type Word48 = OddWord Word64 (One (One  (Zero (Zero (Zero (Zero ()))))))
+type Word49 = OddWord Word64 (One (One  (Zero (Zero (Zero (One  ()))))))
+type Word50 = OddWord Word64 (One (One  (Zero (Zero (One  (Zero ()))))))
+type Word51 = OddWord Word64 (One (One  (Zero (Zero (One  (One  ()))))))
+type Word52 = OddWord Word64 (One (One  (Zero (One  (Zero (Zero ()))))))
+type Word53 = OddWord Word64 (One (One  (Zero (One  (Zero (One  ()))))))
+type Word54 = OddWord Word64 (One (One  (Zero (One  (One  (Zero ()))))))
+type Word55 = OddWord Word64 (One (One  (Zero (One  (One  (One  ()))))))
+type Word56 = OddWord Word64 (One (One  (One  (Zero (Zero (Zero ()))))))
+type Word57 = OddWord Word64 (One (One  (One  (Zero (Zero (One  ()))))))
+type Word58 = OddWord Word64 (One (One  (One  (Zero (One  (Zero ()))))))
+type Word59 = OddWord Word64 (One (One  (One  (Zero (One  (One  ()))))))
+type Word60 = OddWord Word64 (One (One  (One  (One  (Zero (Zero ()))))))
+type Word61 = OddWord Word64 (One (One  (One  (One  (Zero (One  ()))))))
+type Word62 = OddWord Word64 (One (One  (One  (One  (One  (Zero ()))))))
+type Word63 = OddWord Word64 (One (One  (One  (One  (One  (One  ()))))))
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE Haskell2010, ScopedTypeVariables #-}
+
+module Main where
+
+import System.Exit
+import Test.QuickCheck hiding ((.&.))
+import Test.QuickCheck.Gen
+import Data.Bits
+import Data.Word
+import Data.Word.Odd
+import Control.Monad
+
+data UFunc =
+    Add   Integer | Mul   Integer | Sub   Integer | SubR  Integer |
+    Div   Integer | Mod   Integer | Quot  Integer | Rem   Integer |
+    DivR  Integer | ModR  Integer | QuotR Integer | RemR  Integer |
+    Neg           | Abs           | Inv           |
+    And   Integer | Or    Integer | Xor   Integer |
+    ClrB  Int     | SetB  Int     | InvB  Int     |
+    Shift Int     | Rot   Int
+    deriving Show
+
+instance Arbitrary (UFunc) where
+    arbitrary = oneof [
+        choose (0, 0xffff) >>= return . Add,
+        choose (0, 0xffff) >>= return . Mul,
+        choose (0, 0xffff) >>= return . Sub,
+        choose (0, 0xffff) >>= return . SubR,
+        choose (0, 0xffff) >>= return . Div,
+        choose (0, 0xffff) >>= return . Mod,
+        choose (0, 0xffff) >>= return . Quot,
+        choose (0, 0xffff) >>= return . Rem,
+        choose (0, 0xffff) >>= return . DivR,
+        choose (0, 0xffff) >>= return . ModR,
+        choose (0, 0xffff) >>= return . QuotR,
+        choose (0, 0xffff) >>= return . RemR,
+        return Neg,
+        return Abs,
+        return Inv,
+        choose (0, 0xffff) >>= return . And,
+        choose (0, 0xffff) >>= return . Or,
+        choose (0, 0xffff) >>= return . Xor,
+        choose (0, 32) >>= return . ClrB,
+        choose (0, 32) >>= return . SetB,
+        choose (0, 32) >>= return . InvB,
+        choose (-32, 32) >>= return . Shift,
+        choose (-32, 32) >>= return . Rot]
+
+safeDiv :: (Integral a, Bounded a) => a -> a -> a
+safeDiv d 0 = maxBound
+safeDiv d n = div d n
+
+safeMod :: (Integral a) => a -> a -> a
+safeMod d 0 = 0
+safeMod d n = mod d n
+
+safeQuot :: (Integral a, Bounded a) => a -> a -> a
+safeQuot d 0 = maxBound
+safeQuot d n = quot d n
+
+safeRem :: (Integral a) => a -> a -> a
+safeRem d 0 = 0
+safeRem d n = rem d n
+
+fromUFunc :: (Integral a, Bounded a, Bits a) => UFunc -> a -> a
+fromUFunc (Add   i) x = x + (fromInteger i)
+fromUFunc (Mul   i) x = x * (fromInteger i)
+fromUFunc (Sub   i) x = x - (fromInteger i)
+fromUFunc (SubR  i) x = (fromInteger i) - x
+fromUFunc (Div   i) x = safeDiv  x (fromInteger i)
+fromUFunc (Mod   i) x = safeMod  x (fromInteger i)
+fromUFunc (Quot  i) x = safeQuot x (fromInteger i)
+fromUFunc (Rem   i) x = safeRem  x (fromInteger i)
+fromUFunc (DivR  i) x = safeDiv  (fromInteger i) x
+fromUFunc (ModR  i) x = safeMod  (fromInteger i) x
+fromUFunc (QuotR i) x = safeQuot (fromInteger i) x
+fromUFunc (RemR  i) x = safeRem  (fromInteger i) x
+fromUFunc  Neg      x = negate x
+fromUFunc  Abs      x = abs x
+fromUFunc  Inv      x = complement x
+fromUFunc (And   i) x = x .&. (fromInteger i)
+fromUFunc (Or    i) x = x .|. (fromInteger i)
+fromUFunc (Xor   i) x = xor x (fromInteger i)
+fromUFunc (ClrB  n) x = clearBit x n
+fromUFunc (SetB  n) x = setBit x n
+fromUFunc (InvB  n) x = complementBit x n
+fromUFunc (Shift n) x = shift x n
+fromUFunc (Rot   n) x = rotate x n
+
+type TestWord16 = OddWord Word32 (One (Zero (Zero (Zero (Zero ())))))
+
+verifyTestWord16 :: [UFunc] -> Bool
+verifyTestWord16 us =
+    let refFn = foldr (.) id $ map fromUFunc us :: Word16 -> Word16
+        tstFn = foldr (.) id $ map fromUFunc us :: TestWord16 -> TestWord16
+    in toInteger (refFn 0) == toInteger (tstFn 0)
+
+main :: IO ()
+main = do
+    r <- quickCheckWithResult stdArgs {maxSuccess = 1000} verifyTestWord16
+    case r of
+        Success _ _ _ -> exitSuccess
+        _             -> exitFailure
