kalyna-python.c, setup.py: Actually implement the bindings. master 0.1.0
authorMark Wooding <mdw@distorted.org.uk>
Sun, 16 Jul 2017 12:04:18 +0000 (13:04 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 16 Jul 2017 12:18:49 +0000 (13:18 +0100)
kalyna-python.c
setup.py

index 3de4bfe..7def357 100644 (file)
 
 #include "Python.h"
 
+#include "kalyna.h"
+
 /*----- Utilities ---------------------------------------------------------*/
 
+#define EXCERR(exc, str) do {                                          \
+  PyErr_SetString(exc, str);                                           \
+  goto end;                                                            \
+} while (0)
+#define VALERR(str) EXCERR(PyExc_ValueError, str)
+
 #define INSERT(name, ob) do {                                          \
   PyObject *_o = (PyObject *)(ob);                                     \
   Py_INCREF(_o);                                                       \
   PyModule_AddObject(mod, name, _o);                                   \
 } while (0)
 
+#define FREEOBJ(obj)                                                   \
+  (((PyObject *)(obj))->ob_type->tp_free((PyObject *)(obj)))
+
+int convulong(PyObject *o, void *pp)
+{
+  long i;
+  unsigned long *p = pp;
+  PyObject *t;
+
+  if (!o) VALERR("can't delete");
+  if (PyInt_Check(o)) {
+    i = PyInt_AS_LONG(o);
+    if (i < 0) VALERR("must be nonnegative");
+    *p = i;
+  } else {
+    if ((t = PyNumber_Long(o)) == 0) goto end;
+    *p = PyLong_AsUnsignedLong(t);
+    Py_DECREF(t);
+    if (PyErr_Occurred()) goto end;
+  }
+  return (1);
+end:
+  return (0);
+}
+
+static int convszt(PyObject *o, void *pp)
+{
+  unsigned long u;
+  size_t *p = pp;
+
+  if (!convulong(o, &u)) goto end;
+  if (u > ~(size_t)0) VALERR("out of range");
+  *p = u;
+  return (1);
+end:
+  return (0);
+}
+
+static inline void store64(void *p, uint64_t x)
+{
+  unsigned char *pp = p;
+
+  pp[0] = (x >>  0)&0xff; pp[1] = (x >>  8)&0xff;
+  pp[2] = (x >> 16)&0xff; pp[3] = (x >> 24)&0xff;
+  pp[4] = (x >> 32)&0xff; pp[5] = (x >> 40)&0xff;
+  pp[6] = (x >> 48)&0xff; pp[7] = (x >> 56)&0xff;
+}
+
+static inline uint64_t load64(const void *p)
+{
+  const unsigned char *pp = p;
+
+  return ((((uint64_t )pp[0]&0xff) <<  0) | (((uint64_t )pp[1]&0xff) <<  8) |
+         (((uint64_t )pp[2]&0xff) << 16) | (((uint64_t )pp[3]&0xff) << 24) |
+         (((uint64_t )pp[4]&0xff) << 32) | (((uint64_t )pp[5]&0xff) << 40) |
+         (((uint64_t )pp[6]&0xff) << 48) | (((uint64_t )pp[7]&0xff) << 56));
+}
+
+/*----- The Kalyna block cipher -------------------------------------------*/
+
+static PyTypeObject kalyna_pytype;
+
+typedef struct kalyna_pyobj {
+  PyObject_HEAD
+  kalyna_t *k;
+} kalyna_pyobj;
+
+static PyObject *kalyna_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+  char *kwlist[] = { "key", "blksz", 0 };
+  size_t blksz;
+  char *k;
+  Py_ssize_t ksz;
+  kalyna_t *kk;
+  kalyna_pyobj *rc = 0;
+  size_t i;
+  uint64_t k64[8];
+
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", kwlist,
+                                  &k, &ksz, convszt, &blksz))
+    goto end;
+  switch (blksz) {
+    case 16: case 32: case 64: break;
+    default: VALERR("bad block size");
+  }
+  if ((ksz != blksz && ksz != 2*blksz) || ksz > 64)
+    VALERR("bad key length");
+
+  kk = KalynaInit(8*blksz, 8*ksz); if (!kk) VALERR("unknown error");
+  for (i = 0; i < kk->nk; i++) k64[i] = load64(k + 8*i);
+  KalynaKeyExpand(k64, kk);
+  rc = PyObject_NEW(kalyna_pyobj, ty);
+  rc->k = kk;
+end:
+  return ((PyObject *)rc);
+}
+
+static void kalyna_pydealloc(PyObject *me)
+{
+  kalyna_pyobj *kobj = (kalyna_pyobj *)me;
+  KalynaDelete(kobj->k);
+  FREEOBJ(kobj);
+}
+
+static PyObject *kalynameth_encrypt(PyObject *me, PyObject *arg)
+{
+  char *p, *q;
+  Py_ssize_t psz;
+  PyObject *rc = 0;
+  kalyna_pyobj *kobj = (kalyna_pyobj *)me;
+  size_t i;
+  uint64_t p64[8];
+
+  if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &psz)) goto end;
+  if (psz != 8*kobj->k->nb) VALERR("incorrect block size");
+  rc = PyString_FromStringAndSize(0, psz); q = PyString_AS_STRING(rc);
+  for (i = 0; i < kobj->k->nb; i++) p64[i] = load64(p + 8*i);
+  KalynaEncipher(p64, kobj->k, p64);
+  for (i = 0; i < kobj->k->nb; i++) store64(q + 8*i, p64[i]);
+end:
+  return (rc);
+}
+
+static PyObject *kalynameth_decrypt(PyObject *me, PyObject *arg)
+{
+  char *p, *q;
+  Py_ssize_t psz;
+  PyObject *rc = 0;
+  kalyna_pyobj *kobj = (kalyna_pyobj *)me;
+  size_t i;
+  uint64_t p64[8];
+
+  if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &psz)) goto end;
+  if (psz != 8*kobj->k->nb) VALERR("incorrect block size");
+  rc = PyString_FromStringAndSize(0, psz); q = PyString_AS_STRING(rc);
+  for (i = 0; i < kobj->k->nb; i++) p64[i] = load64(p + 8*i);
+  KalynaDecipher(p64, kobj->k, p64);
+  for (i = 0; i < kobj->k->nb; i++) store64(q + 8*i, p64[i]);
+end:
+  return (rc);
+}
+
+static PyMethodDef kalyna_pymethods[] = {
+  { "encrypt", kalynameth_encrypt,     METH_VARARGS,
+    "encrypt(PTBLK) -> CTBLK" },
+  { "decrypt", kalynameth_decrypt,     METH_VARARGS,
+    "decrypt(CTBLK) -> PTBLK" },
+  { 0 }
+};
+
+static PyTypeObject kalyna_pytype = {
+  PyObject_HEAD_INIT(0) 0,             /* Header */
+  "Kalyna",                            /* @tp_name@ */
+  sizeof(kalyna_pyobj),                        /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  kalyna_pydealloc,                    /* @tp_dealloc@ */
+  0,                                   /* @tp_print@ */
+  0,                                   /* @tp_getattr@ */
+  0,                                   /* @tp_setattr@ */
+  0,                                   /* @tp_compare@ */
+  0,                                   /* @tp_repr@ */
+  0,                                   /* @tp_as_number@ */
+  0,                                   /* @tp_as_sequence@ */
+  0,                                   /* @tp_as_mapping@ */
+  0,                                   /* @tp_hash@ */
+  0,                                   /* @tp_call@ */
+  0,                                   /* @tp_str@ */
+  0,                                   /* @tp_getattro@ */
+  0,                                   /* @tp_setattro@ */
+  0,                                   /* @tp_as_buffer@ */
+  Py_TPFLAGS_DEFAULT |                 /* @tp_flags@ */
+    Py_TPFLAGS_BASETYPE,
+
+  /* @tp_doc@ */
+"Kalyna block cipher instance.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternext@ */
+  kalyna_pymethods,                    /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  0,                                   /* @tp_getset@ */
+  0,                                   /* @tp_base@ */
+  0,                                   /* @tp_dict@ */
+  0,                                   /* @tp_descr_get@ */
+  0,                                   /* @tp_descr_set@ */
+  0,                                   /* @tp_dictoffset@ */
+  0,                                   /* @tp_init@ */
+  PyType_GenericAlloc,                 /* @tp_alloc@ */
+  kalyna_pynew,                                /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
 /*----- Main code ---------------------------------------------------------*/
 
 void initkalyna(void)
 {
   PyObject *mod = Py_InitModule("kalyna", 0);
+  if (PyType_Ready(&kalyna_pytype) < 0) return;
   INSERT("version", PyString_FromString(VERSION));
+  INSERT("Kalyna", &kalyna_pytype);
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index a315063..699cd90 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -3,14 +3,18 @@
 import distutils.core as DC
 import mdwsetup as MS
 
-cat = DC.Extension('kalyna', ['kalyna-python.c'],
-                   extra_compile_args = ['-DVERSION="%s"' %
+cat = DC.Extension('kalyna', ['kalyna-python.c',
+                              'ref/kalyna.c', 'ref/tables.c'],
+                   extra_compile_args = ['-Iref/',
+                                         '-DVERSION="%s"' %
                                          MS.auto_version()])
 
 MS.setup(name = 'kalyna-python',
          description = 'Python binding to Kalyna reference implementation',
          url = 'https://git.distorted.org.uk/~mdw/kalyna-python/',
-         author = 'Mark Wooding',
+         author = 'Mark Wooding (Python); '
+                  'Ruslan Kiianchuk, Ruslan Mordvinov, Roman Oliynykov
+                        (reference implementation)',
          author_email = 'mdw@distorted.org.uk',
          license = 'Alas unclear',
          ext_modules = [cat])