diff --git a/README.rst b/README.rst
index 8e16300984d9af785d6aaaf0b1123258578e98e9..1eb40b5921fd63956aac78bd714bd7d74b5cef50 100644
--- a/README.rst
+++ b/README.rst
@@ -37,3 +37,14 @@ Features
 * Secret-key encryption
 * Public-key encryption
 * HMAC (coming soon)
+
+
+Changes
+-------
+
+* 0.3.0: the low-level API (`nacl.c.*`) has been changed to match the
+  upstream NaCl C/C++ conventions (as well as those of other NaCl bindings).
+  The order of arguments and return values has changed significantly. If you
+  have code which calls these functions (e.g. `nacl.c.crypto_box_keypair()`),
+  you must review the new docstrings and update your code to match the new
+  conventions.
diff --git a/src/nacl/__init__.py b/src/nacl/__init__.py
index 95d307725fea6e1f174a56a19dcb8bf8db08fc27..a6f7b59e8f84ee8177d09031ecba8d58ddf8cd3a 100644
--- a/src/nacl/__init__.py
+++ b/src/nacl/__init__.py
@@ -24,7 +24,7 @@ __summary__ = ("Python binding to the Networking and Cryptography (NaCl) "
                "library")
 __uri__ = "https://github.com/pyca/pynacl/"
 
-__version__ = "0.2.3"
+__version__ = "0.3.0"
 
 __author__ = "Donald Stufft"
 __email__ = "donald@stufft.io"
diff --git a/src/nacl/c/crypto_box.py b/src/nacl/c/crypto_box.py
index 069ff5c0a3cda089c3bc3ec1041bdce729d39296..c63fd0e10360dc8d1818df7ce1982d5314366a9a 100644
--- a/src/nacl/c/crypto_box.py
+++ b/src/nacl/c/crypto_box.py
@@ -30,41 +30,41 @@ crypto_box_BEFORENMBYTES = lib.crypto_box_beforenmbytes()
 
 def crypto_box_keypair():
     """
-    Returns a randomly generated secret and public key.
+    Returns a randomly generated public and secret key.
 
-    :rtype: (bytes(secret_key), bytes(public_key))
+    :rtype: (bytes(public_key), bytes(secret_key))
     """
-    sk = lib.ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES)
     pk = lib.ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES)
+    sk = lib.ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES)
 
     if lib.crypto_box_keypair(pk, sk) != 0:
         raise CryptoError("An error occurred trying to generate the keypair")
 
     return (
-        lib.ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:],
         lib.ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:],
+        lib.ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:],
     )
 
 
-def crypto_box(sk, pk, message, nonce):
+def crypto_box(message, nonce, pk, sk):
     """
     Encrypts and returns a message ``message`` using the secret key ``sk``,
     public key ``pk``, and the nonce ``nonce``.
 
-    :param sk: bytes
-    :param pk: bytes
     :param message: bytes
     :param nonce: bytes
+    :param pk: bytes
+    :param sk: bytes
     :rtype: bytes
     """
-    if len(sk) != crypto_box_SECRETKEYBYTES:
-        raise ValueError("Invalid secret key")
+    if len(nonce) != crypto_box_NONCEBYTES:
+        raise ValueError("Invalid nonce size")
 
     if len(pk) != crypto_box_PUBLICKEYBYTES:
         raise ValueError("Invalid public key")
 
-    if len(nonce) != crypto_box_NONCEBYTES:
-        raise ValueError("Invalid nonce size")
+    if len(sk) != crypto_box_SECRETKEYBYTES:
+        raise ValueError("Invalid secret key")
 
     padded = (b"\x00" * crypto_box_ZEROBYTES) + message
     ciphertext = lib.ffi.new("unsigned char[]", len(padded))
@@ -75,25 +75,25 @@ def crypto_box(sk, pk, message, nonce):
     return lib.ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:]
 
 
-def crypto_box_open(sk, pk, ciphertext, nonce):
+def crypto_box_open(ciphertext, nonce, pk, sk):
     """
     Decrypts and returns an encrypted message ``ciphertext``, using the secret
     key ``sk``, public key ``pk``, and the nonce ``nonce``.
 
-    :param sk: bytes
-    :param pk: bytes
     :param ciphertext: bytes
     :param nonce: bytes
+    :param pk: bytes
+    :param sk: bytes
     :rtype: bytes
     """
