diff --git a/pycuda/curandom.py b/pycuda/curandom.py
index 324e5ce..0fa9d27 100644
--- a/pycuda/curandom.py
+++ b/pycuda/curandom.py
@@ -5,7 +5,14 @@ import pycuda.compiler
 import pycuda.driver as drv
 import pycuda.gpuarray as array
 
+# CURAND
+import pycuda._driver as _drv
 
+if not _drv.have_libraries_ext(): 
+    raise ImportError("PyCUDA was compiled without extensions support")
+
+direction_vector_set = _drv.direction_vector_set
+get_direction_vectors32 = _drv.get_direction_vectors32
 
 
 # {{{ MD5-based random number generation
@@ -425,6 +432,15 @@ class _RandomNumberGeneratorBase(object):
 
 # {{{ XORWOW RNG
 
+def seed_getter_uniform(N):
+    result = pycuda.gpuarray.empty([N], numpy.int32)
+    value = random.randint(0, 2**31-1)
+    return result.fill(value)
+
+def seed_getter_unique(N):
+    result = numpy.random.randint(0, 2**31-1, N).astype(numpy.int32)
+    return pycuda.gpuarray.to_gpu(result)
+
 xorwow_random_source = """
 extern "C" {
 __global__ void prepare_with_seeds(curandState *s, const int n,
@@ -497,12 +513,12 @@ class XORWOWRandomNumberGenerator(_RandomNumberGeneratorBase):
 
 sobol32_random_source = """
 extern "C" {
-__global__ void prepare(curandStateSobol32 *s, const int n, unsigned int *v,
+__global__ void prepare(curandStateSobol32 *s, const int n, unsigned int **v,
     const unsigned int o) 
 {
   const int id = blockIdx.x*blockDim.x+threadIdx.x;
   if (id < n)
-    curand_init(v, o, &s[id]);
+    curand_init(v[id], o, &s[id]);
 }
 }
 """
@@ -516,11 +532,18 @@ class Sobol32RandomNumberGenerator(_RandomNumberGeneratorBase):
 
     has_box_muller = False
 
-    def __init__(self, dir_vector, offset):
+    def __init__(self, dir_vector=None, offset=0):
         super(Sobol32RandomNumberGenerator, self).__init__('curandStateSobol32',
             sobol32_random_source)
 
-        raise NotImplementedError("not working yet")
+        if dir_vector is None:
+            dir_vector = generate_direction_vectors(
+                self.block_count * self.generators_per_block)
+
+        if not (isinstance(dir_vector, pycuda.gpuarray.GPUArray)
+                and dir_vector.dtype == np.int32
+                and dir_vector.shape == (self.block_count * self.generators_per_block, 32)):
+            raise TypeError("seed must be GPUArray of integers of right length")
 
         p = self.module.get_function("prepare")
         p.prepare("PiPi", block=(self.generators_per_block, 1, 1))
diff --git a/setup.py b/setup.py
index 517f127..77a5dae 100644
--- a/setup.py
+++ b/setup.py
@@ -20,6 +20,7 @@ def get_config_schema():
         IncludeDir("CUDA", None),
 
         Switch("CUDA_ENABLE_GL", False, "Enable CUDA GL interoperability"),
+        Switch("CUDA_ENABLE_LIBRARIES", False, "Enable CUDA libraries like CURAND"),
 
         LibraryDir("CUDADRV", []),
         Libraries("CUDADRV", ["cuda"]),
@@ -245,6 +246,11 @@ def main():
         EXTRA_SOURCES.append("src/wrapper/wrap_cudagl.cpp")
         EXTRA_DEFINES["HAVE_GL"] = 1
 
+    if conf["CUDA_ENABLE_LIBRARIES"]:
+        LIBRARIES.append("curand")
+        EXTRA_SOURCES.append("src/wrapper/wrap_libraries.cpp")
+        EXTRA_DEFINES["HAVE_LIBRARIES"] = 1
+
     ver_dic = {}
     exec(compile(open("pycuda/__init__.py").read(), "pycuda/__init__.py", 'exec'), ver_dic)
 
@@ -316,7 +322,7 @@ def main():
             packages=["pycuda", "pycuda.gl", "pycuda.sparse"],
 
             install_requires=[
-                "pytools>=8",
+                "pytools>=11",
                 "py>=1.0.0b7",
                 "decorator>=3.2.0"
                 ],
diff --git a/src/cpp/cuda_libraries.hpp b/src/cpp/cuda_libraries.hpp
new file mode 100644
index 0000000..862f300
--- /dev/null
+++ b/src/cpp/cuda_libraries.hpp
@@ -0,0 +1,23 @@
+#ifndef _AFJDFJSDFSD_PYCUDA_HEADER_SEEN_CUDA_LIBRARIES_HPP
+#define _AFJDFJSDFSD_PYCUDA_HEADER_SEEN_CUDA_LIBRARIES_HPP
+
+#include <curand.h>
+
+// To wrap different libraries like CURAND
+
+#if CUDAPP_CUDA_VERSION < 3020
+#error CURAND only works with CUDA 3.2 or newer.
+#endif
+
+
+namespace pycuda { namespace curandom {
+
+  void  py_curand_get_direction_vectors32(curandDirectionVectors32_t *vectors[],
+      curandDirectionVectorSet_t set)
+// TODO: checking; cannot use CUDAPP_CALL_GUARDED because function returns CURAND enum
+  { curandGetDirectionVectors32(vectors, set); }
+
+} }
+
+#endif
+
diff --git a/src/wrapper/wrap_cudadrv.cpp b/src/wrapper/wrap_cudadrv.cpp
index ee6fac6..282ab1d 100644
--- a/src/wrapper/wrap_cudadrv.cpp
+++ b/src/wrapper/wrap_cudadrv.cpp
@@ -407,6 +407,15 @@ namespace
 
 
 
+  bool have_libraries_ext()
+  {
+#ifdef HAVE_LIBRARIES
+    return true;
+#else
+    return false;
+#endif
+  }
+
   bool have_gl_ext()
   {
 #ifdef HAVE_GL
@@ -421,6 +430,7 @@ namespace
 
 
 void pycuda_expose_tools();
+void pycuda_expose_libraries();
 void pycuda_expose_gl();
 
 
@@ -1064,9 +1074,13 @@ BOOST_PYTHON_MODULE(_driver)
   py::scope().attr("TRSF_NORMALIZED_COORDINATES") = CU_TRSF_NORMALIZED_COORDINATES;
   py::scope().attr("TR_DEFAULT") = CU_PARAM_TR_DEFAULT;
 
+  DEF_SIMPLE_FUNCTION(have_libraries_ext);
   DEF_SIMPLE_FUNCTION(have_gl_ext);
 
   pycuda_expose_tools();
+#ifdef HAVE_LIBRARIES
+  pycuda_expose_libraries();
+#endif
 #ifdef HAVE_GL
   pycuda_expose_gl();
 #endif
diff --git a/src/wrapper/wrap_libraries.cpp b/src/wrapper/wrap_libraries.cpp
new file mode 100644
index 0000000..bd96338
--- /dev/null
+++ b/src/wrapper/wrap_libraries.cpp
@@ -0,0 +1,28 @@
+#include <curand.h>
+
+#include <cuda.hpp>
+#include <cuda_libraries.hpp>
+
+// To wrap different libraries like CURAND
+
+#include "tools.hpp"
+#include "wrap_helpers.hpp"
+
+#if CUDAPP_CUDA_VERSION < 3020
+#error CURAND only works with CUDA 3.2 or newer.
+#endif
+
+using namespace pycuda;
+using namespace pycuda::curandom;
+
+void pycuda_expose_libraries()
+{
+  using py::arg;
+  using py::args;
+
+  py::enum_<curandDirectionVectorSet_t>("direction_vector_set")
+    .value("VECTOR_32", CURAND_DIRECTION_VECTORS_32_JOEKUO6)
+  ;
+  py::def("get_direction_vectors32", py_curand_get_direction_vectors32, (arg("vectors"), arg("set")));
+}
+
