diff --git a/bert.cabal b/bert.cabal
--- a/bert.cabal
+++ b/bert.cabal
@@ -1,6 +1,6 @@
 cabal-version: >= 1.16
 name:          bert
-version:       1.2.1
+version:       1.2.1.1
 build-type:    Simple
 license:       BSD3
 license-file:  LICENSE
@@ -55,7 +55,7 @@
     network,
     bert,
     base,
-    smallcheck,
+    smallcheck >= 1.1,
     containers,
     bytestring,
     binary
diff --git a/src/Data/BERT/Term.hs b/src/Data/BERT/Term.hs
--- a/src/Data/BERT/Term.hs
+++ b/src/Data/BERT/Term.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE OverlappingInstances, TypeSynonymInstances, FlexibleInstances #-}
 -- | Define BERT terms their binary encoding & decoding and a typeclass
 -- for converting Haskell values to BERT terms and back.
--- 
+--
 -- We define a number of convenient instances for 'BERT'. Users will
 -- probably want to define their own instances for composite types.
 module Data.BERT.Term
@@ -12,6 +12,7 @@
 import Control.Applicative
 import Data.Bits
 import Data.Char
+import Data.Int
 import Data.Binary
 import Data.Binary.Put
 import Data.Binary.Get
@@ -46,7 +47,7 @@
 
 instance Show Term where
   -- Provide an erlang-compatible 'show' for terms. The results of
-  -- this should be parseable as erlang source. 
+  -- this should be parseable as erlang source.
   show = showTerm
 
 instance Read Term where
@@ -65,14 +66,14 @@
 compose NilTerm = ListTerm []
 compose (BoolTerm True) = ct "true" []
 compose (BoolTerm False) = ct "false" []
-compose (DictionaryTerm kvs) = 
+compose (DictionaryTerm kvs) =
   ct "dict" [ListTerm $ map (\(k, v) -> TupleTerm [k, v]) kvs]
 compose (TimeTerm t) =
   ct "time" [IntTerm mS, IntTerm s, IntTerm uS]
   where
     (mS, s, uS) = decomposeTime t
