diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,2 @@
+0.1.0
+
diff --git a/perfect-vector-shuffle.cabal b/perfect-vector-shuffle.cabal
new file mode 100644
--- /dev/null
+++ b/perfect-vector-shuffle.cabal
@@ -0,0 +1,96 @@
+cabal-version:      2.2
+category:           Random, Vector
+build-type:         Simple
+
+name:               perfect-vector-shuffle
+synopsis:           Library for performing vector shuffles
+version:            0.1.0
+
+author:             Callan McGill
+maintainer:         callan.mcgill@gmail.com
+homepage:           https://github.com/Boarders/perfect-vector-shuffle
+bug-reports:        https://github.com/Boarders/perfect-vector-shuffle/issues
+copyright:          2019
+license:            BSD-3-Clause
+description:
+    .
+    This package contains functions for performing shuffles on mutable and
+    immutable vectors. The shuffles are uniform at random amongst all
+    permuations.
+    .
+    For an example of how to use it:
+    .
+    @
+        module Example where
+        .
+        import Data.Vector
+        import Immutable.Shuffle
+        .
+        myVector :: Vector Int
+        myVector = fromList [1..10]
+        .
+        shuffleMyVector :: IO (Vector Int)
+        shuffleMyVector = shuffleM myVector
+    @
+    .
+    This gives the following:
+    .
+    @
+    > shuffleMyVector
+    [1,10,4,7,2,3,5,9,8,6]
+    > shuffleMyVector
+    [7,4,2,10,9,8,6,5,1,3]
+    @
+
+extra-source-files: CHANGELOG.md
+
+source-repository head
+  type:     git
+  location: https://github.com/Boarders/perfect-vector-shuffle
+
+
+Library
+
+  hs-source-dirs:   src
+
+  ghc-options:      -Wall
+
+  build-depends:    base        ^>= 4.12.0.0
+                  , MonadRandom >= 0.5.1.1  && < 0.6
+                  , primitive   >= 0.6.4.0  && < 0.7
+                  , random      ^>= 1.1
+                  , vector      >= 0.12.0   && < 0.13
+
+  exposed-modules:  Immutable.Shuffle
+                    Mutable.Shuffle
+
+  other-modules:
+
+  default-language: Haskell2010
+
+
+Test-Suite testsuite
+
+  type:             exitcode-stdio-1.0
+
+  main-is:          Test.hs
+
+  hs-source-dirs:   test
+
+  ghc-options:      -Wall
+                    -Wincomplete-patterns
+
+  build-depends:    perfect-vector-shuffle ^>= 0.1.0
+                  , base                   ^>= 4.12.0.0
+                  , QuickCheck             ^>= 2.12.6.1
+                  , random                 ^>= 1.1
+                  , tasty                  >= 1.2    && < 1.3
+                  , tasty-quickcheck       ^>= 0.10
+                  , vector                 >= 0.12.0 && < 0.13
+                  , quickcheck-instances   >= 0.3.19 && < 0.4
+
+
+  other-modules:
+                    Immutable.Test
+
+  default-language: Haskell2010
diff --git a/src/Immutable/Shuffle.hs b/src/Immutable/Shuffle.hs
new file mode 100644
--- /dev/null
+++ b/src/Immutable/Shuffle.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- | This module provides functions to perform shuffles on immutable vectors.
+-- The shuffling is uniform amongst all permuations and performs the minimal
+-- number of transpositions.
+
+module Immutable.Shuffle where
+
+import           Control.Monad.Primitive
+import           Control.Monad.Random    (MonadRandom (..))
+import           Control.Monad.ST        (runST)
+import           Data.Vector
+import qualified Mutable.Shuffle         as MS
+import           Prelude                 hiding (length)
+import           System.Random           (RandomGen (..))
+
+
+-- |
+-- Perform a shuffle on an immutable vector with a given random generator returning a shuffled vector and a new generator.
+shuffle :: forall a g. RandomGen g => Vector a -> g -> (Vector a, g)
+shuffle v g
+  | length v <= 1 = (v, snd . next $ g)
+  | otherwise     =
+      runST $
+        do
+          mutV   <- thaw v
+          newGen <- MS.shuffle mutV g
+          immutV <- unsafeFreeze mutV
+          pure (immutV, newGen)
+
+
+-- |
+-- Perform a shuffle on an input immutable vector in a monad which has a source of randomness.
+shuffleM :: forall m a . (MonadRandom m, PrimMonad m) => Vector a -> m (Vector a)
+shuffleM v
+  | length v <= 1 = pure v
+  | otherwise =
+      do
+        mutV   <- thaw v
+        MS.shuffleM mutV
+        unsafeFreeze mutV
diff --git a/src/Mutable/Shuffle.hs b/src/Mutable/Shuffle.hs
new file mode 100644
--- /dev/null
+++ b/src/Mutable/Shuffle.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- | This module provides functions to perform shuffles on mutable vectors.
+-- The shuffling is uniform amongst all permuations and uses the minimal
+-- number of transpositions.
+
+module Mutable.Shuffle where
+
+import           Control.Monad.Primitive
+import           Control.Monad.Random    (MonadRandom (..))
+import           Data.Vector.Mutable
+import           Prelude                 hiding (length, tail)
+import           System.Random           (RandomGen)
+import qualified System.Random           as SR
+
+-- |
+-- Perform a shuffle on a mutable vector with a given random generator, returning a new random generator.
+shuffle
+  :: forall m a g
+  . ( PrimMonad m
+    , RandomGen g
+    )
+  => MVector (PrimState m) a -> g -> m g
+shuffle mutV gen = go mutV gen (length mutV - 1)
+  where
+    go :: MVector (PrimState m) a -> g -> Int -> m g
+    go _ g 0   =  pure g
+    go v g maxInd =
+      do
+        let (ind, newGen) :: (Int, g) = SR.randomR (0, maxInd) g
+        swap v 0 ind
+        go (tail v) newGen (maxInd - 1)
+
+
+-- |
+-- Perform a shuffle on a mutable vector in a monad which has a source of randomness.
+shuffleM
+  :: forall m a
+  . ( PrimMonad m
+    , MonadRandom m
+    )
+  => MVector (PrimState m) a  -> m ()
+shuffleM mutV = go mutV (length mutV - 1)
+  where
+    go :: MVector (PrimState m) a -> Int -> m ()
+    go _ 0   =  pure ()
+    go v maxInd =
+      do
+        ind <-  getRandomR (0, maxInd)
+        swap v 0 ind
+        go (tail v) (maxInd - 1)
+
+
diff --git a/test/Immutable/Test.hs b/test/Immutable/Test.hs
new file mode 100644
--- /dev/null
+++ b/test/Immutable/Test.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
+module Immutable.Test
+  ( testSuite
+  ) where
+
+import           Data.List                        (sort)
+import           Data.Vector                      (Vector)
+import qualified Data.Vector                      as V
+import           Immutable.Shuffle
+import           System.Random
+import           Test.QuickCheck.Instances.Vector ()
+import           Test.QuickCheck.Monadic
+import           Test.Tasty
+import           Test.Tasty.QuickCheck            as QC hiding (shuffle)
+
+
+testSuite :: TestTree
+testSuite = testGroup ""
+  [ localOption (QuickCheckTests 1000) shuffleTestSuite
+  , localOption (QuickCheckTests 1000) shuffleMTestSuite
+  ]
+
+
+shuffleTestSuite :: TestTree
+shuffleTestSuite = testGroup "shuffle"
+  [ QC.testProperty
+      "Shuffling preserves length and elements"
+      (monadicIO . isPermutation @Int)]
+
+
+shuffleMTestSuite :: TestTree
+shuffleMTestSuite = testGroup "shuffleM"
+  [ QC.testProperty
+      "Shuffling preserves length and elements"
+      (monadicIO . isPermutationM @Int)]
+
+
+isPermutation :: forall a . (Ord a , Show a, Arbitrary a) => Vector a -> PropertyM IO Property
+isPermutation v =
+  do
+    gen <- run $ getStdGen
+    let v' = fst $ shuffle v gen
+    let ls  = V.toList v
+    let ls' = V.toList v'
+    pure $ (sort ls) === (sort ls')
+
+
+isPermutationM :: forall a . (Ord a , Show a, Arbitrary a) => Vector a -> PropertyM IO Property
+isPermutationM v =
+  do
+    v'  <- run $ shuffleM v
+    let ls  = V.toList v
+    let ls' = V.toList v'
+    pure $ (sort ls) === (sort ls')
+
diff --git a/test/Test.hs b/test/Test.hs
new file mode 100644
--- /dev/null
+++ b/test/Test.hs
@@ -0,0 +1,15 @@
+module Main where
+
+import qualified Immutable.Test as Immutable
+import           Test.Tasty
+
+
+main :: IO ()
+main = defaultMain  testSuite
+
+
+testSuite :: TestTree
+testSuite = testGroup "Perfect Vector Sort"
+  [ Immutable.testSuite
+  ]
+