-    if len(sk) != crypto_box_SECRETKEYBYTES:
-        raise ValueError("Invalid secret key")
+    if len(nonce) != crypto_box_NONCEBYTES:
+        raise ValueError("Invalid nonce size")
 
     if len(pk) != crypto_box_PUBLICKEYBYTES:
         raise ValueError("Invalid public key")
 
-    if len(nonce) != crypto_box_NONCEBYTES:
-        raise ValueError("Invalid nonce size")
+    if len(sk) != crypto_box_SECRETKEYBYTES:
+        raise ValueError("Invalid secret key")
 
     padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext
     plaintext = lib.ffi.new("unsigned char[]", len(padded))
@@ -104,22 +104,22 @@ def crypto_box_open(sk, pk, ciphertext, nonce):
     return lib.ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
 
 
-def crypto_box_beforenm(sk, pk):
+def crypto_box_beforenm(pk, sk):
     """
-    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
+    Computes and returns the shared key for the public key ``pk`` and the
+    secret key ``sk``. 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
+    :param sk: 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")
 
+    if len(sk) != crypto_box_SECRETKEYBYTES:
+        raise ValueError("Invalid secret key")
+
     k = lib.ffi.new("unsigned char[]", crypto_box_BEFORENMBYTES)
 
     if lib.crypto_box_beforenm(k, pk, sk) != 0:
@@ -128,22 +128,22 @@ def crypto_box_beforenm(sk, pk):
     return lib.ffi.buffer(k, crypto_box_BEFORENMBYTES)[:]
 
 
-def crypto_box_afternm(k, message, nonce):
+def crypto_box_afternm(message, nonce, k):
     """
     Encrypts and returns the message ``message`` using the shared key ``k`` and
     the nonce ``nonce``.
 
-    :param k: bytes
     :param message: bytes
     :param nonce: bytes
+    :param k: bytes
     :rtype: bytes
     """
-    if len(k) != crypto_box_BEFORENMBYTES:
-        raise ValueError("Invalid shared key")
-
     if len(nonce) != crypto_box_NONCEBYTES:
         raise ValueError("Invalid nonce")
 
+    if len(k) != crypto_box_BEFORENMBYTES:
+        raise ValueError("Invalid shared key")
+
     padded = b"\x00" * crypto_box_ZEROBYTES + message
     ciphertext = lib.ffi.new("unsigned char[]", len(padded))
 
@@ -153,22 +153,22 @@ def crypto_box_afternm(k, message, nonce):
     return lib.ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:]
 
 
-def crypto_box_open_afternm(k, ciphertext, nonce):
+def crypto_box_open_afternm(ciphertext, nonce, k):
     """
     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
+    :param k: bytes
     :rtype: bytes
     """
-    if len(k) != crypto_box_BEFORENMBYTES:
-        raise ValueError("Invalid shared key")
-
     if len(nonce) != crypto_box_NONCEBYTES:
         raise ValueError("Invalid nonce")
 
+    if len(k) != crypto_box_BEFORENMBYTES:
+        raise ValueError("Invalid shared key")
+
     padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext
     plaintext = lib.ffi.new("unsigned char[]", len(padded))
 
diff --git a/src/nacl/c/crypto_secretbox.py b/src/nacl/c/crypto_secretbox.py
index 94e6a66a35c2c0e78986571f4f070c4417de91af..e07caa9c4586e860bb18929d14f0548684d58f64 100644
--- a/src/nacl/c/crypto_secretbox.py
+++ b/src/nacl/c/crypto_secretbox.py
@@ -23,14 +23,14 @@ crypto_secretbox_ZEROBYTES = lib.crypto_secretbox_zerobytes()
 crypto_secretbox_BOXZEROBYTES = lib.crypto_secretbox_boxzerobytes()
 
 
-def crypto_secretbox(key, message, nonce):
+def crypto_secretbox(message, nonce, key):
     """
     Encrypts and returns the message ``message`` with the secret ``key`` and
     the nonce ``nonce``.
 
