aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2014-06-23 10:41:19 -0700
committerAlex Gaynor <alex.gaynor@gmail.com>2014-06-23 10:41:19 -0700
commiteced452177a827a2cf508c2bd6c3573aedfc8bce (patch)
tree3f5a26d1dca1de3b3a8d5db35d2e005da3828ceb /docs
parentda0841898d247ba167c39019ea958b582a578b70 (diff)
parent316b4fd47896766928289d3785d8c53d1ca32892 (diff)
downloadcryptography-eced452177a827a2cf508c2bd6c3573aedfc8bce.tar.gz
cryptography-eced452177a827a2cf508c2bd6c3573aedfc8bce.tar.bz2
cryptography-eced452177a827a2cf508c2bd6c3573aedfc8bce.zip
Merge pull request #1166 from lvh/c-binding-docs
Early developer documentation for C bindings
Diffstat (limited to 'docs')
-rw-r--r--docs/development/c-bindings.rst192
-rw-r--r--docs/development/index.rst1
-rw-r--r--docs/development/submitting-patches.rst66
-rw-r--r--docs/spelling_wordlist.txt4
4 files changed, 199 insertions, 64 deletions
diff --git a/docs/development/c-bindings.rst b/docs/development/c-bindings.rst
new file mode 100644
index 00000000..56963379
--- /dev/null
+++ b/docs/development/c-bindings.rst
@@ -0,0 +1,192 @@
+C bindings
+==========
+
+C bindings are bindings to C libraries, using cffi_ whenever possible.
+
+.. _cffi: http://cffi.readthedocs.org
+
+Bindings live in :py:mod:`cryptography.hazmat.bindings`.
+
+Style guide
+-----------
+
+Don't name parameters:
+
+.. code-block:: c
+
+ /* Good */
+ long f(long);
+ /* Bad */
+ long f(long x);
+
+...unless they're inside a struct:
+
+.. code-block:: c
+
+ struct my_struct {
+ char *name;
+ int number;
+ ...;
+ };
+
+Include ``void`` if the function takes no arguments:
+
+.. code-block:: c
+
+ /* Good */
+ long f(void);
+ /* Bad */
+ long f();
+
+Wrap lines at 80 characters like so:
+
+.. code-block:: c
+
+ /* Pretend this went to 80 characters */
+ long f(long, long,
+ int *)
+
+Include a space after commas between parameters:
+
+.. code-block:: c
+
+ /* Good */
+ long f(int, char *)
+ /* Bad */
+ long f(int,char *)
+
+Use C-style ``/* */`` comments instead of C++-style ``//``:
+
+.. code-block:: c
+
+ // Bad
+ /* Good */
+
+Values set by ``#define`` should be assigned the appropriate type. If you see
+this:
+
+.. code-block:: c
+
+ #define SOME_INTEGER_LITERAL 0x0;
+ #define SOME_UNSIGNED_INTEGER_LITERAL 0x0001U;
+ #define SOME_STRING_LITERAL "hello";
+
+...it should be added to the bindings like so:
+
+.. code-block:: c
+
+ static const int SOME_INTEGER_LITERAL;
+ static const unsigned int SOME_UNSIGNED_INTEGER_LITERAL;
+ static const char *const SOME_STRING_LITERAL;
+
+Adding constant, types, functions...
+------------------------------------
+
+You can create bindings for any name that exists in some version of
+the library you're binding against. However, the project also has to
+keep supporting older versions of the library. In order to achieve
+this, binding modules have ``CUSTOMIZATIONS`` and
+``CONDITIONAL_NAMES`` constants.
+
+Let's say you want to enable quantum transmogrification. The upstream
+library implements this as the following API::
+
+ static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
+ static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
+ typedef ... QM_TRANSMOGRIFICATION_CTX;
+ int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
+
+To start, create a new constant that defines if the *actual* library
+has the feature you want, and add it to ``TYPES``::
+
+ static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION;
+
+This should start with ``Cryptography_``, since we're adding it in
+this library. This prevents namespace collisions.
+
+Then, define the actual features (constants, types, functions...) you
+want to expose. If it's a constant, just add it to ``TYPES``::
+
+ static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
+ static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
+
+If it's a struct, add it to ``TYPES`` as well. The following is an
+opaque struct::
+
+ typedef ... QM_TRANSMOGRIFICATION_CTX;
+
+... but you can also make some or all items in the struct accessible::
+
+ typedef struct {
+ /* Fundamental constant k for your particular universe */
+ BIGNUM *k;
+ ...;
+ } QM_TRANSMOGRIFICATION_CTX;
+
+Confusingly, functions that aren't always available on all supported
+versions of the library, should be defined in ``MACROS`` and *not* in
+``FUNCTIONS``. Fortunately, you just have to copy the signature::
+
+ int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
+
+Then, we define the ``CUSTOMIZATIONS`` entry. To do that, we have to
+come up with a C preprocessor expression that decides whether or not a
+feature exists in the library. For example::
+
+ #ifdef QM_transmogrify
+
+Then, we set the flag that signifies the feature exists::
+
+ static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 1;
+
+Otherwise, we set that flag to 0::
+
+ #else
+ static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 0;
+
+Then, in that ``#else`` block, we define the names that aren't
+available as dummy values. For an integer constant, use 0::
+
+ static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT = 0;
+ static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT = 0;
+
+For a function, it's a bit trickier. You have to define a function
+pointer of the appropriate type to be NULL::
+
+ int (*QM_transmogrify)(QM_TRANSMOGRIFICATION_CTX *, int) = NULL;
+
+(To do that, copy the signature, put a ``*`` in front of the function
+name and wrap it in parentheses, and then put ``= NULL`` at the end).
+
+Note how types don't need to be conditionally defined, as long as all
+the necessarily type definitions are in place.
+
+Finally, add an entry to ``CONDITIONAL_NAMES`` with all of the things
+you want to conditionally export::
+
+ CONDITIONAL_NAMES = {
+ ...
+ "Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION": [
+ "QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT",
+ "QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT",
+ "QM_transmogrify"
+ ]
+ }
+
+Caveats
+~~~~~~~
+
+Sometimes, a set of loosely related features are added in the same
+version, and it's impractical to create ``#ifdef`` statements for each
+one. In that case, it may make sense to either check for a particular
+version. For example, to check for OpenSSL 1.0.0 or newer::
+
+ #if OPENSSL_VERSION_NUMBER >= 0x10000000L
+
+Sometimes, the version of a library on a particular platform will have
+features that you thought it wouldn't, based on its version.
+Occasionally, packagers appear to ship arbitrary VCS checkouts. As a
+result, sometimes you may have to add separate ``#ifdef`` statements
+for particular features. This kind of issue is typically only caught
+by running the tests on a wide variety of systems, which is the job of
+our continuous integration infrastructure.
diff --git a/docs/development/index.rst b/docs/development/index.rst
index 50b60900..f9bc9eea 100644
--- a/docs/development/index.rst
+++ b/docs/development/index.rst
@@ -14,6 +14,7 @@ bug check out `what to put in your bug report`_.
submitting-patches
reviewing-patches
test-vectors
+ c-bindings
.. _`GitHub`: https://github.com/pyca/cryptography
.. _`what to put in your bug report`: http://www.contribution-guide.org/#what-to-put-in-your-bug-report
diff --git a/docs/development/submitting-patches.rst b/docs/development/submitting-patches.rst
index b7f43283..fe2df431 100644
--- a/docs/development/submitting-patches.rst
+++ b/docs/development/submitting-patches.rst
@@ -75,70 +75,8 @@ specifying a different backend.
C bindings
~~~~~~~~~~
-When binding C code with ``cffi`` we have our own style guide, it's pretty
-simple.
-
-Don't name parameters:
-
-.. code-block:: c
-
- // Good
- long f(long);
- // Bad
- long f(long x);
-
-...unless they're inside a struct:
-
-.. code-block:: c
-
- struct my_struct {
- char *name;
- int number;
- ...;
- };
-
-Include ``void`` if the function takes no arguments:
-
-.. code-block:: c
-
- // Good
- long f(void);
- // Bad
- long f();
-
-Wrap lines at 80 characters like so:
-
-.. code-block:: c
-
- // Pretend this went to 80 characters
- long f(long, long,
- int *)
-
-Include a space after commas between parameters:
-
-.. code-block:: c
-
- // Good
- long f(int, char *)
- // Bad
- long f(int,char *)
-
-Values set by ``#define`` should be assigned the appropriate type. If you see
-this:
-
-.. code-block:: c
-
- #define SOME_INTEGER_LITERAL 0x0;
- #define SOME_UNSIGNED_INTEGER_LITERAL 0x0001U;
- #define SOME_STRING_LITERAL "hello";
-
-...it should be added to the bindings like so:
-
-.. code-block:: c
-
- static const int SOME_INTEGER_LITERAL;
- static const unsigned int SOME_UNSIGNED_INTEGER_LITERAL;
- static const char *const SOME_STRING_LITERAL;
+More information on C bindings can be found in :doc:`the dedicated
+section of the documentation <c-bindings>`.
Tests
-----
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index e7a63f26..dc123493 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -30,8 +30,12 @@ invariants
iOS
Koblitz
metadata
+namespace
+namespaces
pickleable
plaintext
+preprocessor
+preprocessors
pseudorandom
Schneier
scrypt