diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2014, Bryan O'Sullivan
+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 AND CONTRIBUTORS
+"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
+OWNER OR CONTRIBUTORS 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/README.markdown b/README.markdown
new file mode 100644
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,14 @@
+This Haskell package provides a
+[QuickCheck](http://hackage.haskell.org/package/QuickCheck) data
+generator and shrink functions for testing software that uses Unicode
+data.
+
+The default
+[`Arbitrary`](http://hackage.haskell.org/package/QuickCheck/docs/Test-QuickCheck.html#t:Arbitrary)
+instance for the `Char` type *intentionally* generates *only* ASCII
+values.  This can lead to a false sense of security in cases where
+Unicode compliance is required, as encodings that span multiple bytes
+or code units will simply not be exercised at all.
+
+This module deliberately avoids using the `text` and `bytestring`
+packages to avoid pulling in extra dependencies.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Test/QuickCheck/Unicode.hs b/Test/QuickCheck/Unicode.hs
new file mode 100644
--- /dev/null
+++ b/Test/QuickCheck/Unicode.hs
@@ -0,0 +1,153 @@
+{-# LANGUAGE FlexibleInstances #-}
+
+-- |
+-- Module      : Test.QuickCheck.Unicode
+-- Copyright   : (c) 2014 Bryan O'Sullivan
+-- License     : BSD-style
+-- Maintainer  : bos@serpentine.com
+-- Stability   : stable
+-- Portability : portable
+--
+-- QuickCheck Generator and shrink functions for testing software that
+-- uses Unicode data.
+--
+-- The default 'Arbitrary' instance for the 'Char' type intentionally
+-- generates only ASCII values.  This can lead to a false sense of
+-- security in cases where Unicode compliance is required, as
+-- encodings that span multiple bytes or code units will simply not be
+-- exercised at all.
+--
+-- This module deliberately avoids using the @text@ and @bytestring@
+-- packages to avoid pulling in extra dependencies.
+
+module Test.QuickCheck.Unicode
+    (
+    -- * Newtype wrapper for convenience
+      Unicode(fromUnicode)
+
+    -- * Generators
+    , char
+    , string
+
+    -- ** Helpers
+    , list
+
+    -- ** Basic generators
+    , planes
+    , ascii
+    , plane0
+    , plane1
+    , plane2
+    , plane14
+
+    -- * Predicates
+    , reserved
+
+    -- * Shrinking functions
+    , shrinkChar
+    ) where
+
+import Control.Applicative ((<$>))
+import Data.Bits ((.&.))
+import Data.Char (chr, ord)
+import Test.QuickCheck hiding ((.&.))
+
+-- | A wrapper for 'Char' and 'String', for which the 'Arbitrary'
+-- instance generates full-Unicode characters.
+newtype Unicode a = Unicode { fromUnicode :: a }
+                  deriving (Eq, Ord, Show, Read)
+
+instance Arbitrary (Unicode Char) where
+    arbitrary = Unicode <$> char
+    shrink    = map Unicode . shrinkChar . fromUnicode
+
+instance Arbitrary (Unicode [Char]) where
+    arbitrary = Unicode <$> string
+    shrink    = map Unicode . shrinkList shrinkChar . fromUnicode
+
+-- | Generate a Unicode code point.  This has a much larger range than
+-- the default 'Arbitrary' instance for 'Char'.
+char :: Gen Char
+char = chr `fmap` excluding reserved (frequency planes)
+
+-- | Generate a list of Unicode code points.
+string :: Gen String
+string = list char
+
+-- | Generate a list of values.
+list :: Gen a -> Gen [a]
+list gen =
+  sized $ \n ->
+    do k <- choose (0,n)
+       vectorOf k gen
+
+-- | Shrink a Unicode code point.
+shrinkChar :: Char -> [Char]
+shrinkChar = map chr . filter (not . reserved) . shrinkIntegral . ord
+
+excluding :: (a -> Bool) -> Gen a -> Gen a
+excluding bad gen = loop
+  where
+    loop = do
+      x <- gen
+      if bad x
+        then loop
+        else return x
+
+-- | Indicate whether a code point is reserved.
+reserved :: Int -> Bool
+reserved = anyOf [(<0), (>0x10FFFF), lowSurrogate, highSurrogate, nonCharacter]
+  where
+    anyOf fs xs     = or (map ($ xs) fs)
+    lowSurrogate c  = c >= 0xDC00 && c <= 0xDFFF
+    highSurrogate c = c >= 0xD800 && c <= 0xDBFF
+    nonCharacter c  = masked == 0xFFFE || masked == 0xFFFF
+      where masked  = c .&. 0xFFFF
+
+-- | A weighted list of generators that favours ASCII characters,
+-- followed by planes 0 and 1.
+planes :: [(Int, Gen Int)]
+planes = [(60, ascii),
+          (14, plane0),
+          (14, plane1),
+          (6,  plane2),
+          (6,  plane14)]
+
+-- ASCII.
+ascii :: Gen Int
+ascii = choose (0,0x7F)
+
+-- | Basic Multilingual Plane.
+plane0 :: Gen Int
+plane0 = choose (0xF0, 0xFFFF)
+
+-- | Supplementary Multilingual Plane.
+plane1 :: Gen Int
+plane1 = oneof [ choose (0x10000, 0x10FFF)
+               , choose (0x11000, 0x11FFF)
+               , choose (0x12000, 0x12FFF)
+               , choose (0x13000, 0x13FFF)
+               , choose (0x1D000, 0x1DFFF)
+               , choose (0x1F000, 0x1FFFF)
+               ]
+
+-- | Supplementary Ideographic Plane.
+plane2 :: Gen Int
+plane2 = oneof [ choose (0x20000, 0x20FFF)
+               , choose (0x21000, 0x21FFF)
+               , choose (0x22000, 0x22FFF)
+               , choose (0x23000, 0x23FFF)
+               , choose (0x24000, 0x24FFF)
+               , choose (0x25000, 0x25FFF)
+               , choose (0x26000, 0x26FFF)
+               , choose (0x27000, 0x27FFF)
+               , choose (0x28000, 0x28FFF)
+               , choose (0x29000, 0x29FFF)
+               , choose (0x2A000, 0x2AFFF)
+               , choose (0x2B000, 0x2BFFF)
+               , choose (0x2F000, 0x2FFFF)
+               ]
+
+-- | Supplementary Special-Purpose Plane.
+plane14 :: Gen Int
+plane14 = choose (0xE0000, 0xE0FFF)
diff --git a/quickcheck-unicode.cabal b/quickcheck-unicode.cabal
new file mode 100644
--- /dev/null
+++ b/quickcheck-unicode.cabal
@@ -0,0 +1,36 @@
+name:           quickcheck-unicode
+version:        1.0.0.0
+homepage:       https://github.com/bos/quickcheck-unicode
+bug-reports:    https://github.com/bos/quickcheck-unicode/issues
+synopsis:       Generator and shrink functions for testing
+                Unicode-related software.
+description:    Generator and shrink functions for testing
+                Unicode-related software.
+license:        BSD3
+license-file:   LICENSE
+author:         Bryan O'Sullivan <bos@serpentine.com>
+maintainer:     Bryan O'Sullivan <bos@serpentine.com>
+copyright:      2014 Bryan O'Sullivan
+category:       Testing, Text
+build-type:     Simple
+cabal-version:  >= 1.8
+extra-source-files:
+  README.markdown
+
+library
+  exposed-modules:
+    Test.QuickCheck.Unicode
+
+  build-depends:
+    base       >= 4.2 && < 5,
+    QuickCheck >= 2.6
+
+  ghc-options: -Wall -fwarn-tabs
+
+source-repository head
+  type:     git
+  location: https://github.com/bos/quickcheck-unicode
+
+source-repository head
+  type:     mercurial
+  location: https://bitbucket.org/bos/quickcheck-unicode