-    :param key: bytes
     :param message: bytes
     :param nonce: bytes
+    :param key: bytes
     :rtype: bytes
     """
     if len(key) != crypto_secretbox_KEYBYTES:
@@ -49,14 +49,14 @@ def crypto_secretbox(key, message, nonce):
     return ciphertext[crypto_secretbox_BOXZEROBYTES:]
 
 
-def crypto_secretbox_open(key, ciphertext, nonce):
+def crypto_secretbox_open(ciphertext, nonce, key):
     """
     Decrypt and returns the encrypted message ``ciphertext`` with the secret
     ``key`` and the nonce ``nonce``.
 
-    :param key: bytes
     :param ciphertext: bytes
     :param nonce: bytes
+    :param key: bytes
     :rtype: bytes
     """
     if len(key) != crypto_secretbox_KEYBYTES:
diff --git a/src/nacl/c/crypto_sign.py b/src/nacl/c/crypto_sign.py
index 7286de062889e0743feecb5e4c730af91df49397..ba6a881e6d8d3b89538e4693b44274568b1ee5e9 100644
--- a/src/nacl/c/crypto_sign.py
+++ b/src/nacl/c/crypto_sign.py
@@ -26,51 +26,51 @@ crypto_sign_SECRETKEYBYTES = lib.crypto_sign_secretkeybytes()
 
 def crypto_sign_keypair():
     """
-    Returns a randomly generated secret key and public key.
+    Returns a randomly generated public key and secret key.
 
-    :rtype: (bytes(secret_key), bytes(public_key))
+    :rtype: (bytes(public_key), bytes(secret_key))
     """
-    sk = lib.ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES)
     pk = lib.ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES)
+    sk = lib.ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES)
 
     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)[:],
+        lib.ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:],
     )
 
 
 def crypto_sign_seed_keypair(seed):
     """
-    Computes and returns the secret key and public key using the seed ``seed``.
+    Computes and returns the public key and secret key using the seed ``seed``.
 
     :param seed: bytes
-    :rtype: (bytes(secret_key), bytes(public_key))
+    :rtype: (bytes(public_key), bytes(secret_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)
+    sk = lib.ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES)
 
     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)[:],
+        lib.ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:],
     )
 
 
-def crypto_sign(sk, message):
+def crypto_sign(message, sk):
     """
     Signs the message ``message`` using the secret key ``sk`` and returns the
     signed message.
 
-    :param sk: bytes
     :param message: bytes
+    :param sk: bytes
     :rtype: bytes
     """
     signed = lib.ffi.new("unsigned char[]", len(message) + crypto_sign_BYTES)
@@ -82,13 +82,13 @@ def crypto_sign(sk, message):
     return lib.ffi.buffer(signed, signed_len[0])[:]
 
 
-def crypto_sign_open(pk, signed):
+def crypto_sign_open(signed, pk):
     """
     Verifies the signature of the signed message ``signed`` using the public
     key ``pkg`` and returns the unsigned message.
 
-    :param pk: bytes
     :param signed: bytes
+    :param pk: bytes
     :rtype: bytes
     """
     message = lib.ffi.new("unsigned char[]", len(signed))
diff --git a/src/nacl/public.py b/src/nacl/public.py
index 25cbb2122c522a16e9f403e63705a2843738fa36..32bda571f636098b52b1f183fc01e0fd10de6403 100644
--- a/src/nacl/public.py
+++ b/src/nacl/public.py
@@ -114,8 +114,8 @@ class Box(encoding.Encodable, StringFixer, object):
     def __init__(self, private_key, public_key):
         if private_key and public_key:
             self._shared_key = nacl.c.crypto_box_beforenm(
-                private_key.encode(encoder=encoding.RawEncoder),
                 public_key.encode(encoder=encoding.RawEncoder),
+                private_key.encode(encoder=encoding.RawEncoder),
             )
         else:
             self._shared_key = None
