0 /* @tp_is_gc@ */
};
+static PyTypeObject *shake_pytype, *shake128_pytype, *shake256_pytype;
+
+typedef struct shake_pyobj {
+ PyObject_HEAD
+ int st;
+ shake_ctx h;
+} shake_pyobj;
+
+#define SHAKE_H(o) (&((shake_pyobj *)(o))->h)
+#define SHAKE_ST(o) (((shake_pyobj *)(o))->st)
+
+static PyObject *shake_dopynew(void (*initfn)(shake_ctx *,
+ const void *, size_t,
+ const void *, size_t),
+ PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ shake_pyobj *rc = 0;
+ char *p = 0, *f = 0;
+ Py_ssize_t psz = 0, fsz = 0;
+ char *kwlist[] = { "perso", "func", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#s#:new", kwlist,
+ &p, &psz, &f, &fsz))
+ goto end;
+ rc = (shake_pyobj *)ty->tp_alloc(ty, 0);
+ initfn(&rc->h, f, fsz, p, psz);
+ rc->st = 0;
+end:
+ return ((PyObject *)rc);
+}
+
+static PyObject *shake128_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+ { return (shake_dopynew(cshake128_init, ty, arg, kw)); }
+
+static PyObject *shake256_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+ { return (shake_dopynew(cshake256_init, ty, arg, kw)); }
+
+static int shake_check(PyObject *me, int st)
+{
+ if (SHAKE_ST(me) != st) VALERR("wrong state");
+ return (0);
+end:
+ return (-1);
+}
+
+static PyObject *shakemeth_hash(PyObject *me, PyObject *arg)
+{
+ char *p;
+ Py_ssize_t sz;
+ if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0);
+ if (shake_check(me, 0)) return (0);
+ shake_hash(SHAKE_H(me), p, sz);
+ RETURN_ME;
+}
+
+#define SHAKEMETH_HASHU_(n, W, w) \
+ static PyObject *shakemeth_hashu##w(PyObject *me, PyObject *arg) \
+ { \
+ uint##n x; \
+ octet b[SZ_##W]; \
+ if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \
+ if (shake_check(me, 0)) goto end; \
+ STORE##W(b, x); shake_hash(SHAKE_H(me), b, sizeof(b)); \
+ RETURN_ME; \
+ end: \
+ return (0); \
+ }
+DOUINTCONV(SHAKEMETH_HASHU_)
+
+#define SHAKEMETH_HASHBUF_(n, W, w) \
+ static PyObject *shakemeth_hashbuf##w(PyObject *me, PyObject *arg) \
+ { \
+ char *p; \
+ Py_ssize_t sz; \
+ octet b[SZ_##W]; \
+ if (!PyArg_ParseTuple(arg, "s#:hashbuf" #w, &p, &sz)) goto end; \
+ if (sz > MASK##n) TYERR("string too long"); \
+ if (shake_check(me, 0)) goto end; \
+ STORE##W(b, sz); shake_hash(SHAKE_H(me), b, sizeof(b)); \
+ shake_hash(SHAKE_H(me), p, sz); \
+ RETURN_ME; \
+ end: \
+ return (0); \
+ }
+DOUINTCONV(SHAKEMETH_HASHBUF_)
+
+static PyObject *shakemeth_hashstrz(PyObject *me, PyObject *arg)
+{
+ char *p;
+ if (!PyArg_ParseTuple(arg, "s:hashstrz", &p)) return (0);
+ if (shake_check(me, 0)) return (0);
+ shake_hash(SHAKE_H(me), p, strlen(p) + 1);
+ RETURN_ME;
+}
+
+static PyObject *shakemeth_xof(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":xof")) goto end;
+ if (shake_check(me, 0)) goto end;
+ shake_xof(SHAKE_H(me));
+ SHAKE_ST(me) = 1;
+ RETURN_ME;
+end:
+ return (0);
+}
+
+static PyObject *shakemeth_done(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ size_t n;
+ if (!PyArg_ParseTuple(arg, "O&:done", convszt, &n)) goto end;
+ if (shake_check(me, 0)) goto end;
+ rc = bytestring_pywrap(0, n);
+ shake_done(SHAKE_H(me), PyString_AS_STRING(rc), n);
+ SHAKE_ST(me) = -1;
+end:
+ return (rc);
+}
+
+static PyObject *shakemeth_copy(PyObject *me, PyObject *arg)
+{
+ shake_pyobj *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, ":copy")) goto end;
+ rc = PyObject_NEW(shake_pyobj, me->ob_type);
+ rc->h = *SHAKE_H(me);
+ rc->st = SHAKE_ST(me);
+end:
+ return ((PyObject *)me);
+}
+
+static PyObject *shakemeth_get(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ size_t sz;
+
+ if (!PyArg_ParseTuple(arg, "O&:get", convszt, &sz)) goto end;
+ if (shake_check(me, 1)) goto end;
+ rc = bytestring_pywrap(0, sz);
+ shake_get(SHAKE_H(me), PyString_AS_STRING(rc), sz);
+end:
+ return (rc);
+}
+
+static PyObject *shakemeth_mask(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+ char *p; Py_ssize_t sz;
+
+ if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) goto end;
+ if (shake_check(me, 1)) goto end;
+ rc = bytestring_pywrap(0, sz);
+ shake_mask(SHAKE_H(me), p, PyString_AS_STRING(rc), sz);
+end:
+ return (rc);
+}
+
+static PyObject *shakeget_rate(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(SHAKE_H(me)->h.r)); }
+
+static PyObject *shakeget_buffered(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(SHAKE_H(me)->h.n)); }
+
+static PyObject *shakeget_state(PyObject *me, void *hunoz)
+{
+ int st = SHAKE_ST(me);
+ return (PyString_FromString(st == 0 ? "absorb" :
+ st == 1 ? "squeeze" : "dead"));
+}
+
+static PyGetSetDef shake_pygetset[] = {
+#define GETSETNAME(op, name) shake##op##_##name
+ GET (rate, "S.rate -> rate, in bytes")
+ GET (buffered, "S.buffered -> amount currently buffered")
+ GET (state, "S.state -> `absorb', `squeeze', `dead'")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyMethodDef shake_pymethods[] = {
+#define METHNAME(func) shakemeth_##func
+ METH (copy, "S.copy() -> SS")
+ METH (hash, "S.hash(M)")
+#define METHU_(n, W, w) METH(hashu##w, "S.hashu" #w "(WORD)")
+ DOUINTCONV(METHU_)
+#undef METHU_
+#define METHBUF_(n, W, w) METH(hashbuf##w, "S.hashbuf" #w "(BYTES)")
+ DOUINTCONV(METHBUF_)
+#undef METHBUF_
+ METH (hashstrz, "S.hashstrz(STRING)")
+ METH (xof, "S.xof()")
+ METH (done, "S.done(LEN) ->H")
+ METH (get, "S.get(LEN) -> H")
+ METH (mask, "S.mask(M) -> C")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject shake_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Shake", /* @tp_name@ */
+ sizeof(shake_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @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@ */
+"SHAKE/cSHAKE base class.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ shake_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ shake_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 PyTypeObject shake128_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Shake128", /* @tp_name@ */
+ 0, /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @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@ */
+"SHAKE128/cSHAKE128 XOF.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @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@ */
+ shake128_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject shake256_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Shake256", /* @tp_name@ */
+ 0, /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ 0, /* @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@ */
+"SHAKE256/cSHAKE256 XOF.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @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@ */
+ shake256_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
/*----- Pseudorandom permutations -----------------------------------------*/
static PyTypeObject *gcprp_pytype, *gprp_pytype;
INITTYPE_META(poly1305key, type, poly1305cls);
INITTYPE(poly1305hash, root);
INITTYPE(kxvik, root);
+ INITTYPE(shake, root);
+ INITTYPE(shake128, shake);
+ INITTYPE(shake256, shake);
INITTYPE(gcprp, type);
INITTYPE(gprp, root);
addmethods(methods);
INSERT("poly1305", poly1305key_pytype);
INSERT("Poly1305Hash", poly1305hash_pytype);
INSERT("Keccak1600", kxvik_pytype);
+ INSERT("Shake", shake_pytype);
+ INSERT("Shake128", shake128_pytype);
+ INSERT("Shake256", shake256_pytype);
INSERT("GCPRP", gcprp_pytype);
INSERT("GPRP", gprp_pytype);
INSERT("gcprps", gcprps());
### along with Catacomb/Python; if not, write to the Free Software Foundation,
### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+from __future__ import with_statement
+
import _base
import types as _types
from binascii import hexlify as _hexify, unhexlify as _unhexify
+from contextlib import contextmanager as _ctxmgr
from sys import argv as _argv
+from struct import pack as _pack
###--------------------------------------------------------------------------
### Basic stuff.
_augment(GHash, _tmp)
_augment(Poly1305Hash, _tmp)
+class _HashBase (object):
+ ## The standard hash methods. Assume that `hash' is defined and returns
+ ## the receiver.
+ def hashu8(me, n): return me.hash(_pack('B', n))
+ def hashu16l(me, n): return me.hash(_pack('<H', n))
+ def hashu16b(me, n): return me.hash(_pack('>H', n))
+ hashu16 = hashu16b
+ def hashu32l(me, n): return me.hash(_pack('<L', n))
+ def hashu32b(me, n): return me.hash(_pack('>L', n))
+ hashu32 = hashu32b
+ def hashu64l(me, n): return me.hash(_pack('<Q', n))
+ def hashu64b(me, n): return me.hash(_pack('>Q', n))
+ hashu64 = hashu64b
+ def hashbuf8(me, s): return me.hashu8(len(s)).hash(s)
+ def hashbuf16l(me, s): return me.hashu16l(len(s)).hash(s)
+ def hashbuf16b(me, s): return me.hashu16b(len(s)).hash(s)
+ hashbuf16 = hashbuf16b
+ def hashbuf32l(me, s): return me.hashu32l(len(s)).hash(s)
+ def hashbuf32b(me, s): return me.hashu32b(len(s)).hash(s)
+ hashbuf32 = hashbuf32b
+ def hashbuf64l(me, s): return me.hashu64l(len(s)).hash(s)
+ def hashbuf64b(me, s): return me.hashu64b(len(s)).hash(s)
+ hashbuf64 = hashbuf64b
+ def hashstrz(me, s): return me.hash(s).hashu8(0)
+
+class _ShakeBase (_HashBase):
+
+ ## Python gets really confused if I try to augment `__new__' on native
+ ## classes, so wrap and delegate. Sorry.
+ def __init__(me, perso = '', *args, **kw):
+ super(_ShakeBase, me).__init__(*args, **kw)
+ me._h = me._SHAKE(perso = perso, func = me._FUNC)
+
+ ## Delegate methods...
+ def copy(me): new = me.__class__(); new._copy(me)
+ def _copy(me, other): me._h = other._h
+ def hash(me, m): me._h.hash(m); return me
+ def xof(me): me._h.xof(); return me
+ def get(me, n): return me._h.get(n)
+ def mask(me, m): return me._h.mask(m)
+ def done(me, n): return me._h.done(n)
+ def check(me, h): return ctstreq(h, me.done(len(h)))
+ @property
+ def state(me): return me._h.state
+ @property
+ def buffered(me): return me._h.buffered
+ @property
+ def rate(me): return me._h.rate
+
+class _tmp:
+ def check(me, h):
+ return ctstreq(h, me.done(len(h)))
+ def leftenc(me, n):
+ nn = MP(n).storeb()
+ return me.hashu8(len(nn)).hash(nn)
+ def rightenc(me, n):
+ nn = MP(n).storeb()
+ return me.hash(nn).hashu8(len(nn))
+ def stringenc(me, str):
+ return me.leftenc(8*len(str)).hash(str)
+ def bytepad_before(me):
+ return me.leftenc(me.rate)
+ def bytepad_after(me):
+ if me.buffered: me.hash(me._Z[:me.rate - me.buffered])
+ return me
+ @_ctxmgr
+ def bytepad(me):
+ me.bytepad_before()
+ yield me
+ me.bytepad_after()
+_augment(Shake, _tmp)
+_augment(_ShakeBase, _tmp)
+Shake._Z = _ShakeBase._Z = ByteString(200*'\0')
+
+class KMAC (_ShakeBase):
+ _FUNC = 'KMAC'
+ def __init__(me, k, *arg, **kw):
+ super(KMAC, me).__init__(*arg, **kw)
+ with me.bytepad(): me.stringenc(k)
+ def done(me, n = -1):
+ if n < 0: n = me._TAGSZ
+ me.rightenc(8*n)
+ return super(KMAC, me).done(n)
+ def xof(me):
+ me.rightenc(0)
+ return super(KMAC, me).xof()
+
+class KMAC128 (KMAC): _SHAKE = Shake128; _TAGSZ = 16
+class KMAC256 (KMAC): _SHAKE = Shake256; _TAGSZ = 32
+
###--------------------------------------------------------------------------
### NaCl `secretbox'.
typedef grand *gcrand_func(const void *, size_t sz);
typedef grand *gcirand_func(const void *, size_t sz, uint32);
typedef grand *gcnrand_func(const void *, size_t sz, const void *);
+typedef grand *gcshakerand_func(const void *, size_t,
+ const void *, size_t,
+ const void *, size_t);
+typedef grand *gcshafuncrand_func(const void *, size_t,
+ const void *, size_t);
+typedef grand *gckmacrand_func(const void *, size_t, const void *, size_t);
typedef struct gccrand_info {
const char *name;
const octet *keysz;
return (0);
}
+static PyObject *gcshakyrand_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ const gccrand_info *info = GCCRAND_INFO(ty);
+ static char *kwlist_shake[] = { "key", "func", "perso", 0 };
+ static char *kwlist_func[] = { "key", "perso", 0 };
+ char *k, *f = 0, *p = 0;
+ Py_ssize_t ksz, fsz = 0, psz = 0;
+
+ if ((info->f&RNGF_MASK) == RNG_SHAKE
+ ? !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#s#:new", kwlist_shake,
+ &k, &ksz, &f, &fsz, &p, &psz)
+ : !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#:new", kwlist_func,
+ &k, &ksz, &p, &psz))
+ goto end;
+ if (keysz(ksz, info->keysz) != ksz) VALERR("bad key length");
+ return (grand_dopywrap(ty,
+ (info->f&RNGF_MASK) == RNG_SHAKE
+ ? ((gcshakerand_func *)info->func)(f, fsz,
+ p, psz,
+ k, ksz)
+ : ((gcshafuncrand_func *)info->func)(p, psz,
+ k, ksz),
+ f_freeme));
+end:
+ return (0);
+}
+
static PyObject *gccrand_pywrap(const gccrand_info *info)
{
gccrand_pyobj *g = newtype(gccrand_pytype, 0, info->name);
switch (info->f&RNGF_MASK) {
case RNG_LATIN: g->ty.ht_type.tp_new = gcnrand_pynew; break;
case RNG_SEAL: g->ty.ht_type.tp_new = gcirand_pynew; break;
+ case RNG_SHAKE: case RNG_KMAC:
+ g->ty.ht_type.tp_new = gcshakyrand_pynew; break;
default: g->ty.ht_type.tp_new = gcrand_pynew; break;
}
typeready(&g->ty.ht_type);