diff --git a/src/nacl/_lib/crypto_sign.h b/src/nacl/_lib/crypto_sign.h
new file mode 100644
index 0000000000000000000000000000000000000000..e401567981b434bd6d112b3f34fb7c16274c2c81
--- /dev/null
+++ b/src/nacl/_lib/crypto_sign.h
@@ -0,0 +1,33 @@
+/* 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_sign_bytes();
+// size_t crypto_sign_seedbytes();
+size_t crypto_sign_publickeybytes();
+size_t crypto_sign_secretkeybytes();
+
+
+int crypto_sign_keypair(unsigned char *pk, unsigned char *sk);
+
+int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk,
+                       const 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);
diff --git a/src/nacl/c/__init__.py b/src/nacl/c/__init__.py
index 377192aec45d53e59c4f487dd37dc20ca0ee416f..eb584354fa2fdf4830e65da806d6ac0e0e69df81 100644
--- a/src/nacl/c/__init__.py
+++ b/src/nacl/c/__init__.py
@@ -28,6 +28,11 @@ from nacl.c.crypto_secretbox import (
     crypto_secretbox_ZEROBYTES, crypto_secretbox_BOXZEROBYTES,
     crypto_secretbox, crypto_secretbox_open,
 )
+from nacl.c.crypto_sign import (
+    crypto_sign_BYTES, crypto_sign_SEEDBYTES, crypto_sign_PUBLICKEYBYTES,
+    crypto_sign_SECRETKEYBYTES, crypto_sign_keypair, crypto_sign_seed_keypair,
+    crypto_sign, crypto_sign_open,
+)
 from nacl.c.randombytes import randombytes
 
 
@@ -56,5 +61,14 @@ __all__ = [
     "crypto_secretbox",
     "crypto_secretbox_open",
 
+    "crypto_sign_BYTES",
+    "crypto_sign_SEEDBYTES",
+    "crypto_sign_PUBLICKEYBYTES",
+    "crypto_sign_SECRETKEYBYTES",
+    "crypto_sign_keypair",
+    "crypto_sign_seed_keypair",
+    "crypto_sign",
+    "crypto_sign_open",
+
     "randombytes",
 ]
diff --git a/src/nacl/c/crypto_sign.py b/src/nacl/c/crypto_sign.py
new file mode 100644
index 0000000000000000000000000000000000000000..505d2658e46d5443bbddb3cd6a83f7cb02899633
--- /dev/null
+++ b/src/nacl/c/crypto_sign.py
@@ -0,0 +1,101 @@
+# 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 BadSignatureError, CryptoError
+
+
+crypto_sign_BYTES = lib.crypto_sign_bytes()
+# crypto_sign_SEEDBYTES = lib.crypto_sign_seedbytes()
+crypto_sign_SEEDBYTES = lib.crypto_sign_secretkeybytes() // 2
+crypto_sign_PUBLICKEYBYTES = lib.crypto_sign_publickeybytes()
+crypto_sign_SECRETKEYBYTES = lib.crypto_sign_secretkeybytes()
+
+
+def crypto_sign_keypair():
+    """
+    Returns a randomly generated secret key and public key.
+
+    :rtype: (bytes(secret_key), bytes(public_key))
+    """
+    sk = lib.ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES)
+    pk = lib.ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES)
+
+    if lib.crypto_sign_keypair(pk, sk) != 0:
+        raise CryptoError("An error occurred while generating keypairs")
+
+    return (
+        lib.ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:],
+        lib.ffi.buffer(pk, crypto_sign_PUBLICKEYBYTES)[:],
+    )
+
+
+def crypto_sign_seed_keypair(seed):
+    """
+    Computes and returns the secret key and public key using the seed ``seed``.
+
+    :param seed: bytes
+    :rtype: (bytes(secret_key), bytes(public_key))
+    """
+    if len(seed) != crypto_sign_SEEDBYTES:
+        raise ValueError("Invalid seed")
+
+    sk = lib.ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES)
+    pk = lib.ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES)
+
+    if lib.crypto_sign_seed_keypair(pk, sk, seed) != 0:
+        raise CryptoError("An error occured while generating keypairs")
+
+    return (
+        lib.ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:],
+        lib.ffi.buffer(pk, crypto_sign_PUBLICKEYBYTES)[:],
+    )
+
+
+def crypto_sign(sk, message):
+    """
+    Signs the message ``message`` using the secret key ``sk`` and returns the
+    signed message.
+
+    :param sk: bytes
+    :param message: bytes
+    :rtype: bytes
+    """
+    signed = lib.ffi.new("unsigned char[]", len(message) + crypto_sign_BYTES)
+    signed_len = lib.ffi.new("unsigned long long *")
+
+    if lib.crypto_sign(signed, signed_len, message, len(message), sk) != 0:
+        raise CryptoError("Failed to sign the message")
+
+    return lib.ffi.buffer(signed, signed_len[0])[:]
+
+
+def crypto_sign_open(pk, signed):
+    """
+    Verifies the signature of the signed message ``signed`` using the public
+    key ``pkg`` and returns the unsigned message.
+
+    :param pk: bytes
+    :param signed: bytes
+    :rtype: bytes
+    """
+    message = lib.ffi.new("unsigned char[]", len(signed))
+    message_len = lib.ffi.new("unsigned long long *")
+
+    if lib.crypto_sign_open(
+            message, message_len, signed, len(signed), pk) != 0:
+        raise BadSignatureError("Signature was forged or corrupt")
+
+    return lib.ffi.buffer(message, message_len[0])[:]
diff --git a/src/nacl/exceptions.py b/src/nacl/exceptions.py
index a50656b63e47faff20d4ed3d602b54a492f4ceca..ae8630f5ebb3845921a34def820b7afc642c7b5d 100644
--- a/src/nacl/exceptions.py
+++ b/src/nacl/exceptions.py
@@ -19,3 +19,9 @@ class CryptoError(Exception):
     """
     Base exception for all nacl related errors
     """
+
+
+class BadSignatureError(CryptoError):
+    """
+    Raised when the signature was forged or otherwise corrupt.
+    """
diff --git a/src/nacl/signing.py b/src/nacl/signing.py
index 5791fdd2256aa7d8a7bc16815a8e9ce8842c7497..036b4d76466a55c1ce1ea0fadec40faa5ccf44ac 100644
--- a/src/nacl/signing.py
+++ b/src/nacl/signing.py
@@ -16,18 +16,12 @@ from __future__ import division
 
 import six
 
+import nacl.c
+
 from . import encoding
-from .c import _lib as nacl
-from .exceptions import CryptoError
 from .utils import StringFixer, random
 
 
-class BadSignatureError(CryptoError):
-    """
-    Raised when the signature was forged or otherwise corrupt.
-    """
-
-
 class SignedMessage(six.binary_type):
     """
     A bytes subclass that holds a messaged that has been signed by a
@@ -69,9 +63,9 @@ class VerifyKey(encoding.Encodable, StringFixer, object):
         # Decode the key
         key = encoder.decode(key)
 
-        if len(key) != nacl.lib.crypto_sign_PUBLICKEYBYTES:
+        if len(key) != nacl.c.crypto_sign_PUBLICKEYBYTES:
             raise ValueError("The key must be exactly %s bytes long" %
-                                nacl.lib.crypto_sign_PUBLICKEYBYTES)
+                                nacl.c.crypto_sign_PUBLICKEYBYTES)
 
         self._key = key
 
@@ -100,13 +94,7 @@ class VerifyKey(encoding.Encodable, StringFixer, object):
         # Decode the signed message
         smessage = encoder.decode(smessage)
 
-        message = nacl.ffi.new("unsigned char[]", len(smessage))
-        message_len = nacl.ffi.new("unsigned long long *")
-
-        if not nacl.lib.crypto_sign_open(message, message_len, smessage, len(smessage), self._key):
-            raise BadSignatureError("Signature was forged or corrupt")
-
-        return nacl.ffi.buffer(message, message_len[0])[:]
+        return nacl.c.crypto_sign_open(self._key, smessage)
 
 
 class SigningKey(encoding.Encodable, StringFixer, object):
@@ -133,23 +121,15 @@ class SigningKey(encoding.Encodable, StringFixer, object):
         seed = encoder.decode(seed)
 
         # Verify that our seed is the proper size
-        seed_size = nacl.lib.crypto_sign_SECRETKEYBYTES // 2
-        if len(seed) != seed_size:
-            raise ValueError(
-                'The seed must be exactly %d bytes long' % (seed_size,))
-
-        pk = nacl.ffi.new("unsigned char[]", nacl.lib.crypto_sign_PUBLICKEYBYTES)
-        sk = nacl.ffi.new("unsigned char[]", nacl.lib.crypto_sign_SECRETKEYBYTES)
+        if len(seed) != nacl.c.crypto_sign_SEEDBYTES:
+            raise ValueError("The seed must be exactly %d bytes long" %
+                                nacl.c.crypto_sign_SEEDBYTES)
 
-        if not nacl.lib.crypto_sign_seed_keypair(pk, sk, seed):
-            raise CryptoError("Failed to generate a key pair")
+        secret_key, public_key = nacl.c.crypto_sign_seed_keypair(seed)
 
-        # Secret values
         self._seed = seed
-        self._signing_key = nacl.ffi.buffer(sk, nacl.lib.crypto_sign_SECRETKEYBYTES)[:]
-
-        # Public values
-        self.verify_key = VerifyKey(nacl.ffi.buffer(pk, nacl.lib.crypto_sign_PUBLICKEYBYTES)[:])
+        self._signing_key = secret_key
+        self.verify_key = VerifyKey(public_key)
 
     def __bytes__(self):
         return self._seed
@@ -161,9 +141,10 @@ class SigningKey(encoding.Encodable, StringFixer, object):
 
         :rtype: :class:`~nacl.signing.SigningKey`
         """
-        return cls(random(nacl.lib.crypto_sign_SECRETKEYBYTES // 2),
-                    encoder=encoding.RawEncoder,
-                )
+        return cls(
+            random(nacl.c.crypto_sign_SEEDBYTES),
+            encoder=encoding.RawEncoder,
+        )
 
     def sign(self, message, encoder=encoding.RawEncoder):
         """
@@ -173,16 +154,10 @@ class SigningKey(encoding.Encodable, StringFixer, object):
         :param encoder: A class that is used to encode the signed message.
         :rtype: :class:`~nacl.signing.SignedMessage`
         """
-        sm = nacl.ffi.new("unsigned char[]", len(message) + nacl.lib.crypto_sign_BYTES)
-        smlen = nacl.ffi.new("unsigned long long *")
-
-        if not nacl.lib.crypto_sign(sm, smlen, message, len(message), self._signing_key):
-            raise CryptoError("Failed to sign the message")
-
-        raw_signed = nacl.ffi.buffer(sm, smlen[0])[:]
+        raw_signed = nacl.c.crypto_sign(self._signing_key, message)
 
-        signature = encoder.encode(raw_signed[:nacl.lib.crypto_sign_BYTES])
-        message = encoder.encode(raw_signed[nacl.lib.crypto_sign_BYTES:])
+        signature = encoder.encode(raw_signed[:nacl.c.crypto_sign_BYTES])
+        message = encoder.encode(raw_signed[nacl.c.crypto_sign_BYTES:])
         signed = encoder.encode(raw_signed)
 
         return SignedMessage._from_parts(signature, message, signed)
diff --git a/tests/test_signing.py b/tests/test_signing.py
index 92ca3f043108551020a2309a0504886bf1b04e36..803f3617b006fe9aaba889ad722307d93beb16f6 100644
--- a/tests/test_signing.py
+++ b/tests/test_signing.py
@@ -21,7 +21,7 @@ import pytest
 
 import nacl.signing
 import nacl.encoding
-import nacl.nacl
+import nacl.exceptions
 
 
 def ed25519_known_answers():
@@ -86,9 +86,9 @@ class TestVerifyKey:
         # Small sanity check
         assert skey.verify_key.verify(smessage)
 
-        with pytest.raises(nacl.signing.BadSignatureError):
+        with pytest.raises(nacl.exceptions.BadSignatureError):
             skey.verify_key.verify(message, signature)
 
-        with pytest.raises(nacl.signing.BadSignatureError):
+        with pytest.raises(nacl.exceptions.BadSignatureError):
             forged = nacl.signing.SignedMessage(signature + message)
             skey.verify_key.verify(forged)