@@ -152,9 +152,9 @@ class Box(encoding.Encodable, StringFixer, object):
                              self.NONCE_SIZE)
 
         ciphertext = nacl.c.crypto_box_afternm(
-            self._shared_key,
             plaintext,
             nonce,
+            self._shared_key,
         )
 
         encoded_nonce = encoder.encode(nonce)
@@ -190,9 +190,9 @@ class Box(encoding.Encodable, StringFixer, object):
                              self.NONCE_SIZE)
 
         plaintext = nacl.c.crypto_box_open_afternm(
-            self._shared_key,
             ciphertext,
             nonce,
+            self._shared_key,
         )
 
         return plaintext
diff --git a/src/nacl/secret.py b/src/nacl/secret.py
index 50107d5070296b15eccf3d6d07b5ec2c5604205f..6ae85876133c5cc1d47144d336ea0d211fc388b5 100644
--- a/src/nacl/secret.py
+++ b/src/nacl/secret.py
@@ -78,7 +78,7 @@ class SecretBox(encoding.Encodable, StringFixer, object):
                 "The nonce must be exactly %s bytes long" % self.NONCE_SIZE,
             )
 
-        ciphertext = nacl.c.crypto_secretbox(self._key, plaintext, nonce)
+        ciphertext = nacl.c.crypto_secretbox(plaintext, nonce, self._key)
 
         encoded_nonce = encoder.encode(nonce)
         encoded_ciphertext = encoder.encode(ciphertext)
@@ -113,6 +113,6 @@ class SecretBox(encoding.Encodable, StringFixer, object):
                 "The nonce must be exactly %s bytes long" % self.NONCE_SIZE,
             )
 
-        plaintext = nacl.c.crypto_secretbox_open(self._key, ciphertext, nonce)
+        plaintext = nacl.c.crypto_secretbox_open(ciphertext, nonce, self._key)
 
         return plaintext
diff --git a/src/nacl/signing.py b/src/nacl/signing.py
index ddc027b43146e62c187868ebc9725d1205ec6304..e9f05deec3bc32057a722997244c45ac6b0488f6 100644
--- a/src/nacl/signing.py
+++ b/src/nacl/signing.py
@@ -96,7 +96,7 @@ class VerifyKey(encoding.Encodable, StringFixer, object):
         # Decode the signed message
         smessage = encoder.decode(smessage)
 
-        return nacl.c.crypto_sign_open(self._key, smessage)
+        return nacl.c.crypto_sign_open(smessage, self._key)
 
 
 class SigningKey(encoding.Encodable, StringFixer, object):
@@ -129,7 +129,7 @@ class SigningKey(encoding.Encodable, StringFixer, object):
                 nacl.c.crypto_sign_SEEDBYTES
             )
 
-        secret_key, public_key = nacl.c.crypto_sign_seed_keypair(seed)
+        public_key, secret_key = nacl.c.crypto_sign_seed_keypair(seed)
 
         self._seed = seed
         self._signing_key = secret_key
