Checkin, Debianized and more or less complete.
[catacomb-python] / share.c
diff --git a/share.c b/share.c
new file mode 100644 (file)
index 0000000..38d966e
--- /dev/null
+++ b/share.c
@@ -0,0 +1,640 @@
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Secret sharing
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of the Python interface to Catacomb.
+ *
+ * Catacomb/Python is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * Catacomb/Python is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb/Python; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "catacomb-python.h"
+
+/*----- GF(2^8)-based secret-sharing --------------------------------------*/
+
+typedef struct gfshare_pyobj {
+  PyObject_HEAD
+  gfshare s;
+} gfshare_pyobj;
+
+static PyTypeObject
+  *gfshare_pytype, *gfsharesplit_pytype, *gfsharejoin_pytype;
+#define GFSHARE_PYCHECK(o) PyObject_TypeCheck((o), gfshare_pytype)
+#define GFSHARESPLIT_PYCHECK(o) PyObject_TypeCheck((o), gfsharesplit_pytype)
+#define GFSHAREJOIN_PYCHECK(o) PyObject_TypeCheck((o), gfsharejoin_pytype)
+#define GFSHARE_S(o) (&((gfshare_pyobj *)(o))->s)
+
+static void gfshare_pydealloc(PyObject *me)
+{
+  gfshare_destroy(GFSHARE_S(me));
+  FREEOBJ(me);
+}
+
+static PyObject *gfsget_threshold(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(GFSHARE_S(me)->t)); }
+static PyObject *gfsget_size(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(GFSHARE_S(me)->sz)); }
+
+static PyGetSetDef gfshare_pygetset[]= {
+#define GETSETNAME(op, name) gfs##op##_##name
+  GET  (threshold,     "S.threshold -> THRESHOLD")
+  GET  (size,          "S.size -> SECRETSZ")
+#undef GETSETNAME
+  { 0 }
+};
+
+static PyTypeObject gfshare_pytype_skel = {
+  PyObject_HEAD_INIT(&PyType_Type) 0,  /* Header */
+  "catacomb.GFShare",                  /* @tp_name@ */
+  sizeof(gfshare_pyobj),               /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  gfshare_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@ */
+"Binary-field secret sharing base class.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternexr@ */
+  0,                                   /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  gfshare_pygetset,                    /* @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@ */
+  abstract_pynew,                      /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+static PyObject *gfsharesplit_pynew(PyTypeObject *ty,
+                                   PyObject *arg, PyObject *kw)
+{
+  char *p;
+  int n;
+  unsigned t;
+  grand *r = &rand_global;
+  gfshare_pyobj *s;
+  char *kwlist[] = { "threshold", "secret", "rng", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&s#|O&:new", kwlist,
+                                  convuint, &t, &p, &n, convgrand, &r))
+    goto end;
+  if (!t || t > 255) VALERR("threshold must be nonzero and < 256");
+  s = (gfshare_pyobj *)ty->tp_alloc(ty, 0);
+  gfshare_create(&s->s, t, n);
+  gfshare_mkshares(&s->s, r, p);
+  return ((PyObject *)s);
+end:
+  return (0);
+}
+
+static PyObject *gfsmeth_get(PyObject *me, PyObject *arg)
+{
+  unsigned i;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "O&:get", convuint, &i)) goto end;
+  if (i >= 255) VALERR("index must be < 255");
+  rc = bytestring_pywrap(0, GFSHARE_S(me)->sz);
+  gfshare_get(GFSHARE_S(me), i, PyString_AS_STRING(rc));
+end:
+  return (rc);
+}
+
+static PyMethodDef gfsharesplit_pymethods[] = {
+#define METHNAME(name) gfsmeth_##name
+  METH (get,           "S.get(I) -> SHARE")
+#undef METHNAME
+  { 0 }
+};
+
+static PyTypeObject gfsharesplit_pytype_skel = {
+  PyObject_HEAD_INIT(&PyType_Type) 0,  /* Header */
+  "catacomb.GFShareSplit",             /* @tp_name@ */
+  sizeof(gfshare_pyobj),               /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  gfshare_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@ */
+"Binary field secret sharing: split secret into shares.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternexr@ */
+  gfsharesplit_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@ */
+  gfsharesplit_pynew,                  /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+static PyObject *gfsharejoin_pynew(PyTypeObject *ty,
+                                  PyObject *arg, PyObject *kw)
+{
+  unsigned t, sz;
+  gfshare_pyobj *s;
+  char *kwlist[] = { "threshold", "size", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+                                  convuint, &t, convuint, &sz))
+    goto end;
+  if (!t || t > 255) VALERR("threshold must be nonzero and < 256");
+  s = (gfshare_pyobj *)ty->tp_alloc(ty, 0);
+  gfshare_create(&s->s, t, sz);
+  return ((PyObject *)s);
+end:
+  return (0);
+}
+
+static PyObject *gfsmeth_addedp(PyObject *me, PyObject *arg)
+{
+  unsigned i;
+  if (!PyArg_ParseTuple(arg, "O&:addedp", convuint, &i)) goto end;
+  if (i > 254) VALERR("index must be < 255");
+  return (getbool(gfshare_addedp(GFSHARE_S(me), i)));
+end:
+  return (0);
+}
+
+static PyObject *gfsmeth_add(PyObject *me, PyObject *arg)
+{
+  unsigned i;
+  char *p;
+  int n;
+  if (!PyArg_ParseTuple(arg, "O&s#:add", convuint, &i, &p, &n)) goto end;
+  if (i > 254) VALERR("index must be < 255");
+  if (n != GFSHARE_S(me)->sz) VALERR("bad share size");
+  if (gfshare_addedp(GFSHARE_S(me), i)) VALERR("this share already added");
+  if (GFSHARE_S(me)->i >= GFSHARE_S(me)->t) VALERR("enough shares already");
+  gfshare_add(GFSHARE_S(me), i, p);
+  return (PyInt_FromLong(GFSHARE_S(me)->t - GFSHARE_S(me)->i));
+end:
+  return (0);
+}
+
+static PyObject *gfsmeth_combine(PyObject *me, PyObject *arg)
+{
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, ":combine")) goto end;
+  if (GFSHARE_S(me)->i < GFSHARE_S(me)->t) VALERR("not enough shares yet");
+  rc = bytestring_pywrap(0, GFSHARE_S(me)->sz);
+  gfshare_combine(GFSHARE_S(me), PyString_AS_STRING(rc));
+end:
+  return (rc);
+}
+
+static PyMethodDef gfsharejoin_pymethods[] = {
+#define METHNAME(name) gfsmeth_##name
+  METH (addedp,        "S.addedp(I) -> BOOL")
+  METH (add,           "S.add(I, SHARE) -> REMAIN")
+  METH (combine,       "S.combine() -> SECRET")
+#undef METHNAME
+  { 0 }
+};
+
+static PyObject *gfsget_remain(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(GFSHARE_S(me)->t - GFSHARE_S(me)->i)); }
+
+static PyGetSetDef gfsharejoin_pygetset[]= {
+#define GETSETNAME(op, name) gfs##op##_##name
+  GET  (remain,        "S.remain -> REMAIN")
+#undef GETSETNAME
+  { 0 }
+};
+
+static PyTypeObject gfsharejoin_pytype_skel = {
+  PyObject_HEAD_INIT(&PyType_Type) 0,  /* Header */
+  "catacomb.GFShareJoin",              /* @tp_name@ */
+  sizeof(gfshare_pyobj),               /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  gfshare_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@ */
+"Binary field secret sharing: join shares to recover secret.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternexr@ */
+  gfsharejoin_pymethods,               /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  gfsharejoin_pygetset,                        /* @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@ */
+  gfsharejoin_pynew,                   /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+/*----- Prime-field secret-sharing ----------------------------------------*/
+
+typedef struct share_pyobj {
+  PyObject_HEAD
+  share s;
+} share_pyobj;
+
+static PyTypeObject
+  *share_pytype, *sharesplit_pytype, *sharejoin_pytype;
+#define SHARE_PYCHECK(o) PyObject_TypeCheck((o), share_pytype)
+#define SHARESPLIT_PYCHECK(o) PyObject_TypeCheck((o), sharesplit_pytype)
+#define SHAREJOIN_PYCHECK(o) PyObject_TypeCheck((o), sharejoin_pytype)
+#define SHARE_S(o) (&((share_pyobj *)(o))->s)
+
+static void share_pydealloc(PyObject *me)
+{
+  share_destroy(SHARE_S(me));
+  FREEOBJ(me);
+}
+
+static PyObject *sget_threshold(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(SHARE_S(me)->t)); }
+static PyObject *sget_modulus(PyObject *me, void *hunoz)
+  { return (mp_pywrap(SHARE_S(me)->p)); }
+
+static PyGetSetDef share_pygetset[]= {
+#define GETSETNAME(op, name) s##op##_##name
+  GET  (threshold,     "S.threshold -> THRESHOLD")
+  GET  (modulus,       "S.modulus -> MODULUS")
+#undef GETSETNAME
+  { 0 }
+};
+
+static PyTypeObject share_pytype_skel = {
+  PyObject_HEAD_INIT(&PyType_Type) 0,  /* Header */
+  "catacomb.Share",                    /* @tp_name@ */
+  sizeof(share_pyobj),                 /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  share_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@ */
+"Prime-field secret sharing base class.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternexr@ */
+  0,                                   /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  share_pygetset,                      /* @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@ */
+  abstract_pynew,                      /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+static PyObject *sharesplit_pynew(PyTypeObject *ty,
+                                 PyObject *arg, PyObject *kw)
+{
+  mp *sec = 0;
+  unsigned t;
+  grand *r = &rand_global;
+  mp *m = 0;
+  share_pyobj *s;
+  char *kwlist[] = { "threshold", "secret", "modulus", "rng", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&)&|O&O&:new", kwlist,
+                                  convuint, &t, convmp, &sec,
+                                  convmp, &m, convgrand, &r))
+    goto end;
+  if (!t) VALERR("threshold must be nonzero");
+  s = (share_pyobj *)ty->tp_alloc(ty, 0);
+  share_create(&s->s, t);
+  s->s.p = m;
+  share_mkshares(&s->s, r, sec);
+  mp_drop(sec);
+  return ((PyObject *)s);
+end:
+  mp_drop(m);
+  mp_drop(sec);
+  return (0);
+}
+
+static PyObject *smeth_get(PyObject *me, PyObject *arg)
+{
+  unsigned i;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "O&:get", convuint, &i)) goto end;
+  rc = mp_pywrap(share_get(SHARE_S(me), MP_NEW, i));
+end:
+  return (rc);
+}
+
+static PyMethodDef sharesplit_pymethods[] = {
+#define METHNAME(name) smeth_##name
+  METH (get,           "S.get(I) -> SHARE")
+#undef METHNAME
+  { 0 }
+};
+
+static PyTypeObject sharesplit_pytype_skel = {
+  PyObject_HEAD_INIT(&PyType_Type) 0,  /* Header */
+  "catacomb.ShareSplit",               /* @tp_name@ */
+  sizeof(share_pyobj),                 /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  share_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@ */
+"Prime field secret sharing: split secret into shares.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternexr@ */
+  sharesplit_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@ */
+  sharesplit_pynew,                    /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+static PyObject *sharejoin_pynew(PyTypeObject *ty,
+                                PyObject *arg, PyObject *kw)
+{
+  unsigned t;
+  mp *m = 0;
+  share_pyobj *s;
+  char *kwlist[] = { "threshold", "modulus", 0 };
+  if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+                                  convuint, &t, convmp, &m))
+    goto end;
+  if (!t) VALERR("threshold must be nonzero");
+  s = (share_pyobj *)ty->tp_alloc(ty, 0);
+  share_create(&s->s, t);
+  s->s.p = m;
+  return ((PyObject *)s);
+end:
+  mp_drop(m);
+  return (0);
+}
+
+static PyObject *smeth_addedp(PyObject *me, PyObject *arg)
+{
+  unsigned i;
+  if (!PyArg_ParseTuple(arg, "O&:addedp", convuint, &i)) goto end;
+  return (getbool(share_addedp(SHARE_S(me), i)));
+end:
+  return (0);
+}
+
+static PyObject *smeth_add(PyObject *me, PyObject *arg)
+{
+  unsigned i;
+  mp *s = 0;
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, "O&O&:add", convuint, &i, convmp, &s)) goto end;
+  if (MP_NEGP(s) || MP_CMP(s, >=, SHARE_S(me)->p))
+    VALERR("share out of range");
+  if (share_addedp(SHARE_S(me), i)) VALERR("this share already added");
+  if (SHARE_S(me)->i >= SHARE_S(me)->t) VALERR("enough shares already");
+  share_add(SHARE_S(me), i, s);
+  rc = PyInt_FromLong(SHARE_S(me)->t - SHARE_S(me)->i);
+end:
+  mp_drop(s);
+  return (rc);
+}
+
+static PyObject *smeth_combine(PyObject *me, PyObject *arg)
+{
+  PyObject *rc = 0;
+  if (!PyArg_ParseTuple(arg, ":combine")) goto end;
+  if (SHARE_S(me)->i < SHARE_S(me)->t) VALERR("not enough shares yet");
+  rc = mp_pywrap(share_combine(SHARE_S(me)));
+end:
+  return (rc);
+}
+
+static PyMethodDef sharejoin_pymethods[] = {
+#define METHNAME(name) smeth_##name
+  METH (addedp,        "S.addedp(I) -> BOOL")
+  METH (add,           "S.add(I, SHARE) -> REMAIN")
+  METH (combine,       "S.combine() -> SECRET")
+#undef METHNAME
+  { 0 }
+};
+
+static PyObject *sget_remain(PyObject *me, void *hunoz)
+  { return (PyInt_FromLong(SHARE_S(me)->t - SHARE_S(me)->i)); }
+
+static PyGetSetDef sharejoin_pygetset[]= {
+#define GETSETNAME(op, name) s##op##_##name
+  GET  (remain,        "S.remain -> REMAIN")
+#undef GETSETNAME
+  { 0 }
+};
+
+static PyTypeObject sharejoin_pytype_skel = {
+  PyObject_HEAD_INIT(&PyType_Type) 0,  /* Header */
+  "catacomb.ShareJoin",                        /* @tp_name@ */
+  sizeof(share_pyobj),                 /* @tp_basicsize@ */
+  0,                                   /* @tp_itemsize@ */
+
+  share_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@ */
+"Prime field secret sharing: join shares to recover secret.",
+
+  0,                                   /* @tp_traverse@ */
+  0,                                   /* @tp_clear@ */
+  0,                                   /* @tp_richcompare@ */
+  0,                                   /* @tp_weaklistoffset@ */
+  0,                                   /* @tp_iter@ */
+  0,                                   /* @tp_iternexr@ */
+  sharejoin_pymethods,                 /* @tp_methods@ */
+  0,                                   /* @tp_members@ */
+  sharejoin_pygetset,                  /* @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@ */
+  sharejoin_pynew,                     /* @tp_new@ */
+  0,                                   /* @tp_free@ */
+  0                                    /* @tp_is_gc@ */
+};
+
+/*----- Global stuff ------------------------------------------------------*/
+
+void share_pyinit(void)
+{
+  INITTYPE(gfshare, root);
+  INITTYPE(gfsharesplit, gfshare);
+  INITTYPE(gfsharejoin, gfshare);
+  INITTYPE(share, root);
+  INITTYPE(sharesplit, share);
+  INITTYPE(sharejoin, share);
+}
+
+void share_pyinsert(PyObject *mod)
+{
+  INSERT("GFShare", gfshare_pytype);
+  INSERT("GFShareSplit", gfsharesplit_pytype);
+  INSERT("GFShareJoin", gfsharejoin_pytype);
+  INSERT("Share", share_pytype);
+  INSERT("ShareSplit", sharesplit_pytype);
+  INSERT("ShareJoin", sharejoin_pytype);
+}
+
+/*----- That's all, folks -------------------------------------------------*/