-compose (RegexTerm s os) = 
-  ct "regex" [BytelistTerm (C.pack s), 
+compose (RegexTerm s os) =
+  ct "regex" [BytelistTerm (C.pack s),
               TupleTerm [ListTerm $ map AtomTerm os]]
 compose _ = error "invalid composite term"
 
@@ -82,15 +83,15 @@
 showTerm (AtomTerm a@(x:xs))
   | isAsciiLower x = a
   | otherwise      = "'" ++ a ++ "'"
-showTerm (TupleTerm ts) = 
+showTerm (TupleTerm ts) =
   "{" ++ intercalate ", " (map showTerm ts) ++ "}"
 showTerm (BytelistTerm bs) = show $ C.unpack bs
-showTerm (ListTerm ts) = 
+showTerm (ListTerm ts) =
   "[" ++ intercalate ", " (map showTerm ts) ++ "]"
 showTerm (BinaryTerm b)
-  | all (isAscii . chr . fromIntegral) (B.unpack b) = 
+  | all (isAscii . chr . fromIntegral) (B.unpack b) =
       wrap $ "\"" ++ C.unpack b ++ "\""
-  | otherwise = 
+  | otherwise =
       wrap $ intercalate ", " $ map show $ B.unpack b
   where
     wrap x = "<<" ++ x ++ ">>"
@@ -158,21 +159,21 @@
 
 instance (BERT a, BERT b, BERT c) => BERT (a, b, c) where
   showBERT (a, b, c) = TupleTerm [showBERT a, showBERT b, showBERT c]
-  readBERT (TupleTerm [a, b, c]) = 
+  readBERT (TupleTerm [a, b, c]) =
     liftM3 (,,) (readBERT a) (readBERT b) (readBERT c)
   readBERT _ = fail "Invalid tuple(3) type"
 
 instance (BERT a, BERT b, BERT c, BERT d) => BERT (a, b, c, d) where
-  showBERT (a, b, c, d) = 
+  showBERT (a, b, c, d) =
     TupleTerm [showBERT a, showBERT b, showBERT c, showBERT d]
-  readBERT (TupleTerm [a, b, c, d]) = 
+  readBERT (TupleTerm [a, b, c, d]) =
     liftM4 (,,,) (readBERT a) (readBERT b) (readBERT c) (readBERT d)
   readBERT _ = fail "Invalid tuple(4) type"
 
 instance (Ord k, BERT k, BERT v) => BERT (Map k v) where
-  showBERT m = DictionaryTerm 
+  showBERT m = DictionaryTerm
              $ map (\(k, v) -> (showBERT k, showBERT v)) (Map.toList m)
-  readBERT (DictionaryTerm kvs) = 
+  readBERT (DictionaryTerm kvs) =
     mapM (\(k, v) -> liftM2 (,) (readBERT k) (readBERT v)) kvs >>=
       return . Map.fromList
   readBERT _ = fail "Invalid map type"
@@ -181,68 +182,70 @@
 instance Binary Term where
   put term = putWord8 131 >> putTerm term
   get      = getWord8 >>= \magic ->
-               case magic of 
+               case magic of
                  131 -> getTerm
                  _   -> fail "bad magic"
 
 -- | Binary encoding of a single term (without header)
-putTerm (IntTerm value) = tag 98 >> put32i value
+putTerm :: Term -> PutM ()
+putTerm (IntTerm value) = tag 98 >> put32s value
 putTerm (FloatTerm value) =
   tag 99 >> (putL . C.pack . pad $ printf "%15.15e" value)
   where
     pad s = s ++ replicate (31 - (length s)) '\0'
 putTerm (AtomTerm value)
-  | len < 256 = tag 100 >> put16i len >> (putL $ C.pack value)
+  | len < 256 = tag 100 >> put16u len >> (putL $ C.pack value)
   | otherwise = fail "BERT atom too long (>= 256)"
   where
     len = length value
 putTerm (TupleTerm value)
-  | len < 256 = tag 104 >> put8i len  >> forM_ value putTerm
-  | otherwise = tag 105 >> put32i len >> forM_ value putTerm
+  | len < 256 = tag 104 >> put8u len  >> forM_ value putTerm
+  | otherwise = tag 105 >> put32u len >> forM_ value putTerm
   where
     len = length value
 putTerm (BytelistTerm value)
-  | len < 65536 = tag 107 >> put16i len >> putL value
+  | len < 65536 = tag 107 >> put16u len >> putL value
   | otherwise = do  -- too big: encode as a list.
       tag 108
-      put32i len
-      forM_ (B.unpack value) $ \v -> do 
+      put32u len
+      forM_ (B.unpack value) $ \v -> do
         tag 97
         putWord8 v
-  where 
+  where
     len = B.length value
 putTerm (ListTerm value)
   | len == 0 = putNil  -- this is mentioend in the BERT spec.
   | otherwise= do
       tag 108
-      put32i $ length value
+      put32u $ length value
       forM_ value putTerm
       putNil
-  where 
+  where
     len = length value
     putNil = putWord8 106
-putTerm (BinaryTerm value) = tag 109 >> (put32i $ B.length value) >> putL value
-putTerm (BigintTerm value) = tag 110 >> putBigint put8i value
-putTerm (BigbigintTerm value) = tag 111 >> putBigint put32i value
+putTerm (BinaryTerm value) = tag 109 >> (put32u $ B.length value) >> putL value
+putTerm (BigintTerm value) = tag 110 >> putBigint put8u value
+putTerm (BigbigintTerm value) = tag 111 >> putBigint put32u value
 -- All other terms are composite:
 putTerm t = putTerm . compose $ t
 
 -- | Binary decoding of a single term (without header)
+getTerm :: Get Term
 getTerm = do
-  tag <- get8i
+  tag <- get8u
   case tag of
-    97  -> IntTerm <$> get8i
-    98  -> IntTerm <$> get32i
+    97  -> IntTerm <$> get8u
+    98  -> IntTerm <$> get32s
     99  -> getL 31 >>= return . FloatTerm . read . C.unpack
-    100 -> get16i >>= getL >>= return . AtomTerm . C.unpack
-    104 -> get8i >>= getN >>= tupleTerm
-    105 -> get32i >>= getN >>= tupleTerm 
+    100 -> get16u >>= getL >>= return . AtomTerm . C.unpack
+    104 -> get8u >>= getN >>= tupleTerm
+    105 -> get32u >>= getN >>= tupleTerm
     106 -> return $ ListTerm []
-    107 -> get16i >>= getL >>= return . BytelistTerm
-    108 -> get32i >>= getN >>= return . ListTerm
-    109 -> get32i >>= getL >>= return . BinaryTerm
-    110 -> getBigint get8i >>= return . BigintTerm . fromIntegral
-    111 -> getBigint get32i >>= return . BigintTerm . fromIntegral
+    107 -> get16u >>= getL >>= return . BytelistTerm
+    108 -> get32u >>= getN >>= return . ListTerm
+    109 -> get32u >>= getL >>= return . BinaryTerm
+    110 -> getBigint get8u >>= return . BigintTerm . fromIntegral
+    111 -> getBigint get32u >>= return . BigintTerm . fromIntegral
   where
     getN n = replicateM n getTerm
     -- First try & decode composite terms.
@@ -253,8 +256,8 @@
       where
         toTuple (TupleTerm [k, v]) = return $ (k, v)
         toTuple _ = fail "invalid dictionary"
-    tupleTerm [AtomTerm "bert", AtomTerm "time", 
-               IntTerm mS, IntTerm s, IntTerm uS] = 
+    tupleTerm [AtomTerm "bert", AtomTerm "time",
+               IntTerm mS, IntTerm s, IntTerm uS] =
       return $ TimeTerm $ composeTime (mS, s, uS)
     tupleTerm [AtomTerm "bert", AtomTerm "regex",
                BytelistTerm s, ListTerm os] =
@@ -270,8 +273,8 @@
 putBigint putter value = do
   putter len  -- TODO: verify size?
   if value < 0
-    then put8i 1
-    else put8i 0
+    then put8u 1
+    else put8u 0
   putL $ B.pack $ map (fromIntegral . digit) [0..len-1]
   where
     value'    = abs value
@@ -280,10 +283,10 @@
 
 getBigint getter = do
   len   <- fromIntegral <$> getter
-  sign  <- get8i
+  sign  <- get8u
   bytes <- getL len
-  multiplier <- 
-    case sign of 
+  multiplier <-
+    case sign of
       0 -> return 1
       1 -> return (-1)
       _ -> fail "Invalid sign byte"
@@ -291,17 +294,31 @@
          $ foldl (\s (n, d) -> s + d*(256^n)) 0
          $ zip [0..len-1] (map fromIntegral $ B.unpack bytes)
 
-put8i :: (Integral a) => a -> Put
-put8i = putWord8 . fromIntegral
-put16i :: (Integral a) => a -> Put
-put16i = putWord16be . fromIntegral
-put32i :: (Integral a) => a -> Put
-put32i = putWord32be . fromIntegral
+-- Note about put32s/get32s:
+--
+-- When dealing with 32-bit signed ints, we first convert between Int and
+-- Int32, and only then cast to Word32. This is to ensure put and get are
+-- as close to inverse as possible. Coercing word types to and from
+-- integer types using 'fromIntegral' is guaranteed to preserve
+-- representation (see Notes in "Data.Int").
+--
+-- For an example of what can go wrong, see
+-- https://github.com/feuerbach/bert/issues/6
+
+put8u :: (Integral a) => a -> Put
+put8u = putWord8 . fromIntegral
+put16u :: (Integral a) => a -> Put
+put16u = putWord16be . fromIntegral
+put32u :: (Integral a) => a -> Put
+put32u = putWord32be . fromIntegral
+put32s :: (Integral a) => a -> Put
+put32s = putWord32be . (fromIntegral :: Int32 -> Word32) . fromIntegral
 putL = putLazyByteString
 
-get8i  = fromIntegral <$> getWord8
-get16i = fromIntegral <$> getWord16be
-get32i = fromIntegral <$> getWord32be
+get8u  = fromIntegral <$> getWord8
+get16u = fromIntegral <$> getWord16be
+get32u = fromIntegral <$> getWord32be
+get32s = fromIntegral . (fromIntegral :: Word32 -> Int32) <$> getWord32be
 getL :: (Integral a) => a -> Get ByteString
 getL = getLazyByteString . fromIntegral
 
diff --git a/src/Network/BERT.hs b/src/Network/BERT.hs
--- a/src/Network/BERT.hs
+++ b/src/Network/BERT.hs
@@ -1,4 +1,4 @@
--- | BERT-RPC client (<http://bert-rpc.org/>). See "Network.BERT.Transport" and "Network.BERT.RPC" for more details.
+-- | BERT-RPC client (<http://bert-rpc.org/>). See "Network.BERT.Client" and "Network.BERT.Server" for more details.
 module Network.BERT
   ( module Network.BERT.Transport
   , module Network.BERT.Client
diff --git a/tests/test.hs b/tests/test.hs
--- a/tests/test.hs
+++ b/tests/test.hs
@@ -7,6 +7,7 @@
 import Data.Map (Map)
 import qualified Data.ByteString.Lazy as L
 import qualified Data.Map as Map
+import Text.Printf
 
 import Control.Concurrent
 import Control.Concurrent.Async
@@ -29,11 +30,21 @@
 instance (Serial m a, Ord a, Serial m b) => Serial m (Map a b) where
   series = liftM Map.fromList series
 
-type T a = a -> Bool
+type T a = a -> Either String String
+
+eqVerbose :: (Eq a, Show a) => a -> a -> Either String String
+eqVerbose x y =
+  let sx = show x
+      sy = show y
+  in
+  if x == y
+    then Right $ printf "%s == %s" sx sy
+    else Left  $ printf "%s /= %s" sx sy
+
 -- value -> Term -> encoded -> Term -> value
-t a = Right a == (readBERT . decode . encode . showBERT) a
+t a = Right a `eqVerbose` (readBERT . decode . encode . showBERT) a
 -- value -> Term -> Packet -> encoded -> Packet -> Term -> value
-p a = Right a == (readBERT . fromPacket . decode . encode . Packet . showBERT) a
+p a = Right a `eqVerbose` (readBERT . fromPacket . decode . encode . Packet . showBERT) a
 
 main = defaultMain $ localOption (SmallCheckDepth 4) $
   testGroup "Tests"
