diff --git a/setup.py b/setup.py
index d211d35038ded12bbaf66295c333cba1ef912933..85865081f1882bc820fad88eb3d08685af84499c 100644
--- a/setup.py
+++ b/setup.py
@@ -62,13 +62,13 @@ def which(name, flags=os.X_OK):  # Taken from twisted
 sys.path += glob.glob("*.egg")
 
 try:
-    import nacl.nacl
+    import nacl._lib
 except ImportError:
     # installing - there is no cffi yet
     ext_modules = []
 else:
     # building bdist - cffi is here!
-    ext_modules = [nacl.nacl.ffi.verifier.get_extension()]
+    ext_modules = [nacl._lib.ffi.verifier.get_extension()]
 
 
 def use_system():
@@ -210,6 +210,7 @@ setup(
     package_dir={"": "src"},
     packages=[
         "nacl",
+        "nacl._lib",
         "nacl.c",
     ],
 
diff --git a/src/nacl/c/lib/__init__.py b/src/nacl/_lib/__init__.py
similarity index 98%
rename from src/nacl/c/lib/__init__.py
rename to src/nacl/_lib/__init__.py
index 31505cc9cfe5270c15efe6338ffb360a3c6dac4c..a54eb05744dee3033dc8458514f10802dc9637c0 100644
--- a/src/nacl/c/lib/__init__.py
+++ b/src/nacl/_lib/__init__.py
@@ -52,7 +52,7 @@ lib = ffi.verify(
     libraries=["sodium"],
 
     # Our ext_package is nacl so look for it
-    ext_package="nacl.c.lib",
+    ext_package="nacl.c._lib",
 )
 
 
diff --git a/src/nacl/c/lib/crypto_box.h b/src/nacl/_lib/crypto_box.h
similarity index 70%
rename from src/nacl/c/lib/crypto_box.h
rename to src/nacl/_lib/crypto_box.h
index 271bb7dbac123b32a1813c67f09bac741c898b71..e7d59f76386f5e6fda65332418d35e9f80ff6f21 100644
--- a/src/nacl/c/lib/crypto_box.h
+++ b/src/nacl/_lib/crypto_box.h
@@ -15,10 +15,10 @@
 
 size_t crypto_box_secretkeybytes();
 size_t crypto_box_publickeybytes();
-
 size_t crypto_box_zerobytes();
 size_t crypto_box_boxzerobytes();
 size_t crypto_box_noncebytes();
+size_t crypto_box_beforenmbytes();
 
 
 int crypto_box_keypair(unsigned char *pk, unsigned char *sk);
@@ -30,3 +30,14 @@ int crypto_box(unsigned char *c,        const unsigned char *m,
 int crypto_box_open(unsigned char *m,        const unsigned char *c,
                     unsigned long long clen, const unsigned char *n,
               const unsigned char *pk,       const unsigned char *sk);
+
+int crypto_box_beforenm(unsigned char *k, const unsigned char *pk,
+                  const unsigned char *sk);
+
+int crypto_box_afternm(unsigned char *c,        const unsigned char *m,
+                       unsigned long long mlen, const unsigned char *n,
+                 const unsigned char *k);
+
+int crypto_box_open_afternm(unsigned char *m,        const unsigned char *c,
+                            unsigned long long clen, const unsigned char *n,
+                      const unsigned char *k);
diff --git a/src/nacl/_lib/crypto_scalarmult.h b/src/nacl/_lib/crypto_scalarmult.h
new file mode 100644
index 0000000000000000000000000000000000000000..dee5e84928e2f2271df849d898f5a2d4bc4ab138
--- /dev/null
+++ b/src/nacl/_lib/crypto_scalarmult.h
@@ -0,0 +1,19 @@
+/* Copyright 2013 Donald Stufft and individual contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+size_t crypto_scalarmult_bytes();
+size_t crypto_scalarmult_scalarbytes();
+
+int crypto_scalarmult_base(unsigned char *q, const unsigned char *n);
diff --git a/src/nacl/c/__init__.py b/src/nacl/c/__init__.py
index 09b02c6189107402d5c19123b7fbddcb0e7d48ee..e9ef7f97121c25b062b83db3b13489d1df465a09 100644
--- a/src/nacl/c/__init__.py
+++ b/src/nacl/c/__init__.py
@@ -13,9 +13,33 @@
 # limitations under the License.
 from __future__ import absolute_import, division, print_function
 
-from nacl.c.crypto_box import crypto_box_keypair
+from nacl.c.crypto_box import (
+    crypto_box_SECRETKEYBYTES, crypto_box_PUBLICKEYBYTES,
+    crypto_box_NONCEBYTES, crypto_box_ZEROBYTES, crypto_box_BOXZEROBYTES,
+    crypto_box_BEFORENMBYTES, crypto_box_keypair, crypto_box, crypto_box_open,
+    crypto_box_beforenm, crypto_box_afternm, crypto_box_open_afternm,
+)
+from nacl.c.crypto_scalarmult import (
+    crypto_scalarmult_BYTES, crypto_scalarmult_SCALARBYTES,
+    crypto_scalarmult_base,
+)
 
 
 __all__ = [
+    "crypto_box_SECRETKEYBYTES",
+    "crypto_box_PUBLICKEYBYTES",
+    "crypto_box_NONCEBYTES",
+    "crypto_box_ZEROBYTES",
+    "crypto_box_BOXZEROBYTES",
+    "crypto_box_BEFORENMBYTES",
     "crypto_box_keypair",
+    "crypto_box",
+    "crypto_box_open",
+    "crypto_box_beforenm",
+    "crypto_box_afternm",
+    "crypto_box_open_afternm",
+
+    "crypto_scalarmult_BYTES",
+    "crypto_scalarmult_SCALARBYTES",
+    "crypto_scalarmult_base",
 ]
diff --git a/src/nacl/c/_lib.py b/src/nacl/c/_lib.py
deleted file mode 100644
index a82ed815116433bb40a8309a25eb05a5f2544209..0000000000000000000000000000000000000000
--- a/src/nacl/c/_lib.py
+++ /dev/null
@@ -1,175 +0,0 @@
-# Copyright 2013 Donald Stufft and individual contributors
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from __future__ import absolute_import
-from __future__ import division
-
-import functools
-
-# We need to patch cffi before importing it
-from nacl import _cffi_fix
-
-import cffi.verifier
-
-from cffi import FFI
-
-
-__all__ = ["ffi", "lib"]
-
-
-ffi = FFI()
-ffi.cdef(
-    # Secret Key Encryption
-    """
-        static const int crypto_secretbox_KEYBYTES;
-        static const int crypto_secretbox_NONCEBYTES;
-        static const int crypto_secretbox_ZEROBYTES;
-        static const int crypto_secretbox_BOXZEROBYTES;
-
-        int crypto_secretbox(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *k);
-        int crypto_secretbox_open(unsigned char *m, const unsigned char *c, unsigned long long clen, const unsigned char *n, const unsigned char *k);
-    """
-
-    # Public Key Encryption - Signatures
-    """
-        static const int crypto_sign_PUBLICKEYBYTES;
-        static const int crypto_sign_SECRETKEYBYTES;
-        static const int crypto_sign_BYTES;
-
-        int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, unsigned char *seed);
-        int crypto_sign(unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen, const unsigned char *sk);
-        int crypto_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk);
-    """
-
-    # Public Key Encryption
-    """
-        static const int crypto_box_PUBLICKEYBYTES;
-        static const int crypto_box_SECRETKEYBYTES;
-        static const int crypto_box_BEFORENMBYTES;
-        static const int crypto_box_NONCEBYTES;
-        static const int crypto_box_ZEROBYTES;
-        static const int crypto_box_BOXZEROBYTES;
-
-        int crypto_box_keypair(unsigned char *pk, unsigned char *sk);
-        int crypto_box_afternm(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *k);
-        int crypto_box_open_afternm(unsigned char *m, const unsigned char *c, unsigned long long clen, const unsigned char *n, const unsigned char *k);
-        int crypto_box_beforenm(unsigned char *k, const unsigned char *pk, const unsigned char *sk);
-    """
-
-    # Hashing
-    """
-        static const int crypto_hash_BYTES;
-        static const int crypto_hash_sha256_BYTES;
-        static const int crypto_hash_sha512_BYTES;
-
-        int crypto_hash(unsigned char *out, const unsigned char *in, unsigned long long inlen);
-        int crypto_hash_sha256(unsigned char *out, const unsigned char *in, unsigned long long inlen);
-        int crypto_hash_sha512(unsigned char *out, const unsigned char *in, unsigned long long inlen);
-    """
-
-    # Secure Random
-    """
-        void randombytes(unsigned char * const buf, const unsigned long long buf_len);
-    """
-
-    # Low Level - Scalar Multiplication
-    """
-        int crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n);
-    """
-)
-
-
-ffi.verifier = cffi.verifier.Verifier(ffi,
-    "#include <sodium.h>",
-
-    # We need to link to the sodium library
-    libraries=["sodium"],
-
-    # Our ext_package is nacl so look for it
-    ext_package="nacl",
-)
-
-
-# This works around a bug in PyPy where CFFI exposed functions do not have a
-# __name__ attribute. See https://bugs.pypy.org/issue1452
-def wraps(wrapped):
-    def inner(func):
-        if hasattr(wrapped, "__name__"):
-            return functools.wraps(wrapped)(func)
-        else:
-            return func
-    return inner
-
-
-# A lot of the functions in nacl return 0 for success and a negative integer
-# for failure. This is inconvenient in Python as 0 is a falsey value while
-# negative integers are truthy. This wrapper has them return True/False as
-# you'd expect in Python
-def wrap_nacl_function(func):
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        ret = func(*args, **kwargs)
-        return ret == 0
-    return wrapper
-
-
-class Library(object):
-
-    wrap = [
-        "crypto_secretbox",
-        "crypto_secretbox_open",
-
-        "crypto_sign_seed_keypair",
-        "crypto_sign",
-        "crypto_sign_open",
-
-        "crypto_box_keypair",
-        "crypto_box_afternm",
-        "crypto_box_open_afternm",
-        "crypto_box_beforenm",
-
-        "crypto_hash",
-        "crypto_hash_sha256",
-        "crypto_hash_sha512",
-
-        "crypto_scalarmult_curve25519_base",
-    ]
-
-    def __init__(self, ffi):
-        self._ffi = ffi
-        self._initalized = False
-
-        # This prevents the compile_module() from being called, the module
-        # should have been compiled by setup.py
-        def _compile_module(*args, **kwargs):
-            raise RuntimeError("Cannot compile module during runtime")
-        self._ffi.verifier.compile_module = _compile_module
-
-    def __getattr__(self, name):
-        if not self._initalized:
-            self._lib = self._ffi.verifier.load_library()
-
-        # redirect attribute access to the underlying lib
-        attr = getattr(self._lib, name)
-
-        # If this is a function that we're wrapping do the actual wrapping
-        if name in self.wrap:
-            attr = wrap_nacl_function(attr)
-
-        # Go ahead and assign the returned value to this class so we don't
-        # need to do this lookup again
-        setattr(self, name, attr)
-
-        return attr
-
-lib = Library(ffi)
diff --git a/src/nacl/c/crypto_box.py b/src/nacl/c/crypto_box.py
index 3a47a0dc40cb51ff6af689237796e95532becfec..57ba5ad2f97eaab67da5fcc24a23d4704e6a19e4 100644
--- a/src/nacl/c/crypto_box.py
+++ b/src/nacl/c/crypto_box.py
@@ -13,29 +13,37 @@
 # limitations under the License.
 from __future__ import absolute_import, division, print_function
 
-from nacl.c import lib
+from nacl import _lib as lib
 from nacl.exceptions import CryptoError
 
 
 __all__ = ["crypto_box_keypair", "crypto_box"]
 
 
+crypto_box_SECRETKEYBYTES = lib.crypto_box_secretkeybytes()
+crypto_box_PUBLICKEYBYTES = lib.crypto_box_publickeybytes()
+crypto_box_NONCEBYTES = lib.crypto_box_noncebytes()
+crypto_box_ZEROBYTES = lib.crypto_box_zerobytes()
+crypto_box_BOXZEROBYTES = lib.crypto_box_boxzerobytes()
+crypto_box_BEFORENMBYTES = lib.crypto_box_beforenmbytes()
+
+
 def crypto_box_keypair():
     """
     Returns a randomly generated secret and public key.
 
     :rtype: (bytes(secret_key), bytes(public_key))
     """
-    sk_size = lib.crypto_box_secretkeybytes()
-    pk_size = lib.crypto_box_publickeybytes()
-
-    sk = lib.ffi.new("unsigned char[]", sk_size)
-    pk = lib.ffi.new("unsigned char[]", pk_size)
+    sk = lib.ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES)
+    pk = lib.ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES)
 
     if lib.crypto_box_keypair(pk, sk) != 0:
         raise CryptoError("An error occurred trying to generate the keypair")
 
-    return (lib.ffi.buffer(sk, sk_size)[:], lib.ffi.buffer(pk, pk_size)[:])
+    return (
+        lib.ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:],
+        lib.ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:],
+    )
 
 
 def crypto_box(sk, pk, message, nonce):
@@ -49,28 +57,22 @@ def crypto_box(sk, pk, message, nonce):
     :param nonce: bytes
     :rtype: bytes
     """
-    sk_size = lib.crypto_box_secretkeybytes()
-    pk_size = lib.crypto_box_publickeybytes()
-    n_size = lib.crypto_box_noncebytes()
-    zero_bytes = lib.crypto_box_zerobytes()
-    box_zeros = lib.crypto_box_boxzerobytes()
-
-    if len(sk) != sk_size:
+    if len(sk) != crypto_box_SECRETKEYBYTES:
         raise ValueError("Invalid secret key")
 
-    if len(pk) != pk_size:
+    if len(pk) != crypto_box_PUBLICKEYBYTES:
         raise ValueError("Invalid public key")
 
-    if len(nonce) != n_size:
+    if len(nonce) != crypto_box_NONCEBYTES:
         raise ValueError("Invalid nonce size")
 
-    padded = (b"\x00" * zero_bytes) + message
+    padded = (b"\x00" * crypto_box_ZEROBYTES) + message
     ciphertext = lib.ffi.new("unsigned char[]", len(padded))
 
-    if lib.crypto_box(ciphertext, message, len(message), nonce, pk, sk) != 0:
+    if lib.crypto_box(ciphertext, padded, len(padded), nonce, pk, sk) != 0:
         raise CryptoError("An error occurred trying to encrypt the message")
 
-    return lib.ffi.buffer(ciphertext, len(padded))[box_zeros:]
+    return lib.ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:]
 
 
 def crypto_box_open(sk, pk, ciphertext, nonce):
@@ -84,26 +86,94 @@ def crypto_box_open(sk, pk, ciphertext, nonce):
     :param nonce: bytes
     :rtype: bytes
     """
-    sk_size = lib.crypto_box_secretkeybytes()
-    pk_size = lib.crypto_box_publickeybytes()
-    n_size = lib.crypto_box_noncebytes()
-    box_zeros = lib.crypto_box_boxzerobytes()
-    zero_bytes = lib.crypto_box_zerobytes()
-
-    if len(sk) != sk_size:
+    if len(sk) != crypto_box_SECRETKEYBYTES:
         raise ValueError("Invalid secret key")
 
-    if len(pk) != pk_size:
+    if len(pk) != crypto_box_PUBLICKEYBYTES:
         raise ValueError("Invalid public key")
 
-    if len(nonce) != n_size:
+    if len(nonce) != crypto_box_NONCEBYTES:
         raise ValueError("Invalid nonce size")
 
-    padded = (b"\x00" * box_zeros) + ciphertext
+    padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext
+    plaintext = lib.ffi.new("unsigned char[]", len(padded))
+
+    if lib.crypto_box_open(plaintext, padded, len(padded), nonce, pk, sk) != 0:
+        raise CryptoError("An error occurred trying to decrypt the message")
+
+    return lib.ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
+
+
+def crypto_box_beforenm(sk, pk):
+    """
+    Computes and returns the shared key for the secret key ``sk`` and the
+    public key ``pk``. This can be used to speed up operations where the same
+    set of keys is going to be used multiple times.
+
+    :param sk: bytes
+    :param pk: bytes
+    :rtype: bytes
+    """
+    if len(sk) != crypto_box_SECRETKEYBYTES:
+        raise ValueError("Invalid secret key")
+
+    if len(pk) != crypto_box_PUBLICKEYBYTES:
+        raise ValueError("Invalid public key")
+
+    k = lib.ffi.new("unsigned char[]", crypto_box_BEFORENMBYTES)
+
+    if lib.crypto_box_beforenm(k, pk, sk) != 0:
+        raise CryptoError("An error occurred computing the shared key.")
+
+    return lib.ffi.buffer(k, crypto_box_BEFORENMBYTES)[:]
+
+
+def crypto_box_afternm(k, message, nonce):
+    """
+    Encrypts and returns the message ``message`` using the shared key ``k`` and
+    the nonce ``nonce``.
+
+    :param k: bytes
+    :param message: bytes
+    :param nonce: bytes
+    :rtype: bytes
+    """
+    if len(k) != crypto_box_BEFORENMBYTES:
+        raise ValueError("Invalid shared key")
+
+    if len(nonce) != crypto_box_NONCEBYTES:
+        raise ValueError("Invalid nonce")
+
+    padded = b"\x00" * crypto_box_ZEROBYTES + message
+    ciphertext = lib.ffi.new("unsigned char[]", len(padded))
+
+    if lib.crypto_box_afternm(ciphertext, padded, len(padded), nonce, k) != 0:
+        raise CryptoError("An error occurred trying to encrypt the message")
+
+    return lib.ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:]
+
+
+def crypto_box_open_afternm(k, ciphertext, nonce):
+    """
+    Decrypts and returns the encrypted message ``ciphertext``, using the shared
+    key ``k`` and the nonce ``nonce``.
+
+    :param k: bytes
+    :param ciphertext: bytes
+    :param nonce: bytes
+    :rtype: bytes
+    """
+    if len(k) != crypto_box_BEFORENMBYTES:
+        raise ValueError("Invalid shared key")
+
+    if len(nonce) != crypto_box_NONCEBYTES:
+        raise ValueError("Invalid nonce")
+
+    padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext
     plaintext = lib.ffi.new("unsigned char[]", len(padded))
 
-    if lib.crypto_box_open(
-            plaintext, ciphertext, len(ciphertext), nonce, pk, sk):
+    if lib.crypto_box_open_afternm(
+            plaintext, padded, len(padded), nonce, k) != 0:
         raise CryptoError("An error occurred trying to decrypt the message")
 
-    return lib.ffi.buffer(plaintext, len(padded))[zero_bytes:]
+    return lib.ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
diff --git a/src/nacl/c/crypto_scalarmult.py b/src/nacl/c/crypto_scalarmult.py
new file mode 100644
index 0000000000000000000000000000000000000000..910552ba4af784084f2b9a5be4f84a0b2ea00c62
--- /dev/null
+++ b/src/nacl/c/crypto_scalarmult.py
@@ -0,0 +1,38 @@
+# Copyright 2013 Donald Stufft and individual contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from __future__ import absolute_import, division, print_function
+
+from nacl import _lib as lib
+from nacl.exceptions import CryptoError
+
+
+crypto_scalarmult_BYTES = lib.crypto_scalarmult_bytes()
+crypto_scalarmult_SCALARBYTES = lib.crypto_scalarmult_scalarbytes()
+
+
+def crypto_scalarmult_base(n):
+    """
+    Computes and returns the scalar product of a standard group element and an
+    integer ``n``.
+
+    :param n: bytes
+    :rtype: bytes
+    """
+    q = lib.ffi.new("unsigned char[]", crypto_scalarmult_BYTES)
+
+    if lib.crypto_scalarmult_base(q, n) != 0:
+        raise CryptoError(
+            "An error occurred while computing the scalar product")
+
+    return lib.ffi.buffer(q, crypto_scalarmult_SCALARBYTES)[:]
diff --git a/src/nacl/public.py b/src/nacl/public.py
index 33d88d8e88f9515e20b7e1d695393e5f128140c5..eb083116abbd32de1fd3440e52dc0807bd90ca2a 100644
--- a/src/nacl/public.py
+++ b/src/nacl/public.py
@@ -14,10 +14,11 @@
 from __future__ import absolute_import
 from __future__ import division
 
-from . import encoding
-from .c import _lib as nacl
-from .exceptions import CryptoError
-from .utils import EncryptedMessage, StringFixer, random
+import nacl.c
+import nacl.c.crypto_box
+
+from nacl import encoding
+from nacl.utils import EncryptedMessage, StringFixer, random
 
 
 class PublicKey(encoding.Encodable, StringFixer, object):
@@ -31,7 +32,7 @@ class PublicKey(encoding.Encodable, StringFixer, object):
     :cvar SIZE: The size that the public key is required to be
     """
 
-    SIZE = nacl.lib.crypto_box_PUBLICKEYBYTES
+    SIZE = nacl.c.crypto_box_PUBLICKEYBYTES
 
     def __init__(self, public_key, encoder=encoding.RawEncoder):
         self._public_key = encoder.decode(public_key)
@@ -59,7 +60,7 @@ class PrivateKey(encoding.Encodable, StringFixer, object):
     :cvar SIZE: The size that the private key is required to be
     """
 
-    SIZE = nacl.lib.crypto_box_SECRETKEYBYTES
+    SIZE = nacl.c.crypto_box_SECRETKEYBYTES
 
     def __init__(self, private_key, encoder=encoding.RawEncoder):
         # Decode the secret_key
@@ -70,15 +71,10 @@ class PrivateKey(encoding.Encodable, StringFixer, object):
             raise ValueError(
                 "The secret key must be exactly %d bytes long" % self.SIZE)
 
-        pk = nacl.ffi.new("unsigned char[]", PublicKey.SIZE)
-
-        if not nacl.lib.crypto_scalarmult_curve25519_base(pk, private_key):
-            raise CryptoError("Failed to generate a key pair")
-
-        _pkey = nacl.ffi.buffer(pk, nacl.lib.crypto_box_PUBLICKEYBYTES)[:]
+        raw_public_key = nacl.c.crypto_scalarmult_base(private_key)
 
         self._private_key = private_key
-        self.public_key = PublicKey(_pkey)
+        self.public_key = PublicKey(raw_public_key)
 
     def __bytes__(self):
         return self._private_key
@@ -113,21 +109,14 @@ class Box(encoding.Encodable, StringFixer, object):
     :cvar NONCE_SIZE: The size that the nonce is required to be.
     """
 
-    NONCE_SIZE = nacl.lib.crypto_box_NONCEBYTES
+    NONCE_SIZE = nacl.c.crypto_box_NONCEBYTES
 
     def __init__(self, private_key, public_key):
         if private_key and public_key:
-            _shared_key_size = nacl.lib.crypto_box_BEFORENMBYTES
-            _shared_key = nacl.ffi.new("unsigned char[]", _shared_key_size)
-
-            if not nacl.lib.crypto_box_beforenm(
-                        _shared_key,
-                        public_key.encode(encoder=encoding.RawEncoder),
-                        private_key.encode(encoder=encoding.RawEncoder),
-                    ):
-                raise CryptoError("Failed to derive shared key")
-
-            self._shared_key = nacl.ffi.buffer(_shared_key, _shared_key_size)[:]
+            self._shared_key = nacl.c.crypto_box_beforenm(
+                private_key.encode(encoder=encoding.RawEncoder),
+                public_key.encode(encoder=encoding.RawEncoder),
+            )
         else:
             self._shared_key = None
 
@@ -162,20 +151,11 @@ class Box(encoding.Encodable, StringFixer, object):
             raise ValueError("The nonce must be exactly %s bytes long" %
                              self.NONCE_SIZE)
 
-        padded = b"\x00" * nacl.lib.crypto_box_ZEROBYTES + plaintext
-        ciphertext = nacl.ffi.new("unsigned char[]", len(padded))
-
-        if not nacl.lib.crypto_box_afternm(
-                    ciphertext,
-                    padded,
-                    len(padded),
-                    nonce,
-                    self._shared_key,
-                ):
-            raise CryptoError("Encryption failed")
-
-        box_zeros = nacl.lib.crypto_box_BOXZEROBYTES
-        ciphertext = nacl.ffi.buffer(ciphertext, len(padded))[box_zeros:]
+        ciphertext = nacl.c.crypto_box_afternm(
+            self._shared_key,
+            plaintext,
+            nonce,
+        )
 
         encoded_nonce = encoder.encode(nonce)
         encoded_ciphertext = encoder.encode(ciphertext)
@@ -209,20 +189,10 @@ class Box(encoding.Encodable, StringFixer, object):
             raise ValueError("The nonce must be exactly %s bytes long" %
                              self.NONCE_SIZE)
 
-        padded = b"\x00" * nacl.lib.crypto_box_BOXZEROBYTES + ciphertext
-        plaintext = nacl.ffi.new("unsigned char[]", len(padded))
-
-        if not nacl.lib.crypto_box_open_afternm(
-                    plaintext,
-                    padded,
-                    len(padded),
-                    nonce,
-                    self._shared_key,
-                ):
-            raise CryptoError(
-                        "Decryption failed. Ciphertext failed verification")
-
-        box_zeros = nacl.lib.crypto_box_ZEROBYTES
-        plaintext = nacl.ffi.buffer(plaintext, len(padded))[box_zeros:]
+        plaintext = nacl.c.crypto_box_open_afternm(
+            self._shared_key,
+            ciphertext,
+            nonce,
+        )
 
         return plaintext