5 * (c) 2005 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the Python interface to Catacomb.
12 * Catacomb/Python is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * Catacomb/Python is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with Catacomb/Python; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /*----- Header files ------------------------------------------------------*/
29 #include "catacomb-python.h"
31 /*----- GF(2^8)-based secret-sharing --------------------------------------*/
33 typedef struct gfshare_pyobj
{
39 *gfshare_pytype
, *gfsharesplit_pytype
, *gfsharejoin_pytype
;
40 #define GFSHARE_PYCHECK(o) PyObject_TypeCheck((o), gfshare_pytype)
41 #define GFSHARESPLIT_PYCHECK(o) PyObject_TypeCheck((o), gfsharesplit_pytype)
42 #define GFSHAREJOIN_PYCHECK(o) PyObject_TypeCheck((o), gfsharejoin_pytype)
43 #define GFSHARE_S(o) (&((gfshare_pyobj *)(o))->s)
45 static void gfshare_pydealloc(PyObject
*me
)
47 gfshare_destroy(GFSHARE_S(me
));
51 static PyObject
*gfsget_threshold(PyObject
*me
, void *hunoz
)
52 { return (PyInt_FromLong(GFSHARE_S(me
)->t
)); }
53 static PyObject
*gfsget_size(PyObject
*me
, void *hunoz
)
54 { return (PyInt_FromLong(GFSHARE_S(me
)->sz
)); }
56 static const PyGetSetDef gfshare_pygetset
[]= {
57 #define GETSETNAME(op, name) gfs##op##_##name
58 GET (threshold
, "S.threshold -> THRESHOLD")
59 GET (size
, "S.size -> SECRETSZ")
64 static const PyTypeObject gfshare_pytype_skel
= {
65 PyObject_HEAD_INIT(&PyType_Type
) 0, /* Header */
66 "GFShare", /* @tp_name@ */
67 sizeof(gfshare_pyobj
), /* @tp_basicsize@ */
68 0, /* @tp_itemsize@ */
70 gfshare_pydealloc
, /* @tp_dealloc@ */
76 0, /* @tp_as_number@ */
77 0, /* @tp_as_sequence@ */
78 0, /* @tp_as_mapping@ */
82 0, /* @tp_getattro@ */
83 0, /* @tp_setattro@ */
84 0, /* @tp_as_buffer@ */
85 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
89 "Binary-field secret sharing base class.",
91 0, /* @tp_traverse@ */
93 0, /* @tp_richcompare@ */
94 0, /* @tp_weaklistoffset@ */
96 0, /* @tp_iternext@ */
99 PYGETSET(gfshare
), /* @tp_getset@ */
102 0, /* @tp_descr_get@ */
103 0, /* @tp_descr_set@ */
104 0, /* @tp_dictoffset@ */
106 PyType_GenericAlloc
, /* @tp_alloc@ */
107 abstract_pynew
, /* @tp_new@ */
112 static PyObject
*gfsharesplit_pynew(PyTypeObject
*ty
,
113 PyObject
*arg
, PyObject
*kw
)
118 grand
*r
= &rand_global
;
120 static const char *const kwlist
[] = { "threshold", "secret", "rng", 0 };
121 if (!PyArg_ParseTupleAndKeywords(arg
, kw
, "O&s#|O&:new", KWLIST
,
122 convuint
, &t
, &p
, &n
, convgrand
, &r
))
124 if (!t
|| t
> 255) VALERR("threshold must be nonzero and < 256");
125 s
= (gfshare_pyobj
*)ty
->tp_alloc(ty
, 0);
126 gfshare_create(&s
->s
, t
, n
);
127 gfshare_mkshares(&s
->s
, r
, p
);
128 return ((PyObject
*)s
);
133 static PyObject
*gfsmeth_get(PyObject
*me
, PyObject
*arg
)
137 if (!PyArg_ParseTuple(arg
, "O&:get", convuint
, &i
)) goto end
;
138 if (i
>= 255) VALERR("index must be < 255");
139 rc
= bytestring_pywrap(0, GFSHARE_S(me
)->sz
);
140 gfshare_get(GFSHARE_S(me
), i
, PyString_AS_STRING(rc
));
145 static const PyMethodDef gfsharesplit_pymethods
[] = {
146 #define METHNAME(name) gfsmeth_##name
147 METH (get
, "S.get(I) -> SHARE")
152 static const PyTypeObject gfsharesplit_pytype_skel
= {
153 PyObject_HEAD_INIT(&PyType_Type
) 0, /* Header */
154 "GFShareSplit", /* @tp_name@ */
155 sizeof(gfshare_pyobj
), /* @tp_basicsize@ */
156 0, /* @tp_itemsize@ */
158 gfshare_pydealloc
, /* @tp_dealloc@ */
160 0, /* @tp_getattr@ */
161 0, /* @tp_setattr@ */
162 0, /* @tp_compare@ */
164 0, /* @tp_as_number@ */
165 0, /* @tp_as_sequence@ */
166 0, /* @tp_as_mapping@ */
170 0, /* @tp_getattro@ */
171 0, /* @tp_setattro@ */
172 0, /* @tp_as_buffer@ */
173 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
177 "GFShareSplit(THRESHOLD, SECRET, [rng = rand]): binary-field sharing:\n"
178 " split secret into shares.",
180 0, /* @tp_traverse@ */
182 0, /* @tp_richcompare@ */
183 0, /* @tp_weaklistoffset@ */
185 0, /* @tp_iternext@ */
186 PYMETHODS(gfsharesplit
), /* @tp_methods@ */
187 0, /* @tp_members@ */
191 0, /* @tp_descr_get@ */
192 0, /* @tp_descr_set@ */
193 0, /* @tp_dictoffset@ */
195 PyType_GenericAlloc
, /* @tp_alloc@ */
196 gfsharesplit_pynew
, /* @tp_new@ */
201 static PyObject
*gfsharejoin_pynew(PyTypeObject
*ty
,
202 PyObject
*arg
, PyObject
*kw
)
206 static const char *const kwlist
[] = { "threshold", "size", 0 };
207 if (!PyArg_ParseTupleAndKeywords(arg
, kw
, "O&O&:new", KWLIST
,
208 convuint
, &t
, convuint
, &sz
))
210 if (!t
|| t
> 255) VALERR("threshold must be nonzero and < 256");
211 s
= (gfshare_pyobj
*)ty
->tp_alloc(ty
, 0);
212 gfshare_create(&s
->s
, t
, sz
);
213 return ((PyObject
*)s
);
218 static PyObject
*gfsmeth_addedp(PyObject
*me
, PyObject
*arg
)
221 if (!PyArg_ParseTuple(arg
, "O&:addedp", convuint
, &i
)) goto end
;
222 if (i
> 254) VALERR("index must be < 255");
223 return (getbool(gfshare_addedp(GFSHARE_S(me
), i
)));
228 static PyObject
*gfsmeth_add(PyObject
*me
, PyObject
*arg
)
233 if (!PyArg_ParseTuple(arg
, "O&s#:add", convuint
, &i
, &p
, &n
)) goto end
;
234 if (i
> 254) VALERR("index must be < 255");
235 if (n
!= GFSHARE_S(me
)->sz
) VALERR("bad share size");
236 if (gfshare_addedp(GFSHARE_S(me
), i
)) VALERR("this share already added");
237 if (GFSHARE_S(me
)->i
>= GFSHARE_S(me
)->t
) VALERR("enough shares already");
238 gfshare_add(GFSHARE_S(me
), i
, p
);
239 return (PyInt_FromLong(GFSHARE_S(me
)->t
- GFSHARE_S(me
)->i
));
244 static PyObject
*gfsmeth_combine(PyObject
*me
)
247 if (GFSHARE_S(me
)->i
< GFSHARE_S(me
)->t
) VALERR("not enough shares yet");
248 rc
= bytestring_pywrap(0, GFSHARE_S(me
)->sz
);
249 gfshare_combine(GFSHARE_S(me
), PyString_AS_STRING(rc
));
254 static const PyMethodDef gfsharejoin_pymethods
[] = {
255 #define METHNAME(name) gfsmeth_##name
256 METH (addedp
, "S.addedp(I) -> BOOL")
257 METH (add
, "S.add(I, SHARE) -> REMAIN")
258 NAMETH(combine
, "S.combine() -> SECRET")
263 static PyObject
*gfsget_remain(PyObject
*me
, void *hunoz
)
264 { return (PyInt_FromLong(GFSHARE_S(me
)->t
- GFSHARE_S(me
)->i
)); }
266 static const PyGetSetDef gfsharejoin_pygetset
[]= {
267 #define GETSETNAME(op, name) gfs##op##_##name
268 GET (remain
, "S.remain -> REMAIN")
273 static const PyTypeObject gfsharejoin_pytype_skel
= {
274 PyObject_HEAD_INIT(&PyType_Type
) 0, /* Header */
275 "GFShareJoin", /* @tp_name@ */
276 sizeof(gfshare_pyobj
), /* @tp_basicsize@ */
277 0, /* @tp_itemsize@ */
279 gfshare_pydealloc
, /* @tp_dealloc@ */
281 0, /* @tp_getattr@ */
282 0, /* @tp_setattr@ */
283 0, /* @tp_compare@ */
285 0, /* @tp_as_number@ */
286 0, /* @tp_as_sequence@ */
287 0, /* @tp_as_mapping@ */
291 0, /* @tp_getattro@ */
292 0, /* @tp_setattro@ */
293 0, /* @tp_as_buffer@ */
294 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
298 "GFShareJoin(THRESHOLD, SIZE): binary field sharing:\n"
299 " join shares to recover secret.",
301 0, /* @tp_traverse@ */
303 0, /* @tp_richcompare@ */
304 0, /* @tp_weaklistoffset@ */
306 0, /* @tp_iternext@ */
307 PYMETHODS(gfsharejoin
), /* @tp_methods@ */
308 0, /* @tp_members@ */
309 PYGETSET(gfsharejoin
), /* @tp_getset@ */
312 0, /* @tp_descr_get@ */
313 0, /* @tp_descr_set@ */
314 0, /* @tp_dictoffset@ */
316 PyType_GenericAlloc
, /* @tp_alloc@ */
317 gfsharejoin_pynew
, /* @tp_new@ */
322 /*----- Prime-field secret-sharing ----------------------------------------*/
324 typedef struct share_pyobj
{
330 *share_pytype
, *sharesplit_pytype
, *sharejoin_pytype
;
331 #define SHARE_PYCHECK(o) PyObject_TypeCheck((o), share_pytype)
332 #define SHARESPLIT_PYCHECK(o) PyObject_TypeCheck((o), sharesplit_pytype)
333 #define SHAREJOIN_PYCHECK(o) PyObject_TypeCheck((o), sharejoin_pytype)
334 #define SHARE_S(o) (&((share_pyobj *)(o))->s)
336 static void share_pydealloc(PyObject
*me
)
338 share_destroy(SHARE_S(me
));
342 static PyObject
*sget_threshold(PyObject
*me
, void *hunoz
)
343 { return (PyInt_FromLong(SHARE_S(me
)->t
)); }
344 static PyObject
*sget_modulus(PyObject
*me
, void *hunoz
)
345 { return (mp_pywrap(SHARE_S(me
)->p
)); }
347 static const PyGetSetDef share_pygetset
[]= {
348 #define GETSETNAME(op, name) s##op##_##name
349 GET (threshold
, "S.threshold -> THRESHOLD")
350 GET (modulus
, "S.modulus -> MODULUS")
355 static const PyTypeObject share_pytype_skel
= {
356 PyObject_HEAD_INIT(&PyType_Type
) 0, /* Header */
357 "Share", /* @tp_name@ */
358 sizeof(share_pyobj
), /* @tp_basicsize@ */
359 0, /* @tp_itemsize@ */
361 share_pydealloc
, /* @tp_dealloc@ */
363 0, /* @tp_getattr@ */
364 0, /* @tp_setattr@ */
365 0, /* @tp_compare@ */
367 0, /* @tp_as_number@ */
368 0, /* @tp_as_sequence@ */
369 0, /* @tp_as_mapping@ */
373 0, /* @tp_getattro@ */
374 0, /* @tp_setattro@ */
375 0, /* @tp_as_buffer@ */
376 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
380 "Prime-field secret sharing base class.",
382 0, /* @tp_traverse@ */
384 0, /* @tp_richcompare@ */
385 0, /* @tp_weaklistoffset@ */
387 0, /* @tp_iternext@ */
388 0, /* @tp_methods@ */
389 0, /* @tp_members@ */
390 PYGETSET(share
), /* @tp_getset@ */
393 0, /* @tp_descr_get@ */
394 0, /* @tp_descr_set@ */
395 0, /* @tp_dictoffset@ */
397 PyType_GenericAlloc
, /* @tp_alloc@ */
398 abstract_pynew
, /* @tp_new@ */
403 static PyObject
*sharesplit_pynew(PyTypeObject
*ty
,
404 PyObject
*arg
, PyObject
*kw
)
408 grand
*r
= &rand_global
;
411 static const char *const kwlist
[] =
412 { "threshold", "secret", "modulus", "rng", 0 };
414 if (!PyArg_ParseTupleAndKeywords(arg
, kw
, "O&O&|O&O&:new", KWLIST
,
415 convuint
, &t
, convmp
, &sec
,
416 convmp
, &m
, convgrand
, &r
))
418 if (!t
) VALERR("threshold must be nonzero");
419 s
= (share_pyobj
*)ty
->tp_alloc(ty
, 0);
420 share_create(&s
->s
, t
);
422 share_mkshares(&s
->s
, r
, sec
);
424 return ((PyObject
*)s
);
431 static PyObject
*smeth_get(PyObject
*me
, PyObject
*arg
)
435 if (!PyArg_ParseTuple(arg
, "O&:get", convuint
, &i
)) goto end
;
436 rc
= mp_pywrap(share_get(SHARE_S(me
), MP_NEW
, i
));
441 static const PyMethodDef sharesplit_pymethods
[] = {
442 #define METHNAME(name) smeth_##name
443 METH (get
, "S.get(I) -> SHARE")
448 static const PyTypeObject sharesplit_pytype_skel
= {
449 PyObject_HEAD_INIT(&PyType_Type
) 0, /* Header */
450 "ShareSplit", /* @tp_name@ */
451 sizeof(share_pyobj
), /* @tp_basicsize@ */
452 0, /* @tp_itemsize@ */
454 share_pydealloc
, /* @tp_dealloc@ */
456 0, /* @tp_getattr@ */
457 0, /* @tp_setattr@ */
458 0, /* @tp_compare@ */
460 0, /* @tp_as_number@ */
461 0, /* @tp_as_sequence@ */
462 0, /* @tp_as_mapping@ */
466 0, /* @tp_getattro@ */
467 0, /* @tp_setattro@ */
468 0, /* @tp_as_buffer@ */
469 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
473 "ShareSplit(THRESHOLD, SECRET, [modulus = ?], [rng = rand]):\n"
474 " prime field secret sharing: split secret into shares.",
476 0, /* @tp_traverse@ */
478 0, /* @tp_richcompare@ */
479 0, /* @tp_weaklistoffset@ */
481 0, /* @tp_iternext@ */
482 PYMETHODS(sharesplit
), /* @tp_methods@ */
483 0, /* @tp_members@ */
487 0, /* @tp_descr_get@ */
488 0, /* @tp_descr_set@ */
489 0, /* @tp_dictoffset@ */
491 PyType_GenericAlloc
, /* @tp_alloc@ */
492 sharesplit_pynew
, /* @tp_new@ */
497 static PyObject
*sharejoin_pynew(PyTypeObject
*ty
,
498 PyObject
*arg
, PyObject
*kw
)
503 static const char *const kwlist
[] = { "threshold", "modulus", 0 };
504 if (!PyArg_ParseTupleAndKeywords(arg
, kw
, "O&O&:new", KWLIST
,
505 convuint
, &t
, convmp
, &m
))
507 if (!t
) VALERR("threshold must be nonzero");
508 s
= (share_pyobj
*)ty
->tp_alloc(ty
, 0);
509 share_create(&s
->s
, t
);
511 return ((PyObject
*)s
);
517 static PyObject
*smeth_addedp(PyObject
*me
, PyObject
*arg
)
520 if (!PyArg_ParseTuple(arg
, "O&:addedp", convuint
, &i
)) goto end
;
521 return (getbool(share_addedp(SHARE_S(me
), i
)));
526 static PyObject
*smeth_add(PyObject
*me
, PyObject
*arg
)
531 if (!PyArg_ParseTuple(arg
, "O&O&:add", convuint
, &i
, convmp
, &s
)) goto end
;
532 if (MP_NEGP(s
) || MP_CMP(s
, >=, SHARE_S(me
)->p
))
533 VALERR("share out of range");
534 if (share_addedp(SHARE_S(me
), i
)) VALERR("this share already added");
535 if (SHARE_S(me
)->i
>= SHARE_S(me
)->t
) VALERR("enough shares already");
536 share_add(SHARE_S(me
), i
, s
);
537 rc
= PyInt_FromLong(SHARE_S(me
)->t
- SHARE_S(me
)->i
);
543 static PyObject
*smeth_combine(PyObject
*me
)
546 if (SHARE_S(me
)->i
< SHARE_S(me
)->t
) VALERR("not enough shares yet");
547 rc
= mp_pywrap(share_combine(SHARE_S(me
)));
552 static const PyMethodDef sharejoin_pymethods
[] = {
553 #define METHNAME(name) smeth_##name
554 METH (addedp
, "S.addedp(I) -> BOOL")
555 METH (add
, "S.add(I, SHARE) -> REMAIN")
556 NAMETH(combine
, "S.combine() -> SECRET")
561 static PyObject
*sget_remain(PyObject
*me
, void *hunoz
)
562 { return (PyInt_FromLong(SHARE_S(me
)->t
- SHARE_S(me
)->i
)); }
564 static const PyGetSetDef sharejoin_pygetset
[]= {
565 #define GETSETNAME(op, name) s##op##_##name
566 GET (remain
, "S.remain -> REMAIN")
571 static const PyTypeObject sharejoin_pytype_skel
= {
572 PyObject_HEAD_INIT(&PyType_Type
) 0, /* Header */
573 "ShareJoin", /* @tp_name@ */
574 sizeof(share_pyobj
), /* @tp_basicsize@ */
575 0, /* @tp_itemsize@ */
577 share_pydealloc
, /* @tp_dealloc@ */
579 0, /* @tp_getattr@ */
580 0, /* @tp_setattr@ */
581 0, /* @tp_compare@ */
583 0, /* @tp_as_number@ */
584 0, /* @tp_as_sequence@ */
585 0, /* @tp_as_mapping@ */
589 0, /* @tp_getattro@ */
590 0, /* @tp_setattro@ */
591 0, /* @tp_as_buffer@ */
592 Py_TPFLAGS_DEFAULT
| /* @tp_flags@ */
596 "ShareJoin(THRESHOLD, MODULUS): prime field secret sharing:\n"
597 " join shares to recover secret.",
599 0, /* @tp_traverse@ */
601 0, /* @tp_richcompare@ */
602 0, /* @tp_weaklistoffset@ */
604 0, /* @tp_iternext@ */
605 PYMETHODS(sharejoin
), /* @tp_methods@ */
606 0, /* @tp_members@ */
607 PYGETSET(sharejoin
), /* @tp_getset@ */
610 0, /* @tp_descr_get@ */
611 0, /* @tp_descr_set@ */
612 0, /* @tp_dictoffset@ */
614 PyType_GenericAlloc
, /* @tp_alloc@ */
615 sharejoin_pynew
, /* @tp_new@ */
620 /*----- Global stuff ------------------------------------------------------*/
622 void share_pyinit(void)
624 INITTYPE(gfshare
, root
);
625 INITTYPE(gfsharesplit
, gfshare
);
626 INITTYPE(gfsharejoin
, gfshare
);
627 INITTYPE(share
, root
);
628 INITTYPE(sharesplit
, share
);
629 INITTYPE(sharejoin
, share
);
632 void share_pyinsert(PyObject
*mod
)
634 INSERT("GFShare", gfshare_pytype
);
635 INSERT("GFShareSplit", gfsharesplit_pytype
);
636 INSERT("GFShareJoin", gfsharejoin_pytype
);
637 INSERT("Share", share_pytype
);
638 INSERT("ShareSplit", sharesplit_pytype
);
639 INSERT("ShareJoin", sharejoin_pytype
);
642 /*----- That's all, folks -------------------------------------------------*/