@@ -158,7 +158,7 @@ class SigningKey(encoding.Encodable, StringFixer, object):
         :param encoder: A class that is used to encode the signed message.
         :rtype: :class:`~nacl.signing.SignedMessage`
         """
-        raw_signed = nacl.c.crypto_sign(self._signing_key, message)
+        raw_signed = nacl.c.crypto_sign(message, self._signing_key)
 
         signature = encoder.encode(raw_signed[:nacl.c.crypto_sign_BYTES])
         message = encoder.encode(raw_signed[nacl.c.crypto_sign_BYTES:])
diff --git a/tests/test_raw.py b/tests/test_raw.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3a0ed4f75c6fa2591cc87d6c21d87872fe5b7d4
--- /dev/null
+++ b/tests/test_raw.py
@@ -0,0 +1,113 @@
+# 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 binascii import hexlify
+from nacl import c
+import hashlib
+
+
+def tohex(b):
+    return hexlify(b).decode("ascii")
+
+
+def test_hash():
+    msg = b"message"
+    h1 = c.crypto_hash(msg)
+    assert len(h1) == c.crypto_hash_BYTES
+    assert tohex(h1) == ("f8daf57a3347cc4d6b9d575b31fe6077"
+                         "e2cb487f60a96233c08cb479dbf31538"
+                         "cc915ec6d48bdbaa96ddc1a16db4f4f9"
+                         "6f37276cfcb3510b8246241770d5952c")
+    assert tohex(h1) == hashlib.sha512(msg).hexdigest()
+
+    h2 = c.crypto_hash_sha512(msg)
+    assert len(h2) == c.crypto_hash_sha512_BYTES
+    assert tohex(h2) == tohex(h1)
+
+    h3 = c.crypto_hash_sha256(msg)
+    assert len(h3) == c.crypto_hash_sha256_BYTES
+    assert tohex(h3) == ("ab530a13e45914982b79f9b7e3fba994"
+                         "cfd1f3fb22f71cea1afbf02b460c6d1d")
+    assert tohex(h3) == hashlib.sha256(msg).hexdigest()
+
+
+def test_secretbox():
+    key = b"\x00" * c.crypto_secretbox_KEYBYTES
+    msg = b"message"
+    nonce = b"\x01" * c.crypto_secretbox_NONCEBYTES
+    ct = c.crypto_secretbox(msg, nonce, key)
+    assert len(ct) == len(msg) + c.crypto_secretbox_BOXZEROBYTES
+    assert tohex(ct) == "3ae84dfb89728737bd6e2c8cacbaf8af3d34cc1666533a"
+    msg2 = c.crypto_secretbox_open(ct, nonce, key)
+    assert msg2 == msg
+
+
+def test_box():
+    A_pubkey, A_secretkey = c.crypto_box_keypair()
+    assert len(A_secretkey) == c.crypto_box_SECRETKEYBYTES
+    assert len(A_pubkey) == c.crypto_box_PUBLICKEYBYTES
+    B_pubkey, B_secretkey = c.crypto_box_keypair()
+
+    k1 = c.crypto_box_beforenm(B_pubkey, A_secretkey)
+    assert len(k1) == c.crypto_box_BEFORENMBYTES
+    k2 = c.crypto_box_beforenm(A_pubkey, B_secretkey)
+    assert tohex(k1) == tohex(k2)
+
+    message = b"message"
+    nonce = b"\x01" * c.crypto_box_NONCEBYTES
+    ct1 = c.crypto_box_afternm(message, nonce, k1)
+    assert len(ct1) == len(message) + c.crypto_box_BOXZEROBYTES
+
+    ct2 = c.crypto_box(message, nonce, B_pubkey, A_secretkey)
+    assert tohex(ct2) == tohex(ct1)
+
+    m1 = c.crypto_box_open(ct1, nonce, A_pubkey, B_secretkey)
+    assert m1 == message
+
+    m2 = c.crypto_box_open_afternm(ct1, nonce, k1)
+    assert m2 == message
+
+
+def test_sign():
+    seed = b"\x00" * c.crypto_sign_SEEDBYTES
+    pubkey, secretkey = c.crypto_sign_seed_keypair(seed)
+    assert len(pubkey) == c.crypto_sign_PUBLICKEYBYTES
+    assert len(secretkey) == c.crypto_sign_SECRETKEYBYTES
+
+    pubkey, secretkey = c.crypto_sign_keypair()
+    assert len(pubkey) == c.crypto_sign_PUBLICKEYBYTES
+    assert len(secretkey) == c.crypto_sign_SECRETKEYBYTES
+
+    msg = b"message"
+    sigmsg = c.crypto_sign(msg, secretkey)
+    assert len(sigmsg) == len(msg) + c.crypto_sign_BYTES
+
+    msg2 = c.crypto_sign_open(sigmsg, pubkey)
+    assert msg2 == msg
+
+
+def secret_scalar():
+    pubkey, secretkey = c.crypto_box_keypair()
+    assert len(secretkey) == c.crypto_box_SECRETKEYBYTES
+    assert c.crypto_box_SECRETKEYBYTES == c.crypto_scalarmult_BYTES
+    return secretkey, pubkey
+
+
+def test_scalarmult():
+    x, xpub = secret_scalar()
+    assert len(x) == 32
+    y, ypub = secret_scalar()
+
+    bx = c.crypto_scalarmult_base(x)
+    assert tohex(bx) == tohex(xpub)