--- /dev/null
+Mark Wooding <mdw@distorted.org.uk> <mdw>
-### Manifest template for Catacomb/Python.
+### Manifest template for Catacomb/Python. -*-conf-*-
## Generated build machinery.
include COPYING auto-version mdwsetup.py pysetup.mk
include t/*.py t/keyring
include algorithms.py
exclude algorithms.h
+
+## Scripts.
+include pock
include pwsafe
+## Manual pages.
+include *.[13]
+
## Python wrapping.
recursive-include catacomb *.py
static PyObject *keyszany_pynew(PyTypeObject *ty,
PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "default", 0 };
+ static const char *const kwlist[] = { "default", 0 };
int dfl;
keysz_pyobj *o;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "i:new", kwlist, &dfl))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "i:new", KWLIST, &dfl))
goto end;
if (dfl < 0) VALERR("key size cannot be negative");
o = (keysz_pyobj *)ty->tp_alloc(ty, 0);
static PyObject *keyszrange_pynew(PyTypeObject *ty,
PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "default", "min", "max", "mod", 0 };
+ static const char *const kwlist[] = { "default", "min", "max", "mod", 0 };
int dfl, min = 0, max = 0, mod = 1;
keyszrange_pyobj *o;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|iii:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|iii:new", KWLIST,
&dfl, &min, &max, &mod))
goto end;
- if (dfl < 0 || min < 0 || max < 0)
- VALERR("key size cannot be negative");
- if (min > dfl || (max && dfl > max))
- VALERR("bad key size bounds");
- if (mod <= 0 || dfl % mod || min % mod || max % mod)
+ if (dfl < 0 || min < 0) VALERR("key size cannot be negative");
+ if (min > dfl || (max && dfl > max)) VALERR("bad key size bounds");
+ if (mod <= 0 || dfl%mod || min%mod || max%mod)
VALERR("bad key size modulus");
o = (keyszrange_pyobj *)ty->tp_alloc(ty, 0);
o->dfl = dfl;
static PyObject *keyszset_pynew(PyTypeObject *ty,
PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "default", "set", 0 };
+ static const char *const kwlist[] = { "default", "set", 0 };
int dfl, i, n, xx;
PyObject *set = 0;
PyObject *x = 0, *l = 0;
keyszset_pyobj *o = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|O:new", kwlist,
- &dfl, &set))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "i|O:new", KWLIST, &dfl, &set))
goto end;
if (!set) set = PyTuple_New(0);
else Py_INCREF(set);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key size constraints.",
+"Key size constraints. Abstract.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key size constraints. This object imposes no constraints on size.",
+"KeySZAny(DEFAULT)\n\
+ Key size constraints. This object imposes no constraints on size.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key size constraints. This object asserts minimum and maximum (if\n\
-sizes, and requires the key length to be a multiple of some value.",
+"KeySZRange(DEFAULT, [min = 0], [max = 0], [mod = 1])\n\
+ Key size constraints. Key size must be between MIN and MAX inclusive,\n\
+ and be a multiple of MOD.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key size constraints. This object requires the key to be one of a\n\
-few listed sizes.",
+"KeySZSet(DEFAULT, SEQ)\n\
+ Key size constraints. Key size must be DEFAULT or one in SEQ.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
CONVFUNC(gccipher, gccipher *, GCCIPHER_CC)
CONVFUNC(gcipher, gcipher *, GCIPHER_C)
-PyObject *gcipher_pywrap(PyObject *cobj, gcipher *c, unsigned f)
+PyObject *gcipher_pywrap(PyObject *cobj, gcipher *c)
{
gcipher_pyobj *g;
if (!cobj) cobj = gccipher_pywrap((/*unconst*/ gccipher *)GC_CLASS(c));
else Py_INCREF(cobj);
g = PyObject_NEW(gcipher_pyobj, (PyTypeObject *)cobj);
g->c = c;
- g->f = f;
return ((PyObject *)g);
}
static PyObject *gcipher_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "k", 0 };
+ static const char *const kwlist[] = { "k", 0 };
char *k;
Py_ssize_t sz;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &k, &sz))
goto end;
if (keysz(sz, GCCIPHER_CC(ty)->keysz) != sz) VALERR("bad key length");
return (gcipher_pywrap((PyObject *)ty,
- GC_INIT(GCCIPHER_CC(ty), k, sz),
- f_freeme));
+ GC_INIT(GCCIPHER_CC(ty), k, sz)));
end:
return (0);
}
static void gcipher_pydealloc(PyObject *me)
{
- if (GCIPHER_F(me) & f_freeme)
- GC_DESTROY(GCIPHER_C(me));
+ GC_DESTROY(GCIPHER_C(me));
Py_DECREF(me->ob_type);
FREEOBJ(me);
}
0 /* @tp_is_gc@ */
};
+/*----- Authenticated encryption ------------------------------------------*/
+
+PyTypeObject *gcaead_pytype, *gaeadkey_pytype;
+PyTypeObject *gcaeadaad_pytype, *gaeadaad_pytype;
+PyTypeObject *gcaeadenc_pytype, *gaeadenc_pytype;
+PyTypeObject *gcaeaddec_pytype, *gaeaddec_pytype;
+
+CONVFUNC(gcaead, gcaead *, GCAEAD_AEC)
+CONVFUNC(gaeadkey, gaead_key *, GAEADKEY_K)
+
+PyObject *gaeadkey_pywrap(PyObject *cobj, gaead_key *k)
+{
+ gaeadkey_pyobj *gk;
+
+ if (!cobj) cobj = gcaead_pywrap((/*unconst*/ gcaead *)GAEAD_CLASS(k));
+ else Py_INCREF(cobj);
+ gk = PyObject_NEW(gaeadkey_pyobj, (PyTypeObject *)cobj);
+ gk->k = k;
+ return ((PyObject *)gk);
+}
+
+static PyObject *gaeadkey_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { "k", 0 };
+ char *k;
+ Py_ssize_t sz;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &k, &sz))
+ goto end;
+ if (keysz(sz, GCAEAD_AEC(ty)->keysz) != sz) VALERR("bad key length");
+ return (gaeadkey_pywrap((PyObject *)ty,
+ GAEAD_KEY(GCAEAD_AEC(ty), k, sz)));
+end:
+ return (0);
+}
+
+PyObject *gcaead_pywrap(gcaead *aec)
+{
+ gcaead_pyobj *gck;
+ gcaeadaad_pyobj *gca;
+ gcaeadenc_pyobj *gce;
+ gcaeaddec_pyobj *gcd;
+
+#define MKTYPE(obj, thing, newfn, namefmt) do { \
+ (obj) = newtype(gcaead_pytype, 0, 0); \
+ (obj)->ty.ht_name = PyString_FromFormat(namefmt, aec->name); \
+ (obj)->ty.ht_type.tp_name = PyString_AS_STRING((obj)->ty.ht_name); \
+ (obj)->ty.ht_type.tp_basicsize = sizeof(gaead##thing##_pyobj); \
+ (obj)->ty.ht_type.tp_base = gaead##thing##_pytype; \
+ Py_INCREF(gaead##thing##_pytype); \
+ (obj)->ty.ht_type.tp_flags = \
+ (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE); \
+ (obj)->ty.ht_type.tp_alloc = PyType_GenericAlloc; \
+ (obj)->ty.ht_type.tp_free = 0; \
+ (obj)->ty.ht_type.tp_new = newfn; \
+ typeready(&(obj)->ty.ht_type); \
+} while (0)
+
+ MKTYPE(gck, key, gaeadkey_pynew, "%s(key)");
+ MKTYPE(gca, aad, abstract_pynew, "%s(aad-hash)");
+ MKTYPE(gce, enc, abstract_pynew, "%s(encrypt)");
+ MKTYPE(gcd, dec, abstract_pynew, "%s(decrypt)");
+
+#undef MKTYPE
+
+ gck->aec = aec; gck->aad = gca; gck->enc = gce; gck->dec = gcd;
+ gca->key = gce->key = gcd->key = gck;
+ return ((PyObject *)gck);
+}
+
+static void gaeadkey_pydealloc(PyObject *me)
+ { GAEAD_DESTROY(GAEADKEY_K(me)); Py_DECREF(me->ob_type); FREEOBJ(me); }
+
+static PyObject *gcaeget_name(PyObject *me, void *hunoz)
+ { return (PyString_FromString(GCAEAD_AEC(me)->name)); }
+
+static PyObject *gcaeget_keysz(PyObject *me, void *hunoz)
+ { return (keysz_pywrap(GCAEAD_AEC(me)->keysz)); }
+
+static PyObject *gcaeget_noncesz(PyObject *me, void *hunoz)
+ { return (keysz_pywrap(GCAEAD_AEC(me)->noncesz)); }
+
+static PyObject *gcaeget_tagsz(PyObject *me, void *hunoz)
+ { return (keysz_pywrap(GCAEAD_AEC(me)->tagsz)); }
+
+static PyObject *gcaeget_blksz(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCAEAD_AEC(me)->blksz)); }
+
+static PyObject *gcaeget_bufsz(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCAEAD_AEC(me)->bufsz)); }
+
+static PyObject *gcaeget_ohd(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCAEAD_AEC(me)->ohd)); }
+
+static PyObject *gcaeget_flags(PyObject *me, void *hunoz)
+ { return (PyInt_FromLong(GCAEAD_AEC(me)->f)); }
+
+static PyGetSetDef gcaead_pygetset[] = {
+#define GETSETNAME(op, name) gcae##op##_##name
+ GET (keysz, "AEC.keysz -> acceptable key sizes")
+ GET (noncesz, "AEC.noncesz -> acceptable nonce sizes")
+ GET (tagsz, "AEC.tagsz -> acceptable tag sizes")
+ GET (blksz, "AEC.blksz -> block size, or zero")
+ GET (bufsz, "AEC.bufsz -> amount of data buffered internally")
+ GET (ohd, "AEC.ohd -> maximum encryption overhead")
+ GET (name, "AEC.name -> name of this kind of AEAD scheme")
+ GET (flags, "AEC.flags -> mask of `AEADF_...' flags")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *gaekmeth_aad(PyObject *me, PyObject *arg)
+{
+ const gaead_key *k = GAEADKEY_K(me);
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, ":aad")) return (0);
+ if (k->ops->c->f&AEADF_AADNDEP)
+ VALERR("aad must be associated with enc/dec op");
+ rc = gaeadaad_pywrap((PyObject *)GCAEAD_AAD(me->ob_type),
+ GAEAD_AAD(k), 0, 0);
+end:
+ return (rc);
+}
+
+static int check_aead_encdec(const gcaead *aec, unsigned *f_out, size_t nsz,
+ PyObject *hszobj, size_t *hsz_out,
+ PyObject *mszobj, size_t *msz_out,
+ PyObject *tszobj, size_t *tsz_out)
+{
+ unsigned f = 0, miss;
+ int rc = -1;
+
+ if (hszobj != Py_None)
+ { f |= AEADF_PCHSZ; if (!convszt(hszobj, hsz_out)) goto end; }
+ if (mszobj != Py_None)
+ { f |= AEADF_PCMSZ; if (!convszt(mszobj, msz_out)) goto end; }
+ if (tszobj != Py_None)
+ { f |= AEADF_PCTSZ; if (!convszt(tszobj, tsz_out)) goto end; }
+ miss = aec->f&~f;
+ if (miss&AEADF_PCHSZ) VALERR("header length precommitment required");
+ if (miss&AEADF_PCMSZ) VALERR("message length precommitment required");
+ if (miss&AEADF_PCTSZ) VALERR("tag length precommitment required");
+ if (keysz(nsz, aec->noncesz) != nsz) VALERR("bad nonce length");
+ if (tszobj != Py_None && keysz(*tsz_out, aec->tagsz) != *tsz_out)
+ VALERR("bad tag length");
+ *f_out = f | aec->f; rc = 0;
+end:
+ return (rc);
+}
+
+static PyObject *gaekmeth_enc(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { "nonce", "hsz", "msz", "tsz", 0 };
+ const gaead_key *k = GAEADKEY_K(me);
+ gaead_enc *e;
+ PyObject *rc = 0;
+ char *n; Py_ssize_t nsz;
+ PyObject *hszobj = Py_None, *mszobj = Py_None, *tszobj = Py_None;
+ size_t hsz = 0, msz = 0, tsz = 0;
+ unsigned f;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|OOO:enc", KWLIST,
+ &n, &nsz, &hszobj, &mszobj, &tszobj))
+ goto end;
+ if (check_aead_encdec(k->ops->c, &f, nsz,
+ hszobj, &hsz, mszobj, &msz, tszobj, &tsz))
+ goto end;
+ e = GAEAD_ENC(GAEADKEY_K(me), n, nsz, hsz, msz, tsz);
+ if (!e) VALERR("bad aead parameter combination");
+ rc = gaeadenc_pywrap((PyObject *)GCAEAD_ENC(me->ob_type),
+ e, f, hsz, msz, tsz);
+end:
+ return (rc);
+}
+
+static PyObject *gaekmeth_dec(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { "nonce", "hsz", "csz", "tsz", 0 };
+ const gaead_key *k = GAEADKEY_K(me);
+ gaead_dec *d;
+ PyObject *rc = 0;
+ char *n; Py_ssize_t nsz;
+ PyObject *hszobj = Py_None, *cszobj = Py_None, *tszobj = Py_None;
+ size_t hsz = 0, csz = 0, tsz = 0;
+ unsigned f;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|OOO:dec", KWLIST,
+ &n, &nsz, &hszobj, &cszobj, &tszobj))
+ goto end;
+ if (check_aead_encdec(k->ops->c, &f, nsz,
+ hszobj, &hsz, cszobj, &csz, tszobj, &tsz))
+ goto end;
+ d = GAEAD_DEC(GAEADKEY_K(me), n, nsz, hsz, csz, tsz);
+ if (!d) VALERR("bad aead parameter combination");
+ rc = gaeaddec_pywrap((PyObject *)GCAEAD_DEC(me->ob_type),
+ d, f, hsz, csz, tsz);
+end:
+ return (rc);
+}
+
+static PyMethodDef gaeadkey_pymethods[] = {
+#define METHNAME(name) gaekmeth_##name
+ METH (aad, "KEY.aad() -> AAD")
+ KWMETH(enc, "KEY.enc(NONCE, [hsz], [msz], [tsz]) -> ENC")
+ KWMETH(dec, "KEY.dec(NONCE, [hsz], [csz], [tsz]) -> DEC")
+#undef METHNAME
+ { 0 }
+};
+
+PyObject *gaeadaad_pywrap(PyObject *cobj, gaead_aad *a,
+ unsigned f, size_t hsz)
+{
+ gaeadaad_pyobj *ga;
+
+ assert(cobj); Py_INCREF(cobj);
+ ga = PyObject_NEW(gaeadaad_pyobj, (PyTypeObject *)cobj);
+ ga->a = a; ga->f = f; ga->hsz = hsz; ga->hlen = 0;
+ return ((PyObject *)ga);
+}
+
+static void gaeadaad_pydealloc(PyObject *me)
+{
+ gaeadaad_pyobj *ga = (gaeadaad_pyobj *)me;
+
+ if (ga->a) GAEAD_DESTROY(ga->a);
+ Py_DECREF(me->ob_type); FREEOBJ(me);
+}
+
+static int gaea_check(PyObject *me)
+{
+ gaeadaad_pyobj *ga = (gaeadaad_pyobj *)me;
+ int rc = -1;
+
+ if ((ga->f&AEADF_DEAD) || !ga->a) VALERR("aad object no longer active");
+ rc = 0;
+end:
+ return (rc);
+}
+
+static void gaea_invalidate(gaeadaad_pyobj *ga)
+ { if (ga) ga->f |= AEADF_DEAD; }
+
+static void gaea_sever(gaeadaad_pyobj **ga_inout)
+{
+ gaeadaad_pyobj *ga = *ga_inout;
+ if (ga) { ga->f |= AEADF_DEAD; ga->a = 0; Py_DECREF(ga); *ga_inout = 0; }
+}
+
+static PyObject *gaeaget_hsz(PyObject *me, void *hunoz)
+{
+ if (gaea_check(me)) return (0);
+ else if (GAEADAAD_F(me)&AEADF_PCHSZ) return getulong(GAEADAAD_HSZ(me));
+ else RETURN_NONE;
+}
+
+static PyObject *gaeaget_hlen(PyObject *me, void *hunoz)
+ { return (gaea_check(me) ? 0 : getulong(GAEADAAD_HLEN(me))); }
+
+static PyGetSetDef gaeadaad_pygetset[] = {
+#define GETSETNAME(op, name) gaea##op##_##name
+ GET (hsz, "AAD.hsz -> precommitted header length or `None'")
+ GET (hlen, "AAD.hlen -> header length so far")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *gaeameth_copy(PyObject *me, PyObject *arg)
+{
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, ":copy")) goto end;
+ if (gaea_check(me)) goto end;
+ if (GAEADAAD_F(me)&AEADF_AADNDEP)
+ VALERR("can't duplicate nonce-dependent aad");
+ rc = gaeadaad_pywrap((PyObject *)me->ob_type,
+ GAEAD_DUP(GAEADAAD_A(me)), 0, 0);
+end:
+ return (rc);
+}
+
+static int gaeadaad_hash(PyObject *me, const void *h, size_t hsz)
+{
+ gaeadaad_pyobj *ga = (gaeadaad_pyobj *)me;
+ int rc = -1;
+
+ if (gaea_check(me)) goto end;
+ if ((ga->f&AEADF_NOAAD) && hsz)
+ VALERR("header data not permitted");
+ if ((ga->f&AEADF_PCHSZ) && hsz > ga->hsz - ga->hlen)
+ VALERR("too large for precommitted header length");
+ GAEAD_HASH(ga->a, h, hsz); ga->hlen += hsz;
+ rc = 0;
+end:
+ return (rc);
+}
+
+
+static PyObject *gaeameth_hash(PyObject *me, PyObject *arg)
+{
+ char *h; Py_ssize_t hsz;
+
+ if (!PyArg_ParseTuple(arg, "s#:hash", &h, &hsz)) return (0);
+ if (gaeadaad_hash(me, h, hsz)) return (0);
+ RETURN_ME;
+}
+
+#define GAEAMETH_HASHU_(n, W, w) \
+ static PyObject *gaeameth_hashu##w(PyObject *me, PyObject *arg) \
+ { \
+ uint##n x; octet b[SZ_##W]; \
+ if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) return (0); \
+ STORE##W(b, x); if (gaeadaad_hash(me, b, sizeof(b))) return (0); \
+ RETURN_ME; \
+ }
+DOUINTCONV(GAEAMETH_HASHU_)
+
+#define GAEAMETH_HASHBUF_(n, W, w) \
+ static PyObject *gaeameth_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"); \
+ STORE##W(b, sz); if (gaeadaad_hash(me, b, sizeof(b))) goto end; \
+ if (gaeadaad_hash(me, p, sz)) goto end; \
+ RETURN_ME; \
+ end: \
+ return (0); \
+ }
+DOUINTCONV(GAEAMETH_HASHBUF_)
+
+static PyObject *gaeameth_hashstrz(PyObject *me, PyObject *arg)
+{
+ char *p;
+ if (!PyArg_ParseTuple(arg, "s:hashstrz", &p)) return (0);
+ if (gaeadaad_hash(me, p, strlen(p) + 1)) return (0);
+ RETURN_ME;
+}
+
+static PyMethodDef gaeadaad_pymethods[] = {
+#define METHNAME(name) gaeameth_##name
+ METH (copy, "AAD.copy() -> AAD'")
+ METH (hash, "AAD.hash(H)")
+#define METHU_(n, W, w) METH(hashu##w, "AAD.hashu" #w "(WORD)")
+ DOUINTCONV(METHU_)
+#undef METHU_
+#define METHBUF_(n, W, w) METH(hashbuf##w, "AAD.hashbuf" #w "(BYTES)")
+ DOUINTCONV(METHBUF_)
+#undef METHBUF_
+ METH (hashstrz, "AAD.hashstrz(STRING)")
+#undef METHNAME
+ { 0 }
+};
+
+PyObject *gaeadenc_pywrap(PyObject *cobj, gaead_enc *e, unsigned f,
+ size_t hsz, size_t msz, size_t tsz)
+{
+ gaeadenc_pyobj *ge;
+
+ assert(cobj); Py_INCREF(cobj);
+ ge = PyObject_NEW(gaeadenc_pyobj, (PyTypeObject *)cobj);
+ ge->e = e; ge->f = f; ge->hsz = hsz; ge->msz = msz; ge->tsz = tsz;
+ ge->aad = 0; ge->mlen = 0;
+ return ((PyObject *)ge);
+}
+
+static void gaeadenc_pydealloc(PyObject *me)
+{
+ gaeadenc_pyobj *ge = (gaeadenc_pyobj *)me;
+
+ gaea_sever(&ge->aad); GAEAD_DESTROY(ge->e);
+ Py_DECREF(me->ob_type); FREEOBJ(me);
+}
+
+static PyObject *gaeeget_hsz(PyObject *me, void *hunoz)
+{
+ if (GAEADENC_F(me)&AEADF_PCHSZ) return getulong(GAEADENC_HSZ(me));
+ else RETURN_NONE;
+}
+
+static PyObject *gaeeget_msz(PyObject *me, void *hunoz)
+{
+ if (GAEADENC_F(me)&AEADF_PCMSZ) return getulong(GAEADENC_MSZ(me));
+ else RETURN_NONE;
+}
+
+static PyObject *gaeeget_tsz(PyObject *me, void *hunoz)
+{
+ if (GAEADENC_F(me)&AEADF_PCTSZ) return getulong(GAEADENC_TSZ(me));
+ else RETURN_NONE;
+}
+
+static PyObject *gaeeget_mlen(PyObject *me, void *hunoz)
+ { return getulong(GAEADENC_MLEN(me)); }
+
+static PyGetSetDef gaeadenc_pygetset[] = {
+#define GETSETNAME(op, name) gaee##op##_##name
+ GET (hsz, "ENC.hsz -> precommitted header length or `None'")
+ GET (msz, "ENC.msz -> precommitted message length or `None'")
+ GET (tsz, "ENC.tsz -> precommitted tag length or `None'")
+ GET (mlen, "ENC.mlen -> message length so far")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *gaeemeth_aad(PyObject *me, PyObject *arg)
+{
+ gaeadenc_pyobj *ge = (gaeadenc_pyobj *)me;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, ":aad")) return (0);
+ if (!(ge->f&AEADF_AADNDEP))
+ rc = gaeadaad_pywrap((PyObject *)GCAEADENC_KEY(ge->ob_type)->aad,
+ GAEAD_AAD(ge->e), 0, 0);
+ else {
+ if ((ge->f&AEADF_AADFIRST) && ge->mlen)
+ VALERR("too late for aad");
+ if (!ge->aad)
+ ge->aad = (gaeadaad_pyobj *)
+ gaeadaad_pywrap((PyObject *)GCAEADENC_KEY(ge->ob_type)->aad,
+ GAEAD_AAD(ge->e), ge->f&AEADF_PCHSZ, ge->hsz);
+ Py_INCREF(ge->aad);
+ rc = (PyObject *)ge->aad;
+ }
+end:
+ return (rc);
+}
+
+static PyObject *gaeemeth_reinit(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { "nonce", "hsz", "msz", "tsz", 0 };
+ gaeadenc_pyobj *ge = (gaeadenc_pyobj *)me;
+ char *n; Py_ssize_t nsz;
+ PyObject *hszobj = Py_None, *mszobj = Py_None, *tszobj = Py_None;
+ size_t hsz = 0, msz = 0, tsz = 0;
+ unsigned f;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|OOO:enc", KWLIST,
+ &n, &nsz, &hszobj, &mszobj, &tszobj))
+ goto end;
+ if (check_aead_encdec(ge->e->ops->c, &f, nsz,
+ hszobj, &hsz, mszobj, &msz, tszobj, &tsz))
+ goto end;
+ if (GAEAD_REINIT(ge->e, n, nsz, hsz, msz, tsz))
+ VALERR("bad aead parameter combination");
+ gaea_sever(&ge->aad);
+ ge->f = f; ge->hsz = hsz; ge->msz = msz; ge->tsz = tsz;
+end:
+ return (0);
+}
+
+static PyObject *gaeemeth_encrypt(PyObject *me, PyObject *arg)
+{
+ gaeadenc_pyobj *ge = (gaeadenc_pyobj *)me;
+ char *m; Py_ssize_t msz;
+ char *c = 0; size_t csz; buf b;
+ int err;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#:encrypt", &m, &msz)) goto end;
+ if (ge->f&AEADF_AADFIRST) {
+ if ((ge->f&AEADF_PCHSZ) && (ge->aad ? ge->aad->hlen : 0) != ge->hsz)
+ VALERR("header doesn't match precommitted length");
+ gaea_invalidate(ge->aad);
+ }
+ if ((ge->f&AEADF_PCMSZ) && msz > ge->msz - ge->mlen)
+ VALERR("too large for precommitted message length");
+ csz = msz + ge->e->ops->c->bufsz; c = xmalloc(csz); buf_init(&b, c, csz);
+ err = GAEAD_ENCRYPT(ge->e, m, msz, &b); assert(!err); (void)err;
+ buf_flip(&b); rc = bytestring_pywrapbuf(&b); ge->mlen += msz;
+end:
+ xfree(c);
+ return (rc);
+}
+
+static PyObject *gaeemeth_done(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { "tsz", "aad", 0 };
+ gaeadenc_pyobj *ge = (gaeadenc_pyobj *)me;
+ PyObject *aad = Py_None;
+ char *c = 0; size_t csz; buf b;
+ PyObject *tszobj = Py_None; PyObject *tag; size_t tsz;
+ int err;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OO:done", KWLIST,
+ &tszobj, &aad))
+ goto end;
+ if (tszobj != Py_None && !convszt(tszobj, &tsz)) goto end;
+ if (aad != Py_None &&
+ !PyObject_TypeCheck(aad,
+ (PyTypeObject *)GCAEADENC_KEY(me->ob_type)->aad))
+ TYERR("wanted aad");
+ if ((ge->f&AEADF_AADNDEP) && aad != Py_None && aad != (PyObject *)ge->aad)
+ VALERR("mismatched aad");
+ if ((ge->f&AEADF_PCHSZ) &&
+ (aad == Py_None ? 0 : GAEADAAD_HLEN(aad)) != ge->hsz)
+ VALERR("header doesn't match precommitted length");
+ if ((ge->f&AEADF_PCMSZ) && ge->mlen != ge->msz)
+ VALERR("message doesn't match precommitted length");
+ if (tszobj == Py_None) {
+ if (ge->f&AEADF_PCTSZ) tsz = ge->tsz;
+ else tsz = keysz(0, ge->e->ops->c->tagsz);
+ } else {
+ if ((ge->f&AEADF_PCTSZ) && tsz != ge->tsz)
+ VALERR("tag length doesn't match precommitted value");
+ if (keysz(tsz, ge->e->ops->c->tagsz) != tsz) VALERR("bad tag length");
+ }
+ csz = ge->e->ops->c->bufsz; c = xmalloc(csz); buf_init(&b, c, csz);
+ tag = bytestring_pywrap(0, tsz);
+ err = GAEAD_DONE(ge->e, aad == Py_None ? 0 : GAEADAAD_A(aad), &b,
+ PyString_AS_STRING(tag), tsz);
+ assert(!err); (void)err;
+ buf_flip(&b); rc = Py_BuildValue("NN", bytestring_pywrapbuf(&b), tag);
+end:
+ xfree(c);
+ return (rc);
+}
+
+static PyMethodDef gaeadenc_pymethods[] = {
+#define METHNAME(name) gaeemeth_##name
+ METH (aad, "ENC.aad() -> AAD")
+ KWMETH(reinit, "ENC.reinit(NONCE, [hsz], [msz], [tsz])")
+ METH (encrypt, "ENC.encrypt(MSG) -> CT")
+ KWMETH(done, "ENC.done([tsz], [aad]) -> CT, TAG")
+#undef METHNAME
+ { 0 }
+};
+
+PyObject *gaeaddec_pywrap(PyObject *cobj, gaead_dec *d, unsigned f,
+ size_t hsz, size_t csz, size_t tsz)
+{
+ gaeaddec_pyobj *gd;
+ assert(cobj); Py_INCREF(cobj);
+ gd = PyObject_NEW(gaeaddec_pyobj, (PyTypeObject *)cobj);
+ gd->d = d; gd->f = f; gd->hsz = hsz; gd->csz = csz; gd->tsz = tsz;
+ gd->aad = 0; gd->clen = 0;
+ return ((PyObject *)gd);
+}
+
+static void gaeaddec_pydealloc(PyObject *me)
+{
+ gaeaddec_pyobj *gd = (gaeaddec_pyobj *)me;
+
+ gaea_sever(&gd->aad); GAEAD_DESTROY(GAEADDEC_D(me));
+ Py_DECREF(me->ob_type); FREEOBJ(me);
+}
+
+static PyObject *gaedget_hsz(PyObject *me, void *hunoz)
+{
+ if (GAEADDEC_F(me)&AEADF_PCHSZ) return getulong(GAEADDEC_HSZ(me));
+ else RETURN_NONE;
+}
+
+static PyObject *gaedget_csz(PyObject *me, void *hunoz)
+{
+ if (GAEADDEC_F(me)&AEADF_PCMSZ) return getulong(GAEADDEC_CSZ(me));
+ else RETURN_NONE;
+}
+
+static PyObject *gaedget_tsz(PyObject *me, void *hunoz)
+{
+ if (GAEADDEC_F(me)&AEADF_PCTSZ) return getulong(GAEADDEC_TSZ(me));
+ else RETURN_NONE;
+}
+
+static PyObject *gaedget_clen(PyObject *me, void *hunoz)
+ { return getulong(GAEADDEC_CLEN(me)); }
+
+static PyGetSetDef gaeaddec_pygetset[] = {
+#define GETSETNAME(op, name) gaed##op##_##name
+ GET (hsz, "DEC.hsz -> precommitted header length or `None'")
+ GET (csz, "DEC.csz -> precommitted ciphertext length or `None'")
+ GET (tsz, "DEC.tsz -> precommitted tag length or `None'")
+ GET (clen, "DEC.clen -> ciphertext length so far")
+#undef GETSETNAME
+ { 0 }
+};
+
+static PyObject *gaedmeth_aad(PyObject *me, PyObject *arg)
+{
+ gaeaddec_pyobj *gd = (gaeaddec_pyobj *)me;
+
+ if (!PyArg_ParseTuple(arg, ":aad")) return (0);
+ if (!(gd->f&AEADF_AADNDEP))
+ return (gaeadaad_pywrap((PyObject *)GCAEADDEC_KEY(gd->ob_type)->aad,
+ GAEAD_AAD(gd->d), 0, 0));
+ else {
+ if (!gd->aad)
+ gd->aad = (gaeadaad_pyobj *)
+ gaeadaad_pywrap((PyObject *)GCAEADENC_KEY(gd->ob_type)->aad,
+ GAEAD_AAD(gd->d), gd->f&AEADF_PCHSZ, gd->hsz);
+ Py_INCREF(gd->aad);
+ return ((PyObject *)gd->aad);
+ }
+}
+
+static PyObject *gaedmeth_reinit(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { "nonce", "hsz", "csz", "tsz", 0 };
+ gaeaddec_pyobj *gd = (gaeaddec_pyobj *)me;
+ char *n; Py_ssize_t nsz;
+ PyObject *hszobj = Py_None, *cszobj = Py_None, *tszobj = Py_None;
+ size_t hsz = 0, csz = 0, tsz = 0;
+ unsigned f;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|OOO:enc", KWLIST,
+ &n, &nsz, &hszobj, &cszobj, &tszobj))
+ goto end;
+ if (check_aead_encdec(gd->d->ops->c, &f, nsz,
+ hszobj, &hsz, cszobj, &csz, tszobj, &tsz))
+ goto end;
+ if (GAEAD_REINIT(gd->d, n, nsz, hsz, csz, tsz))
+ VALERR("bad aead parameter combination");
+ gaea_sever(&gd->aad);
+ gd->f = f; gd->hsz = hsz; gd->csz = csz; gd->tsz = tsz;
+end:
+ return (0);
+}
+
+static PyObject *gaedmeth_decrypt(PyObject *me, PyObject *arg)
+{
+ gaeaddec_pyobj *gd = (gaeaddec_pyobj *)me;
+ char *c; Py_ssize_t csz;
+ char *m = 0; size_t msz; buf b;
+ int err;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTuple(arg, "s#:decrypt", &c, &csz)) goto end;
+ if (gd->f&AEADF_AADFIRST) {
+ if ((gd->f&AEADF_PCHSZ) && (gd->aad ? gd->aad->hlen : 0) != gd->hsz)
+ VALERR("header doesn't match precommitted length");
+ gaea_invalidate(gd->aad);
+ }
+ if ((gd->f&AEADF_PCMSZ) && csz > gd->csz - gd->clen)
+ VALERR("too large for precommitted message length");
+ msz = csz + gd->d->ops->c->bufsz; m = xmalloc(msz); buf_init(&b, m, msz);
+ err = GAEAD_DECRYPT(gd->d, c, csz, &b); assert(!err); (void)err;
+ buf_flip(&b); rc = bytestring_pywrapbuf(&b); gd->clen += csz;
+end:
+ xfree(m);
+ return (rc);
+}
+
+static PyObject *gaedmeth_done(PyObject *me, PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { "tag", "aad", 0 };
+ gaeaddec_pyobj *gd = (gaeaddec_pyobj *)me;
+ PyObject *aad = Py_None;
+ char *t; Py_ssize_t tsz;
+ char *m = 0; size_t msz; buf b;
+ int err;
+ PyObject *rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O:done", KWLIST,
+ &t, &tsz, &aad))
+ goto end;
+ if (aad != Py_None &&
+ !PyObject_TypeCheck(aad,
+ (PyTypeObject *)GCAEADENC_KEY(me->ob_type)->aad))
+ TYERR("wanted aad");
+ if ((gd->f&AEADF_AADNDEP) && aad != Py_None && aad != (PyObject *)gd->aad)
+ VALERR("mismatched aad");
+ if ((gd->f&AEADF_PCHSZ) &&
+ (aad == Py_None ? 0 : GAEADAAD_HLEN(aad)) != gd->hsz)
+ VALERR("header doesn't match precommitted length");
+ if ((gd->f&AEADF_PCMSZ) && gd->clen != gd->csz)
+ VALERR("message doesn't match precommitted length");
+ if ((gd->f&AEADF_PCTSZ) && tsz != gd->tsz)
+ VALERR("tag length doesn't match precommitted value");
+ if (keysz(tsz, gd->d->ops->c->tagsz) != tsz) VALERR("bad tag length");
+ msz = gd->d->ops->c->bufsz; m = xmalloc(msz); buf_init(&b, m, msz);
+ err = GAEAD_DONE(gd->d, aad == Py_None ? 0 : GAEADAAD_A(aad), &b, t, tsz);
+ assert(err >= 0);
+ if (!err) VALERR("decryption failed");
+ buf_flip(&b); rc = bytestring_pywrapbuf(&b);
+end:
+ xfree(m);
+ return (rc);
+}
+
+static PyMethodDef gaeaddec_pymethods[] = {
+#define METHNAME(name) gaedmeth_##name
+ METH (aad, "DEC.aad() -> AAD")
+ KWMETH(reinit, "DEC.reinit(NONCE, [hsz], [csz], [tsz])")
+ METH (decrypt, "DEC.decrypt(CT) -> MSG")
+ KWMETH(done, "DEC.done(TAG, [aad]) -> MSG | None")
+#undef METHNAME
+ { 0 }
+};
+
+static PyTypeObject gcaead_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GCAEAD", /* @tp_name@ */
+ sizeof(gcaead_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@ */
+"Authenticated encryption (key) metaclass.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gcaead_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 gaeadkey_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GAEKey", /* @tp_name@ */
+ sizeof(gaeadkey_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gaeadkey_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@ */
+"Authenticated encryption key.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ gaeadkey_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@ */
+ abstract_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gcaeadaad_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GAEAADClass", /* @tp_name@ */
+ sizeof(gcaeadaad_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@ */
+"Authenticated encryption additional-data hash metaclass.",
+
+ 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@ */
+ abstract_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gaeadaad_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GAEAAD", /* @tp_name@ */
+ sizeof(gaeadaad_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gaeadaad_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@ */
+"Authenticated encryption AAD hash.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ gaeadaad_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gaeadaad_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 gcaeadenc_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GAEEncClass", /* @tp_name@ */
+ sizeof(gcaeadenc_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@ */
+"Authenticated encryption operation metaclass.",
+
+ 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@ */
+ abstract_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gaeadenc_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GAEEnc", /* @tp_name@ */
+ sizeof(gaeadenc_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gaeadenc_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@ */
+"Authenticated encryption operation.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ gaeadenc_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gaeadenc_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 gcaeaddec_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GAEDecClass", /* @tp_name@ */
+ sizeof(gcaeaddec_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@ */
+"Authenticated decryption operation metaclass.",
+
+ 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@ */
+ abstract_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
+static PyTypeObject gaeaddec_pytype_skel = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "GAEDec", /* @tp_name@ */
+ sizeof(gaeaddec_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ gaeaddec_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@ */
+"Authenticated decryption operation.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ gaeaddec_pymethods, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ gaeaddec_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@ */
+};
+
/*----- Hash functions ----------------------------------------------------*/
PyTypeObject *gchash_pytype, *ghash_pytype;
static PyObject *ghash_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist))
+ static const char *const kwlist[] = { 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST))
goto end;
- return (ghash_pywrap((PyObject *)ty, GH_INIT(GCHASH_CH(ty)), f_freeme));
+ return (ghash_pywrap((PyObject *)ty, GH_INIT(GCHASH_CH(ty))));
end:
return (0);
}
return ((PyObject *)g);
}
-PyObject *ghash_pywrap(PyObject *cobj, ghash *h, unsigned f)
+PyObject *ghash_pywrap(PyObject *cobj, ghash *h)
{
ghash_pyobj *g;
if (!cobj) cobj = gchash_pywrap((/*unconst*/ gchash *)GH_CLASS(h));
else Py_INCREF(cobj);
g = PyObject_NEW(ghash_pyobj, (PyTypeObject *)cobj);
g->h = h;
- g->f = f;
return ((PyObject *)g);
}
static void ghash_pydealloc(PyObject *me)
{
- if (GHASH_F(me) & f_freeme)
- GH_DESTROY(GHASH_H(me));
+ GH_DESTROY(GHASH_H(me));
Py_DECREF(me->ob_type);
FREEOBJ(me);
}
static PyObject *gchget_bufsz(PyObject *me, void *hunoz)
{ return (PyInt_FromLong(GCHASH_CH(me)->bufsz)); }
+static PyObject *ghmeth_copy(PyObject *me, PyObject *arg)
+{
+ if (!PyArg_ParseTuple(arg, ":copy")) return (0);
+ return (ghash_pywrap((PyObject *)me->ob_type, GH_COPY(GHASH_H(me))));
+}
+
static PyObject *ghmeth_hash(PyObject *me, PyObject *arg)
{
char *p;
static PyObject *ghmeth_hashu##w(PyObject *me, PyObject *arg) \
{ \
uint##n x; \
- if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \
+ if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) return (0); \
GH_HASHU##W(GHASH_H(me), x); \
RETURN_ME; \
- end: \
- return (0); \
}
DOUINTCONV(GHMETH_HASHU_)
static PyMethodDef ghash_pymethods[] = {
#define METHNAME(name) ghmeth_##name
+ METH (copy, "H.copy() -> HH")
METH (hash, "H.hash(M)")
#define METHU_(n, W, w) METH(hashu##w, "H.hashu" #w "(WORD)")
DOUINTCONV(METHU_)
static PyObject *gmac_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "k", 0 };
+ static const char *const kwlist[] = { "k", 0 };
char *k;
Py_ssize_t sz;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &k, &sz))
goto end;
if (keysz(sz, GCMAC_CM(ty)->keysz) != sz) VALERR("bad key length");
return (gmac_pywrap((PyObject *)ty,
- GM_KEY(GCMAC_CM(ty), k, sz),
- f_freeme));
+ GM_KEY(GCMAC_CM(ty), k, sz)));
end:
return (0);
}
static PyObject *gmhash_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { 0 };
+ static const char *const kwlist[] = { 0 };
ghash_pyobj *g;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) return (0);
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) return (0);
g = PyObject_NEW(ghash_pyobj, ty);
g->h = GM_INIT(GMAC_M(ty));
- g->f = f_freeme;
Py_INCREF(ty);
return ((PyObject *)g);
}
return ((PyObject *)g);
}
-PyObject *gmac_pywrap(PyObject *cobj, gmac *m, unsigned f)
+PyObject *gmac_pywrap(PyObject *cobj, gmac *m)
{
gmac_pyobj *g;
if (!cobj) cobj = gcmac_pywrap((/*unconst*/ gcmac *)GM_CLASS(m));
g->ty.ht_type.tp_new = gmhash_pynew;
typeready(&g->ty.ht_type);
g->m = m;
- g->f = f;
return ((PyObject *)g);
}
static void gmac_pydealloc(PyObject *me)
{
- if (GMAC_F(me) & f_freeme)
- GM_DESTROY(GMAC_M(me));
+ GM_DESTROY(GMAC_M(me));
Py_DECREF(me->ob_type);
PyType_Type.tp_dealloc(me);
}
static PyObject *poly1305hash_pynew(PyTypeObject *ty,
PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "mask", 0 };
+ static const char *const kwlist[] = { "mask", 0 };
poly1305key_pyobj *pk = (poly1305key_pyobj *)ty;
poly1305hash_pyobj *ph;
char *m = 0;
Py_ssize_t sz;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#:new", kwlist, &m, &sz))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#:new", KWLIST, &m, &sz))
return (0);
if (m && sz != POLY1305_MASKSZ) VALERR("bad mask length");
ph = PyObject_NEW(poly1305hash_pyobj, ty);
static PyObject *poly1305key_pynew(PyTypeObject *ty,
PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "k", 0 };
+ static const char *const kwlist[] = { "k", 0 };
poly1305key_pyobj *pk;
char *k;
Py_ssize_t sz;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &k, &sz))
goto end;
if (keysz(sz, poly1305_keysz) != sz) VALERR("bad key length");
{ \
uint##n x; \
octet b[SZ_##W]; \
- if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \
+ if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) return (0); \
STORE##W(b, x); poly1305_hash(P1305_CTX(me), b, sizeof(b)); \
RETURN_ME; \
- end: \
- return (0); \
}
DOUINTCONV(POLYMETH_HASHU_)
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Poly1305 key.",
+"poly1305(K): Poly1305 key.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
unsigned n = 24;
kxvik_pyobj *rc = 0;
- char *kwlist[] = { "nround", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist,
+ static const char *const kwlist[] = { "nround", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", KWLIST,
convuint, &n))
goto end;
rc = (kxvik_pyobj *)ty->tp_alloc(ty, 0);
return ((PyObject *)rc);
}
+static PyObject *kxvikmeth_copy(PyObject *me, PyObject *arg)
+{
+ kxvik_pyobj *k = (kxvik_pyobj *)me, *rc = 0;
+ if (!PyArg_ParseTuple(arg, ":copy")) goto end;
+ rc = (kxvik_pyobj *)k->ob_type->tp_alloc(k->ob_type, 0);
+ rc->s = k->s; rc->n = k->n;
+end:
+ return ((PyObject *)rc);
+}
+
static PyObject *kxvikmeth_mix(PyObject *me, PyObject *arg)
{
kxvik_pyobj *k = (kxvik_pyobj *)me;
static PyMethodDef kxvik_pymethods[] = {
#define METHNAME(func) kxvikmeth_##func
+ METH (copy, "KECCAK.copy() -> KECCAK'")
METH (mix, "KECCAK.mix(DATA)")
METH (extract, "KECCAK.extract(NOCTETS)")
METH (step, "KECCAK.step()")
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Keccak-p[1600, n] state.",
+"Keccak1600([nround = 24]): Keccak-p[1600, n] state.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
shake_pyobj *rc = 0;
char *p = 0, *f = 0;
Py_ssize_t psz = 0, fsz = 0;
- char *kwlist[] = { "perso", "func", 0 };
+ static const char *const kwlist[] = { "perso", "func", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#s#:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#s#:new", KWLIST,
&p, &psz, &f, &fsz))
goto end;
rc = (shake_pyobj *)ty->tp_alloc(ty, 0);
{ \
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; \
+ if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) return (0); \
+ if (shake_check(me, 0)) return (0); \
STORE##W(b, x); shake_hash(SHAKE_H(me), b, sizeof(b)); \
RETURN_ME; \
- end: \
- return (0); \
}
DOUINTCONV(SHAKEMETH_HASHU_)
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"SHAKE128/cSHAKE128 XOF.",
+"Shake128([perso = STR], [func = STR]): SHAKE128/cSHAKE128 XOF.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"SHAKE256/cSHAKE256 XOF.",
+"Shake256([perso = STR], [func = STR]): SHAKE256/cSHAKE256 XOF.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *gprp_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "key", 0 };
+ static const char *const kwlist[] = { "key", 0 };
char *k;
Py_ssize_t sz;
const prpinfo *prp = GCPRP_PRP(ty);
PyObject *me;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &k, &sz))
goto end;
if (keysz(sz, prp->keysz) != sz) VALERR("bad key length");
me = (PyObject *)ty->tp_alloc(ty, 0);
INITTYPE(keyszset, keysz);
INITTYPE(gccipher, type);
INITTYPE(gcipher, root);
+ INITTYPE(gcaead, type);
+ INITTYPE(gaeadkey, root);
+ INITTYPE(gcaeadaad, type);
+ INITTYPE(gaeadaad, root);
+ INITTYPE(gcaeadenc, type);
+ INITTYPE(gaeadenc, root);
+ INITTYPE(gcaeaddec, type);
+ INITTYPE(gaeaddec, root);
INITTYPE(gchash, type);
INITTYPE(ghash, root);
INITTYPE(gcmac, type);
}
GEN(gcciphers, cipher)
+GEN(gcaeads, aead)
GEN(gchashes, hash)
GEN(gcmacs, mac)
#define gcprp prpinfo
INSERT("GCCipher", gccipher_pytype);
INSERT("GCipher", gcipher_pytype);
INSERT("gcciphers", gcciphers());
+ INSERT("GCAEAD", gcaead_pytype);
+ INSERT("GAEKey", gaeadkey_pytype);
+ INSERT("GAEAADClass", gcaeadaad_pytype);
+ INSERT("GAEAAD", gaeadaad_pytype);
+ INSERT("GAEEncClass", gcaeadenc_pytype);
+ INSERT("GAEEnc", gaeadenc_pytype);
+ INSERT("GAEDecClass", gcaeaddec_pytype);
+ INSERT("GAEDec", gaeaddec_pytype);
+ INSERT("gcaeads", gcaeads());
INSERT("GCHash", gchash_pytype);
INSERT("GHash", ghash_pytype);
INSERT("gchashes", d = gchashes());
'''.split()
pmodes = '''
ecb cbc cfb ofb counter
+cmac pmac1
+ccm eax gcm ocb1 ocb3
'''.split()
streamciphers = '''
rc4 seal
char *p, *q;
Py_ssize_t n;
buf_pyobj *me = 0;
- static char *kwlist[] = { "data", 0 };
+ static const char *const kwlist[] = { "data", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &p, &n))
goto end;
q = xmalloc(n);
memcpy(q, p, n);
static PyObject *rbmeth_getecpt(PyObject *me, PyObject *arg, PyObject *kw)
{
PyObject *cobj = Py_None;
- static char *kwlist[] = { "curve", 0 };
+ static const char *const kwlist[] = { "curve", 0 };
ec pt = EC_INIT;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:getecpt", kwlist, &cobj))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:getecpt", KWLIST, &cobj))
goto end;
if (cobj == Py_None) cobj = (PyObject *)ecpt_pytype;
if (!PyType_Check(cobj) ||
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "A read buffer.",
+"ReadBuffer(STR): a read buffer.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
char *p;
size_t n = 64;
buf_pyobj *me = 0;
- static char *kwlist[] = { "size", 0 };
+ static const char *const kwlist[] = { "size", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", KWLIST,
convszt, &n))
goto end;
me = (buf_pyobj *)ty->tp_alloc(ty, 0);
static PyObject *wbget_size(PyObject *me, void *hunoz)
{ return (PyInt_FromLong(BLEN(BUF_B(me)))); }
+static PyObject *wbget_contents(PyObject *me, void *hunoz)
+ { return (bytestring_pywrap(BBASE(BUF_B(me)), BLEN(BUF_B(me)))); }
+
static PyGetSetDef wbuf_pygetset[] = {
#define GETSETNAME(op, name) wb##op##_##name
GET (size, "WBUF.size -> SIZE")
+ GET (contents, "WBUF.contents -> STR")
#undef GETSETNAME
{ 0 }
};
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "A write buffer.",
+"WriteBuffer([size = ?]): a write buffer.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
PyTypeObject *bytestring_pytype;
-static PyObject *dowrap(PyTypeObject *ty, const void *p, size_t n)
+static PyObject *empty, *bytev[256];
+
+static PyObject *allocate(PyTypeObject *ty, size_t n)
{
- PyStringObject *x = (PyStringObject *)ty->tp_alloc(ty, n);
- if (p) memcpy(x->ob_sval, p, n);
+ PyStringObject *x;
+ x = (PyStringObject *)ty->tp_alloc(ty, n);
x->ob_sval[n] = 0;
#if defined(CACHE_HASH) || PY_VERSION_HEX >= 0x02030000
x->ob_shash = -1;
return ((PyObject *)x);
}
+static PyObject *dowrap(PyTypeObject *ty, const void *p, size_t n)
+{
+ PyObject *x;
+ int ch;
+
+ if (p && ty == bytestring_pytype) {
+ if (!n) {
+ if (!empty) empty = allocate(ty, 0);
+ Py_INCREF(empty); return (empty);
+ } else if (n == 1 && (ch = *(unsigned char *)p) < sizeof(bytev)) {
+ if (!bytev[ch])
+ { bytev[ch] = allocate(ty, 1); *PyString_AS_STRING(bytev[ch]) = ch; }
+ Py_INCREF(bytev[ch]); return (bytev[ch]);
+ }
+ }
+
+ x = allocate(ty, n);
+ if (p) memcpy(PyString_AS_STRING(x), p, n);
+ return (x);
+}
+
PyObject *bytestring_pywrap(const void *p, size_t n)
{ return (dowrap(bytestring_pytype, p, n)); }
{
const char *p;
Py_ssize_t n;
- static char *kwlist[] = { "data", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n))
+ static const char *const kwlist[] = { "data", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &p, &n))
return (0);
return (dowrap(ty, p, n));
}
else RETURN_FALSE;
}
+static PyObject *bytestring_pyconcat(PyObject *x, PyObject *y)
+{
+ const void *xv; Py_ssize_t xsz;
+ const void *yv; Py_ssize_t ysz;
+ PyObject *z = 0; char *zp; size_t zsz;
+
+ if (PyObject_AsReadBuffer(x, &xv, &xsz) ||
+ PyObject_AsReadBuffer(y, &yv, &ysz))
+ goto end;
+ zsz = (size_t)xsz + (size_t)ysz;
+ if (xsz < 0 || ysz < 0 || zsz < xsz) VALERR("too long");
+ z = bytestring_pywrap(0, zsz); zp = PyString_AS_STRING(z);
+ memcpy(zp, xv, xsz); memcpy(zp + xsz, yv, ysz);
+end:
+ return (z);
+}
+
+static PyObject *bytestring_pyrepeat(PyObject *me, Py_ssize_t n)
+{
+ const unsigned char *xp; size_t xsz;
+ PyObject *z = 0; char *zp; size_t zsz;
+
+ xp = (const unsigned char *)PyString_AS_STRING(me);
+ xsz = PyString_GET_SIZE(me);
+ if (n < 0 || (n && xsz >= (size_t)-1/n)) VALERR("too long");
+ zsz = n*xsz; z = bytestring_pywrap(0, zsz); zp = PyString_AS_STRING(z);
+ if (xsz == 1) memset(zp, *xp, zsz);
+ else while (zsz) { memcpy(zp, xp, xsz); zp += xsz; zsz -= xsz; }
+end:
+ return (z);
+}
+
+static PyObject *bytestring_pyitem(PyObject *me, Py_ssize_t i)
+{
+ PyObject *rc = 0;
+
+ if (i < 0 || i >= PyString_GET_SIZE(me)) IXERR("out of range");
+ rc = bytestring_pywrap(PyString_AS_STRING(me) + i, 1);
+end:
+ return (rc);
+}
+
+static PyObject *bytestring_pyslice(PyObject *me, Py_ssize_t i, Py_ssize_t j)
+{
+ PyObject *rc = 0;
+ size_t n = PyString_GET_SIZE(me);
+
+ if (i < 0) i = 0;
+ if (j < 0) j = 0;
+ else if (j > n) j = n;
+ if (j < i) i = j = 0;
+ if (i == 0 && j == n && me->ob_type == bytestring_pytype)
+ { Py_INCREF(me); rc = me; goto end; }
+ rc = bytestring_pywrap(PyString_AS_STRING(me) + i, j - i);
+end:
+ return (rc);
+}
+
+static PyObject *bytestring_pysubscript(PyObject *me, PyObject *ix)
+{
+ Py_ssize_t i, j, k, n;
+ const unsigned char *p;
+ unsigned char *q;
+ PyObject *rc = 0;
+
+ if (PyIndex_Check(ix)) {
+ i = PyNumber_AsSsize_t(ix, PyExc_IndexError);
+ if (i == -1 && PyErr_Occurred()) return (0);
+ if (i < 0) i += PyString_GET_SIZE(me);
+ rc = bytestring_pyitem(me, i);
+ } else if (PySlice_Check(ix)) {
+ if (PySlice_GetIndicesEx((PySliceObject *)ix, PyString_GET_SIZE(me),
+ &i, &j, &k, &n))
+ return (0);
+ if (k == 1) return bytestring_pyslice(me, i, j);
+ rc = bytestring_pywrap(0, n);
+ p = (unsigned char *)PyString_AS_STRING(me) + i;
+ q = (unsigned char *)PyString_AS_STRING(rc);
+ while (n--) { *q++ = *p; p += k; }
+ } else
+ TYERR("wanted integer or slice");
+end:
+ return (rc);
+}
+
#define BINOP(name, op) \
static PyObject *bytestring_py##name(PyObject *x, PyObject *y) { \
const void *xv, *yv; \
0, /* @nb_hex@ */
};
+static PySequenceMethods bytestring_pysequence = {
+ 0, /* @sq_length@ */
+ bytestring_pyconcat, /* @sq_concat@ */
+ bytestring_pyrepeat, /* @sq_repeat@ */
+ bytestring_pyitem, /* @sq_item@ */
+ bytestring_pyslice, /* @sq_slice@ */
+ 0, /* @sq_ass_item@ */
+ 0, /* @sq_ass_slice@ */
+ 0, /* @sq_contains@ */
+ 0, /* @sq_inplace_concat@ */
+ 0, /* @sq_inplace_repeat@ */
+};
+
+static PyMappingMethods bytestring_pymapping = {
+ 0, /* @mp_length@ */
+ bytestring_pysubscript, /* @mp_subscript@ */
+ 0, /* @mp_ass_subscript@ */
+};
+
static PyBufferProcs bytestring_pybuffer;
static PyTypeObject bytestring_pytype_skel = {
0, /* @tp_compare@ */
0, /* @tp_repr@ */
&bytestring_pynumber, /* @tp_as_number@ */
- 0, /* @tp_as_sequence@ */
- 0, /* @tp_as_mapping@ */
+ &bytestring_pysequence, /* @tp_as_sequence@ */
+ &bytestring_pymapping, /* @tp_as_mapping@ */
0, /* @tp_hash@ */
0, /* @tp_call@ */
0, /* @tp_str@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Byte string class.",
+"ByteString(STR): byte string class.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
#include <catacomb/blkc.h>
#include <catacomb/gcipher.h>
+#include <catacomb/gaead.h>
#include <catacomb/ghash.h>
#include <catacomb/gmac.h>
#include <catacomb/md5.h>
#define VALERR(str) EXCERR(PyExc_ValueError, str)
#define OVFERR(str) EXCERR(PyExc_OverflowError, str)
#define TYERR(str) EXCERR(PyExc_TypeError, str)
+#define IXERR(str) EXCERR(PyExc_IndexError, str)
#define ZDIVERR(str) EXCERR(PyExc_ZeroDivisionError, str)
#define SYSERR(str) EXCERR(PyExc_SystemError, str)
#define NIERR(str) EXCERR(PyExc_NotImplementedError, str)
return (d); \
}
+#define KWLIST (/*unconst*/ char **)kwlist
+
struct nameval { const char *name; unsigned f; unsigned long value; };
#define CF_SIGNED 1u
extern void setconstants(PyObject *, const struct nameval *);
extern PyTypeObject *gccipher_pytype;
#define GCCIPHER_PYCHECK(o) PyObject_TypeCheck((o), gccipher_pytype)
#define GCCIPHER_CC(o) (((gccipher_pyobj *)(o))->cc)
-#define GCCIPHER_F(o) (((gccipher_pyobj *)(o))->f)
extern PyObject *gccipher_pywrap(gccipher *);
extern int convgccipher(PyObject *, void *);
-extern int convgcipher(PyObject *, void *);
typedef struct gcipher_pyobj {
PyObject_HEAD
- unsigned f;
gcipher *c;
} gcipher_pyobj;
extern PyTypeObject *gcipher_pytype;
#define GCIPHER_PYCHECK(o) PyObject_TypeCheck((o), gcipher_pytype)
#define GCIPHER_C(o) (((gcipher_pyobj *)(o))->c)
-#define GCIPHER_F(o) (((gcipher_pyobj *)(o))->f)
-extern PyObject *gcipher_pywrap(PyObject *, gcipher *, unsigned);
+extern PyObject *gcipher_pywrap(PyObject *, gcipher *);
extern int convgcipher(PyObject *, void *);
+typedef struct gcaead_pyobj {
+ PyHeapTypeObject ty;
+ gcaead *aec;
+ struct gcaeadaad_pyobj *aad;
+ struct gcaeadenc_pyobj *enc;
+ struct gcaeaddec_pyobj *dec;
+} gcaead_pyobj;
+
+extern PyTypeObject *gcaead_pytype;
+#define GCAEAD_PYCHECK(o) PyObject_TypeCheck((o), gcaead_pytype)
+#define GCAEAD_AEC(o) (((gcaead_pyobj *)(o))->aec)
+#define GCAEAD_AAD(o) (((gcaead_pyobj *)(o))->aad)
+#define GCAEAD_ENC(o) (((gcaead_pyobj *)(o))->enc)
+#define GCAEAD_DEC(o) (((gcaead_pyobj *)(o))->dec)
+extern PyObject *gcaead_pywrap(gcaead *);
+extern int convgcaead(PyObject *, void *);
+
+typedef struct gaeadkey_pyobj {
+ PyObject_HEAD
+ gaead_key *k;
+} gaeadkey_pyobj;
+
+extern PyTypeObject *gaeadkey_pytype;
+#define GAEADKEY_PYCHECK(o) PyObject_TypeCheck((o), gaeadkey_pytype)
+#define GAEADKEY_K(o) (((gaeadkey_pyobj *)(o))->k)
+extern PyObject *gaeadkey_pywrap(PyObject *, gaead_key *);
+extern int convgaeadkey(PyObject *, void *);
+
+typedef struct gcaeadaad_pyobj {
+ PyHeapTypeObject ty;
+ gcaead_pyobj *key;
+} gcaeadaad_pyobj;
+#define GCAEADAAD_KEY(o) (((gcaeadaad_pyobj *)(o))->key)
+extern PyTypeObject *gcaeadaad_pytype;
+
+typedef struct gaeadaad_pyobj {
+ PyObject_HEAD
+ gaead_aad *a;
+ unsigned f;
+#define AEADF_DEAD 32768u
+ size_t hsz, hlen;
+} gaeadaad_pyobj;
+
+extern PyTypeObject *gaeadaad_pytype;
+#define GAEADAAD_PYCHECK(o) PyObject_TypeCheck((o), gaeadaad_pytype)
+#define GAEADAAD_A(o) (((gaeadaad_pyobj *)(o))->a)
+#define GAEADAAD_F(o) (((gaeadaad_pyobj *)(o))->f)
+#define GAEADAAD_HSZ(o) (((gaeadaad_pyobj *)(o))->hsz)
+#define GAEADAAD_HLEN(o) (((gaeadaad_pyobj *)(o))->hlen)
+extern PyObject *gaeadaad_pywrap(PyObject *, gaead_aad *, unsigned, size_t);
+extern int convgaeadaad(PyObject *, void *);
+
+typedef struct gcaeadenc_pyobj {
+ PyHeapTypeObject ty;
+ gcaead_pyobj *key;
+} gcaeadenc_pyobj;
+#define GCAEADENC_KEY(o) (((gcaeadenc_pyobj *)(o))->key)
+extern PyTypeObject *gcaeadenc_pytype;
+
+typedef struct gaeadenc_pyobj {
+ PyObject_HEAD
+ gaead_enc *e;
+ gaeadaad_pyobj *aad;
+ unsigned f;
+ size_t hsz, msz, tsz;
+ size_t mlen;
+} gaeadenc_pyobj;
+
+extern PyTypeObject *gaeadenc_pytype;
+#define GAEADENC_PYCHECK(o) PyObject_TypeCheck((o), gaeadenc_pytype)
+#define GAEADENC_AAD(o) (((gaeadenc_pyobj *)(o))->aad)
+#define GAEADENC_E(o) (((gaeadenc_pyobj *)(o))->e)
+#define GAEADENC_F(o) (((gaeadenc_pyobj *)(o))->f)
+#define GAEADENC_HSZ(o) (((gaeadenc_pyobj *)(o))->hsz)
+#define GAEADENC_MSZ(o) (((gaeadenc_pyobj *)(o))->msz)
+#define GAEADENC_TSZ(o) (((gaeadenc_pyobj *)(o))->tsz)
+#define GAEADENC_MLEN(o) (((gaeadenc_pyobj *)(o))->mlen)
+extern PyObject *gaeadenc_pywrap(PyObject *, gaead_enc *, unsigned,
+ size_t, size_t, size_t);
+extern int convgaeadenc(PyObject *, void *);
+
+typedef struct gcaeaddec_pyobj {
+ PyHeapTypeObject ty;
+ gcaead_pyobj *key;
+} gcaeaddec_pyobj;
+#define GCAEADDEC_KEY(o) (((gcaeaddec_pyobj *)(o))->key)
+extern PyTypeObject *gcaeaddec_pytype;
+
+typedef struct gaeaddec_pyobj {
+ PyObject_HEAD
+ gaead_dec *d;
+ gaeadaad_pyobj *aad;
+ unsigned f;
+ size_t hsz, csz, tsz;
+ size_t clen;
+} gaeaddec_pyobj;
+
+extern PyTypeObject *gaeaddec_pytype;
+#define GAEADDEC_PYCHECK(o) PyObject_TypeCheck((o), gaeaddec_pytype)
+#define GAEADDEC_AAD(o) (((gaeaddec_pyobj *)(o))->aad)
+#define GAEADDEC_D(o) (((gaeaddec_pyobj *)(o))->d)
+#define GAEADDEC_F(o) (((gaeaddec_pyobj *)(o))->f)
+#define GAEADDEC_HSZ(o) (((gaeaddec_pyobj *)(o))->hsz)
+#define GAEADDEC_CSZ(o) (((gaeaddec_pyobj *)(o))->csz)
+#define GAEADDEC_TSZ(o) (((gaeaddec_pyobj *)(o))->tsz)
+#define GAEADDEC_CLEN(o) (((gaeaddec_pyobj *)(o))->clen)
+extern PyObject *gaeaddec_pywrap(PyObject *, gaead_dec *, unsigned,
+ size_t, size_t, size_t);
+extern int convgaeaddec(PyObject *, void *);
+
typedef struct gchash_pyobj {
PyHeapTypeObject ty;
gchash *ch;
extern PyTypeObject *gchash_pytype;
#define GCHASH_PYCHECK(o) PyObject_TypeCheck((o), gchash_pytype)
#define GCHASH_CH(o) (((gchash_pyobj *)(o))->ch)
-#define GCHASH_F(o) (((gchash_pyobj *)(o))->f)
extern PyObject *gchash_pywrap(gchash *);
extern int convgchash(PyObject *, void *);
typedef struct ghash_pyobj {
PyObject_HEAD
- unsigned f;
ghash *h;
} ghash_pyobj;
extern PyObject *sha_pyobj, *has160_pyobj;
#define GHASH_PYCHECK(o) PyObject_TypeCheck((o), ghash_pytype)
#define GHASH_H(o) (((ghash_pyobj *)(o))->h)
-#define GHASH_F(o) (((ghash_pyobj *)(o))->f)
-extern PyObject *ghash_pywrap(PyObject *, ghash *, unsigned);
+extern PyObject *ghash_pywrap(PyObject *, ghash *);
extern int convghash(PyObject *, void *);
extern int convgmhash(PyObject *, void *);
typedef struct gmac_pyobj {
PyHeapTypeObject ty;
- unsigned f;
gmac *m;
} gmac_pyobj;
#define GMAC_PYCHECK(o) PyObject_TypeCheck((o), gmac_pytype)
#define GMAC_M(o) (((gmac_pyobj *)(o))->m)
#define GMAC_F(o) (((gmac_pyobj *)(o))->f)
-extern PyObject *gmac_pywrap(PyObject *, gmac *, unsigned);
+extern PyObject *gmac_pywrap(PyObject *, gmac *);
extern int convgmac(PyObject *, void *);
/*----- Key generation ----------------------------------------------------*/
C(ED25519_KEYSZ), C(ED25519_PUBSZ), C(ED25519_SIGSZ),
C(ED25519_MAXPERSOSZ),
C(ED448_KEYSZ), C(ED448_PUBSZ), C(ED448_SIGSZ), C(ED448_MAXPERSOSZ),
+ C(AEADF_PCHSZ), C(AEADF_PCMSZ), C(AEADF_PCTSZ),
+ C(AEADF_AADNDEP), C(AEADF_AADFIRST), C(AEADF_NOAAD),
#define ENTRY(tag, val, str) C(KERR_##tag),
KEY_ERRORS(ENTRY)
#undef ENTRY
for j in b:
if j[:plen] == pre:
setattr(c, j[plen:], classmethod(b[j]))
- for i in [gcciphers, gchashes, gcmacs, gcprps]:
+ for i in [gcciphers, gcaeads, gchashes, gcmacs, gcprps]:
for c in i.itervalues():
d[_fixname(c.name)] = c
for c in gccrands.itervalues():
ByteString.__hash__ = str.__hash__
bytes = ByteString.fromhex
+###--------------------------------------------------------------------------
+### Symmetric encryption.
+
+class _tmp:
+ def encrypt(me, n, m, tsz = None, h = ByteString('')):
+ if tsz is None: tsz = me.__class__.tagsz.default
+ e = me.enc(n, len(h), len(m), tsz)
+ if not len(h): a = None
+ else: a = e.aad().hash(h)
+ c0 = e.encrypt(m)
+ c1, t = e.done(aad = a)
+ return c0 + c1, t
+ def decrypt(me, n, c, t, h = ByteString('')):
+ d = me.dec(n, len(h), len(c), len(t))
+ if not len(h): a = None
+ else: a = d.aad().hash(h)
+ m = d.decrypt(c)
+ m += d.done(t, aad = a)
+ return m
+_augment(GAEKey, _tmp)
+
###--------------------------------------------------------------------------
### Hashing.
me.bytepad_after()
_augment(Shake, _tmp)
_augment(_ShakeBase, _tmp)
-Shake._Z = _ShakeBase._Z = ByteString(200*'\0')
+Shake._Z = _ShakeBase._Z = ByteString.zero(200)
class KMAC (_ShakeBase):
_FUNC = 'KMAC'
### NaCl `secretbox'.
def secret_box(k, n, m):
- E = xsalsa20(k).setiv(n)
- r = E.enczero(poly1305.keysz.default)
- s = E.enczero(poly1305.masksz)
- y = E.encrypt(m)
- t = poly1305(r)(s).hash(y).done()
- return ByteString(t + y)
+ y, t = salsa20_naclbox(k).encrypt(n, m)
+ return t + y
def secret_unbox(k, n, c):
- E = xsalsa20(k).setiv(n)
- r = E.enczero(poly1305.keysz.default)
- s = E.enczero(poly1305.masksz)
- y = c[poly1305.tagsz:]
- if not poly1305(r)(s).hash(y).check(c[0:poly1305.tagsz]):
- raise ValueError, 'decryption failed'
- return E.decrypt(c[poly1305.tagsz:])
+ tsz = poly1305.tagsz
+ return salsa20_naclbox(k).decrypt(n, c[tsz:], c[0:tsz])
###--------------------------------------------------------------------------
### Multiprecision integers and binary polynomials.
def __repr__(me): return '%s(%d)' % (_clsname(me), me.default)
def check(me, sz): return True
def best(me, sz): return sz
+ def pad(me, sz): return sz
_augment(KeySZAny, _tmp)
class _tmp:
pp.pretty(me.max); pp.text(','); pp.breakable()
pp.pretty(me.mod)
pp.end_group(ind, ')')
- def check(me, sz): return me.min <= sz <= me.max and sz % me.mod == 0
+ def check(me, sz): return me.min <= sz <= me.max and sz%me.mod == 0
def best(me, sz):
if sz < me.min: raise ValueError, 'key too small'
elif sz > me.max: return me.max
- else: return sz - (sz % me.mod)
+ else: return sz - sz%me.mod
+ def pad(me, sz):
+ if sz > me.max: raise ValueError, 'key too large'
+ elif sz < me.min: return me.min
+ else: sz += me.mod; return sz - sz%me.mod
_augment(KeySZRange, _tmp)
class _tmp:
if found < i <= sz: found = i
if found < 0: raise ValueError, 'key too small'
return found
+ def pad(me, sz):
+ found = -1
+ for i in me.set:
+ if sz <= i and (found == -1 or i < found): found = i
+ if found < 0: raise ValueError, 'key too large'
+ return found
_augment(KeySZSet, _tmp)
###--------------------------------------------------------------------------
### DSA and related schemes.
class _tmp:
- def __repr__(me): return '%s(G = %r, p = %r)' % (_clsname(me), me.G, me.p)
+ def __repr__(me): return '%s(G = %r, p = %r, hash = %r)' % \
+ (_clsname(me), me.G, me.p, me.hash)
def _repr_pretty_(me, pp, cyclep):
ind = _pp_bgroup_tyname(pp, me)
if cyclep:
pp.text('...')
else:
_pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable()
- _pp_kv(pp, 'p', me.p)
+ _pp_kv(pp, 'p', me.p); pp.text(','); pp.breakable()
+ _pp_kv(pp, 'hash', me.hash)
pp.end_group(ind, ')')
_augment(DSAPub, _tmp)
_augment(KCDSAPub, _tmp)
class _tmp:
- def __repr__(me): return '%s(G = %r, u = %s, p = %r)' % \
- (_clsname(me), me.G, _repr_secret(me.u), me.p)
+ def __repr__(me): return '%s(G = %r, u = %s, p = %r, hash = %r)' % \
+ (_clsname(me), me.G, _repr_secret(me.u), me.p, me.hash)
def _repr_pretty_(me, pp, cyclep):
ind = _pp_bgroup_tyname(pp, me)
if cyclep:
else:
_pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable()
_pp_kv(pp, 'u', me.u, True); pp.text(','); pp.breakable()
- _pp_kv(pp, 'p', me.p)
+ _pp_kv(pp, 'p', me.p); pp.text(','); pp.breakable()
+ _pp_kv(pp, 'hash', me.hash)
pp.end_group(ind, ')')
_augment(DSAPriv, _tmp)
_augment(KCDSAPriv, _tmp)
+catacomb-python (1.3.0.1) experimental; urgency=medium
+
+ * Fix required Catacomb version in `setup.py' script. Only affects the
+ source package.
+
+ -- Mark Wooding <mdw@distorted.org.uk> Sun, 22 Sep 2019 01:21:28 +0100
+
+catacomb-python (1.3.0) experimental; urgency=medium
+
+ * catacomb: Bindings for new blockcipher-based MACs, and AEAD schemes.
+ * catacomb: Invalidate `grand' objects passed into Python through prime-
+ generation events.
+ * catacomb: Improve class docstrings. (They're still extremely terse.)
+ * catacomb: Add missing `copy' methods on hash and Keccak objects.
+ * catacomb: Add `WriteBuffer.contents' as a more convenient way to
+ extract the contents than coercing to `str' or `ByteString'.
+ * catacomb: Set `RTLD_DEEPBIND' while loading the native module to work
+ around #868366.
+ * pock: New program for generating efficiently verifiable prime numbers,
+ and for verifying their certificates.
+
+ -- Mark Wooding <mdw@distorted.org.uk> Sat, 21 Sep 2019 23:00:25 +0100
+
catacomb-python (1.2.1.1) experimental; urgency=medium
* Fixing to build against Debian `stretch'.
Maintainer: Mark Wooding <mdw@distorted.org.uk>
Build-Depends: debhelper (>= 9), dh-python, pkg-config,
python (>= 2.6.6-3~), python-all-dev,
- mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.4.0)
+ mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.5.0)
Standards-Version: 3.8.0
Package: python-catacomb
-Catacomb/Python is copyright (c) 2005 Straylight/Edgeware
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Copyright: 2006--2010, 2012--2017 Straylight/Edgeware
+Upstream-Name: catacomb-python
+Upstream-Contact: Mark Wooding <mdw@distorted.org.uk>
+Source: https://ftp.distorted.org.uk/pub/mdw/
+License: LGPL-2.0+
-Catacomb/Python is free software; you can redistribute it and/or modify
-it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+Files: *
+Copyright: 2006--2010, 2012--2017 Straylight/Edgeware
+License: LGPL-2.0+
-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
-Library General Public License for more details.
-
-You should have a copy of the GNU Library General Public License in
-/usr/share/common-licenses/LGPL-2; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-USA.
+License: LGPL-2.0+
+ Catacomb/Python is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library 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
+ Library General Public License for more details.
+ .
+ You should have a copy of the GNU Library General Public License in
+ /usr/share/common-licenses/LGPL-2; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA.
+ .
+ On Debian systems, the full text of the GNU Library General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/LGPL-2'.
ec pp = EC_INIT;
unsigned f = EC_EXPLY;
int len;
- char *kwlist[] = { "flags", 0 };
+ static const char *const kwlist[] = { "flags", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:ec2osp", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:ec2osp", KWLIST,
convuint, &f))
return (0);
len = c->f->noctets * 2 + 1;
{
PyObject *x = 0, *y = 0, *z = 0;
ec p = EC_INIT;
- char *kwlist[] = { "x", "y", 0 };
+ static const char *const kwlist[] = { "x", "y", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OO:new", kwlist, &x, &y) ||
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OO:new", KWLIST, &x, &y) ||
ecptxl(0, &p, x, y, z))
goto end;
return (ecpt_pywrapout(ty, &p));
{
PyObject *x = 0, *y = 0, *z = 0;
ec p = EC_INIT;
- char *kwlist[] = { "x", "y", "z", 0 };
+ static const char *const kwlist[] = { "x", "y", "z", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OOO:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|OOO:new", KWLIST,
&x, &y, &z) ||
ecptxl(ECCURVE_C(ty), &p, x, y, z))
goto end;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Elliptic curve points, not associated with any curve.",
+"ECPt([X, [Y]]): elliptic curve points, not associated with any curve.\n\
+ X alone may be None, an existing point, a string 'X, Y', an\n\
+ x-coordinate, or a pair (X, Y); X and Y should be a coordinate pair.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
ec_curve *cc;
unsigned f = EC_XONLY | EC_LSB | EC_SORT | EC_EXPLY;
ec pp = EC_INIT;
- char *kwlist[] = { "class", "buf", "flags", 0 };
+ static const char *const kwlist[] = { "class", "buf", "flags", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|O&:os2ecp", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|O&:os2ecp", KWLIST,
&me, &p, &len, convuint, &f))
return (0);
buf_init(&b, p, len);
static PyObject *ecmeth_rand(PyObject *me, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "rng", 0 };
+ static const char *const kwlist[] = { "rng", 0 };
grand *r = &rand_global;
ec p = EC_INIT;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", KWLIST,
convgrand, &r))
return (0);
ec_rand(ECCURVE_C(me), &p, r);
{
PyObject *fobj;
PyObject *cobj = 0;
- char *kwlist[] = { "field", "a", "b", 0 };
+ static const char *const kwlist[] = { "field", "a", "b", 0 };
mp *aa = 0, *bb = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&O&", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&O&", KWLIST,
field_pytype, &fobj,
convmp, &aa, convmp, &bb))
goto end;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "An elliptic curve. Abstract class.",
+"An elliptic curve. Abstract class.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "An elliptic curve over a prime field. Use ecprimeprojcurve.",
+"ECPrimeCurve(FIELD, A, B): an elliptic curve over a prime field.\n\
+ Use ECPrimeProjCurve instead.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "An elliptic curve over a prime field, using projective coordinates.",
+"ECPrimeProjCurve(FIELD, A, B): an elliptic curve over a prime field\n\
+ using projective coordinates.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "An elliptic curve over a binary field. Use ecbinprojcurve.",
+"ECBinCurve(FIELD, A, B): an elliptic curve over a binary field.\n\
+ Use ECBinProjCurve instead.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "An elliptic curve over a binary field, using projective coordinates.",
+"ECBinProjCurve(FIELD, A, B): an elliptic curve over a binary field,\n\
+ using projective coordinates.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
ec_info ei = { 0 };
PyObject *e, *g;
- char *kwlist[] = { "curve", "G", "r", "h", 0 };
+ static const char *const kwlist[] = { "curve", "G", "r", "h", 0 };
ecinfo_pyobj *rc = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O&O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O&O&:new", KWLIST,
eccurve_pytype, &e, ecpt_pytype, &g,
convmp, &ei.r, convmp, &ei.h))
goto end;
static PyObject *eimeth_check(PyObject *me, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "rng", 0 };
+ static const char *const kwlist[] = { "rng", 0 };
grand *r = &rand_global;
const char *p;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:check", KWLIST,
convgrand, &r))
goto end;
if ((p = ec_checkinfo(ECINFO_EI(me), r)) != 0)
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Elliptic curve domain parameters.",
+"ECInfo(CURVE, G, R, H): elliptic curve domain parameters.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
PyObject *x;
mp *z;
- char *kwlist[] = { "x", 0 };
+ static const char *const kwlist[] = { "x", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:fe", kwlist, &x))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:fe", KWLIST, &x))
return (0);
if (FE_PYCHECK(x) && FE_F(x) == FIELD_F(ty)) RETURN_OBJ(x);
if ((z = getmp(x)) == 0) return (0);
static PyObject *fmeth_rand(PyObject *me, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "rng", 0 };
+ static const char *const kwlist[] = { "rng", 0 };
grand *r = &rand_global;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:rand", KWLIST,
convgrand, &r))
return (0);
return (fe_pywrap(me, F_RAND(FIELD_F(me), MP_NEW, r)));
{
mp *xx = 0;
field *f;
- char *kwlist[] = { "p", 0 };
+ static const char *const kwlist[] = { "p", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:primefield", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:primefield", KWLIST,
convmp, &xx))
goto end;
if ((f = field_prime(xx)) == 0)
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Prime fields.",
+"PrimeField(P): prime fields.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mp *xx = 0;
field *f;
- char *kwlist[] = { "p", 0 };
+ static const char *const kwlist[] = { "p", 0 };
if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:niceprimefield",
- kwlist, convmp, &xx))
+ KWLIST, convmp, &xx))
goto end;
if ((f = field_niceprime(xx)) == 0)
VALERR("bad prime for niceprimefield");
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Nice prime fields.",
+"NicePrimeField(P): prime field using Solinas reduction.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Binary fields. Abstract class.",
+"Binary fields. Abstract class.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mp *xx = 0;
field *f;
- char *kwlist[] = { "p", 0 };
+ static const char *const kwlist[] = { "p", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:binpolyfield", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:binpolyfield", KWLIST,
convgf, &xx))
goto end;
if ((f = field_binpoly(xx)) == 0) VALERR("bad poly for binpolyfield");
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Binary fields with polynomial basis representation.",
+"BinPolyField(P): binary fields with polynomial basis representation.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mp *xx = 0, *yy = 0;
field *f;
- char *kwlist[] = { "p", "beta", 0 };
+ static const char *const kwlist[] = { "p", "beta", 0 };
if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:binnormfield",
- kwlist, convgf, &xx, convgf, &yy))
+ KWLIST, convgf, &xx, convgf, &yy))
goto end;
if ((f = field_binnorm(xx, yy)) == 0) VALERR("bad args for binnormfield");
MP_DROP(xx); MP_DROP(yy);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Binary fields with normal basis representation.",
+"BinNormField(P, BETA): binary fields with normal basis representation.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *fginfo_pynew(PyTypeObject *ty,
PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "p", "r", "g", 0 };
+ static const char *const kwlist[] = { "p", "r", "g", 0 };
gprime_param dp = { 0 };
fginfo_pyobj *z = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&O&:new", KWLIST,
convmp, &dp.p,
convmp, &dp.q,
convmp, &dp.g))
grand *r = &rand_global;
struct excinfo exc = EXCINFO_INIT;
pypgev evt = { { 0 } };
- char *kwlist[] =
+ static const char *const kwlist[] =
{ "class", "pbits", "qbits", "event", "rng", "nsteps", 0 };
PyObject *rc = 0;
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", KWLIST,
&me, convuint, &pl, convuint, &ql,
convpgev, &evt, convgrand, &r,
convuint, &steps))
pypgev oe = { { 0 } }, ie = { { 0 } };
int subgroupp = 1;
unsigned f = 0;
- char *kwlist[] = { "class", "pbits", "qbits", "event", "ievent",
- "rng", "nsteps", "subgroupp", 0 };
+ static const char *const kwlist[] = {
+ "class", "pbits", "qbits", "event", "ievent",
+ "rng", "nsteps", "subgroupp", 0
+ };
size_t i, nf;
mp **v = 0;
PyObject *rc = 0, *vec = 0;
oe.exc = ie.exc = &exc;
if (!PyArg_ParseTupleAndKeywords(arg, kw,
- "OO&O&|O&O&O&O&O&:genlimlee", kwlist,
+ "OO&O&|O&O&O&O&O&:genlimlee", KWLIST,
&me, convuint, &pl, convuint, &ql,
convpgev, &oe, convpgev, &ie,
convgrand, &r, convuint, &steps,
grand *r = &rand_global;
struct excinfo exc = EXCINFO_INIT;
pypgev evt = { { 0 } };
- char *kwlist[] = { "class", "pbits", "qbits",
- "event", "rng", "nsteps", 0 };
+ static const char *const kwlist[] =
+ { "class", "pbits", "qbits", "event", "rng", "nsteps", 0 };
mp *v = MP_NEW;
PyObject *rc = 0;
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&|O&O&O&:genkcdsa", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&|O&O&O&:genkcdsa", KWLIST,
&me, convuint, &pl, convuint, &ql,
convpgev, &evt, convgrand, &r,
convuint, &steps))
Py_ssize_t ksz;
struct excinfo exc = EXCINFO_INIT;
pypgev evt = { { 0 } };
- char *kwlist[] =
+ static const char *const kwlist[] =
{ "class", "pbits", "qbits", "seed", "event", "nsteps", 0 };
PyObject *rc = 0;
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&s#|O&O&:gendsa", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&s#|O&O&:gendsa", KWLIST,
&me, convuint, &pl, convuint, &ql,
&k, &ksz, convpgev, &evt,
convuint, &steps))
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Abstract base class for field-group information objects.",
+"Abstract base class for field-group information objects.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Standard (integer) Diffie-Hellman group information.",
+"DHInfo(P, R, G): standard (integer) Diffie-Hellman group information.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Binary-field Diffie-Hellman group information.",
+"BinDHInfo(P, R, G): binary-field Diffie-Hellman group information.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *ge_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "x", 0 };
+ static const char *const kwlist[] = { "x", 0 };
PyObject *x;
group *g;
ec p = EC_INIT;
mptext_stringctx sc;
g = GROUP_G(ty);
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &x)) goto end;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &x)) goto end;
xx = G_CREATE(g);
if (ECPT_PYCHECK(x)) {
getecptout(&p, x);
static PyObject *gemeth_toec(PyObject *me, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "curve", 0 };
+ static const char *const kwlist[] = { "curve", 0 };
PyTypeObject *cty = 0;
PyObject *rc = 0;
group *g;
ec_curve *c;
ec p = EC_INIT;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:toec", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:toec", KWLIST,
&cty)) goto end;
g = GROUP_G(GE_GOBJ(me));
if (cty) {
static PyObject *gmeth_checkgroup(PyObject *me, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "rng", 0 };
+ static const char *const kwlist[] = { "rng", 0 };
grand *r = &rand_global;
const char *p;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:checkgroup", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:checkgroup", KWLIST,
convgrand, &r))
goto end;
if ((p = G_CHECK(GROUP_G(me), r)) != 0)
PyObject *arg, PyObject *kw)
{
PyObject *i;
- char *kwlist[] = { "info", 0 };
+ static const char *const kwlist[] = { "info", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", KWLIST,
dhinfo_pytype, &i))
return (0);
return (group_dopywrap(ty, group_prime(FGINFO_DP(i))));
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Subgroups of prime fields.",
+"PrimeGroup(INFO): subgroups of prime fields.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
PyObject *arg, PyObject *kw)
{
PyObject *i;
- char *kwlist[] = { "info", 0 };
+ static const char *const kwlist[] = { "info", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", KWLIST,
bindhinfo_pytype, &i))
return (0);
return (group_dopywrap(ty, group_binary(FGINFO_DP(i))));
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Subgroups of binary fields.",
+"BinGroup(INFO): subgroups of binary fields.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
PyObject *i;
ec_info ei;
- char *kwlist[] = { "info", 0 };
+ static const char *const kwlist[] = { "info", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!:new", KWLIST,
ecinfo_pytype, &i))
return (0);
ecinfo_copy(&ei, ECINFO_EI(i));
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Elliptic curve groups.",
+"ECGroup(INFO): elliptic curve groups.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *kdmeth_copy(PyObject *me, PyObject *arg, PyObject *kw)
{
key_filter f = { 0, 0 };
- static char *kwlist[] = { "filter", 0 };
+ static const char *const kwlist[] = { "filter", 0 };
key_data *kd;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:copy", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:copy", KWLIST,
convfilter, &f))
return (0);
if ((kd = key_copydata(KEYDATA_KD(me), &f)) == 0)
key_filter f = { 0, 0 };
dstr d = DSTR_INIT;
PyObject *rc = 0;
- static char *kwlist[] = { "filter", 0 };
+ static const char *const kwlist[] = { "filter", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:write", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:write", KWLIST,
convfilter, &f))
return (0);
key_write(KEYDATA_KD(me), &d, &f);
key_filter f = { 0, 0 };
dstr d = DSTR_INIT;
PyObject *rc = 0;
- static char *kwlist[] = { "filter", 0 };
+ static const char *const kwlist[] = { "filter", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:encode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:encode", KWLIST,
convfilter, &f))
return (0);
key_encode(KEYDATA_KD(me), &d, &f);
Py_ssize_t n;
unsigned f = 0;
keydata_pyobj *me = 0;
- static char *kwlist[] = { "key", "flags", 0 };
+ static const char *const kwlist[] = { "key", "flags", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", KWLIST,
&p, &n, convflags, &f))
goto end;
me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key data for binary keys.",
+"KeyDataBinary(KEY, [flags = 0]): key data for binary keys.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_ssize_t n;
unsigned f = 0;
keydata_pyobj *me = 0;
- static char *kwlist[] = { "key", "flags", 0 };
+ static const char *const kwlist[] = { "key", "flags", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", KWLIST,
&p, &n, convflags, &f))
goto end;
me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key data for encrypted keys.",
+"KeyDataEncrypted(KEY, [flags = 0]): key data for encrypted keys.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
mp *x = 0;
unsigned f = 0;
keydata_pyobj *me = 0;
- static char *kwlist[] = { "key", "flags", 0 };
+ static const char *const kwlist[] = { "key", "flags", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", KWLIST,
convmp, &x, convflags, &f))
goto end;
me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key data for large-integer keys.",
+"KeyDataMP(KEY, [flags = 0]): key data for large-integer keys.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
char *p;
unsigned f = 0;
keydata_pyobj *me = 0;
- static char *kwlist[] = { "key", "flags", 0 };
+ static const char *const kwlist[] = { "key", "flags", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:new", KWLIST,
&p, convflags, &f))
goto end;
me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key data for string keys.",
+"KeyDataString(KEY, [flags = 0]): key data for string keys.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
ec x = EC_INIT;
unsigned f = 0;
keydata_pyobj *me = 0;
- static char *kwlist[] = { "key", "flags", 0 };
+ static const char *const kwlist[] = { "key", "flags", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", KWLIST,
convecpt, &x, convflags, &f))
goto end;
me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key data for elliptic-curve keys.",
+"KeyDataECPt(KEY, [flags = 0]): key data for elliptic-curve keys.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
char *p;
keydata_pyobj *me = 0;
key_data *kd = 0;
- static char *kwlist[] = { "subkeys", 0 };
+ static const char *const kwlist[] = { "subkeys", 0 };
Py_XINCREF(arg); Py_XINCREF(kw);
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", kwlist, &sub))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", KWLIST, &sub))
goto end;
kd = key_newstruct();
if (sub) {
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key data for structured keys.",
+"KeyDataStructured([subkeys = []]): key data for structured keys.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
uint32 id;
char *type;
unsigned long exptime = KEXP_FOREVER;
- static char *kwlist[] = { "keyfile", "id", "type", "exptime", 0 };
+ static const char *const kwlist[] =
+ { "keyfile", "id", "type", "exptime", 0 };
key *k;
int err;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&s|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&s|O&:new", KWLIST,
keyfile_pytype, &kfobj, convu32, &id,
&type, convulong, &exptime))
goto end;
PyObject *nameobj;
char *name;
FILE *fp;
- static char *kwlist[] = { "file", "filter", 0 };
+ static const char *const kwlist[] = { "file", "filter", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O&:extract", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O&:extract", KWLIST,
&PyFile_Type, &file,
convfilter, &f) ||
(fp = PyFile_AsFile(file)) == 0 ||
{
ghash *h;
key_filter f = { KF_NONSECRET, KF_NONSECRET };
- static char *kwlist[] = { "hash", "filter", 0 };
+ static const char *const kwlist[] = { "hash", "filter", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:fingerprint", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:fingerprint", KWLIST,
convghash, &h, convfilter, &f))
return (0);
return (getbool(key_fingerprint(KEY_K(me), h, &f)));
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Key object.",
+"Key(KF, ID, TYPE, [exptime = KEXP_FOREVER]): key object.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
char *file = 0;
unsigned how = KOPEN_READ;
keyfile_pyobj *rc = 0;
- static char *kwlist[] = { "file", "how", "report", 0 };
+ static const char *const kwlist[] = { "file", "how", "report", 0 };
Py_XINCREF(arg); Py_XINCREF(kw);
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|iO:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|iO:new", KWLIST,
&file, &how, &ri.func))
goto end;
if (ri.func && !PyCallable_Check(ri.func))
PyObject *x = 0;
FILE *fp = 0;
int rc;
- static char *kwlist[] = { "file", "report", 0 };
+ static const char *const kwlist[] = { "file", "report", 0 };
Py_XINCREF(arg); Py_XINCREF(kw);
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O:merge", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O:merge", KWLIST,
&PyFile_Type, &x, &ri.func))
goto end;
if (ri.func && !PyCallable_Check(ri.func))
uint32 id;
char *type;
long exptime = KEXP_FOREVER;
- static char *kwlist[] = { "id", "type", "exptime", 0 };
+ static const char *const kwlist[] = { "id", "type", "exptime", 0 };
key *k;
int err;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&s|l:newkey", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&s|l:newkey", KWLIST,
convu32, &id, &type, &exptime))
goto end;
if ((err = key_new(KEYFILE_KF(me), id, type, exptime, &k)) != 0)
char *tag;
dstr d = DSTR_INIT;
PyObject *rc = 0;
- static char *kwlist[] = { "tag", "new", 0 };
+ static const char *const kwlist[] = { "tag", "new", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O!:qtag", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O!:qtag", KWLIST,
&tag, keydata_pytype, &newkdobj))
goto end;
if (key_qtag(KEYFILE_KF(me), tag, &d, &k, &kd))
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Keyring file.",
+"KeyFile(FILE, [how = KOPEN_READ], [report = ?]): Keyring file.\n\
+ calls REPORT(FILE, LINE, MSG) on problems",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
mp *z;
mp_pyobj *zz = 0;
int radix = 0;
- char *kwlist[] = { "x", "radix", 0 };
+ static const char *const kwlist[] = { "x", "radix", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:new", kwlist, &x, &radix))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:new", KWLIST, &x, &radix))
goto end;
if (MP_PYCHECK(x)) RETURN_OBJ(x);
if (!good_radix_p(radix, 1)) VALERR("bad radix");
static PyObject *mpmeth_tostring(PyObject *me, PyObject *arg, PyObject *kw)
{
int radix = 10;
- char *kwlist[] = { "radix", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|i:tostring", kwlist, &radix))
+ static const char *const kwlist[] = { "radix", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|i:tostring", KWLIST, &radix))
goto end;
if (!good_radix_p(radix, 0)) VALERR("bad radix");
return (mp_topystring(MP_X(me), radix, 0, 0, 0));
PyObject *arg, PyObject *kw) \
{ \
long len = -1; \
- char *kwlist[] = { "len", 0 }; \
+ static const char *const kwlist[] = { "len", 0 }; \
PyObject *rc = 0; \
\
if (!PyArg_ParseTupleAndKeywords(arg, kw, "|l:" #name, \
- kwlist, &len)) \
+ KWLIST, &len)) \
goto end; \
if (len < 0) { \
len = mp_octets##c(MP_X(me)); \
static PyObject *mpmeth_primep(PyObject *me, PyObject *arg, PyObject *kw)
{
grand *r = &rand_global;
- char *kwlist[] = { "rng", 0 };
+ static const char *const kwlist[] = { "rng", 0 };
PyObject *rc = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&", kwlist, convgrand, &r))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&", KWLIST, convgrand, &r))
goto end;
rc = getbool(pgen_primep(MP_X(me), r));
end:
\n\
Notes:\n\
\n\
- * Use `//' for division. MPs don't have `/' division.",
+ * Use `//' for integer division. `/' gives exact rational division.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
PyObject *z = 0;
mp *zz;
mptext_stringctx sc;
- char *kwlist[] = { "class", "x", "radix", 0 };
+ static const char *const kwlist[] = { "class", "x", "radix", 0 };
if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|i:fromstring",
- kwlist, &me, &p, &len, &r))
+ KWLIST, &me, &p, &len, &r))
goto end;
if (!good_radix_p(r, 1)) VALERR("bad radix");
sc.buf = p; sc.lim = p + len;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"An object for multiplying many small integers.",
+"MPMul(N_0, N_1, ....): an object for multiplying many small integers.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *mpmont_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
mpmont_pyobj *mm = 0;
- char *kwlist[] = { "m", 0 };
+ static const char *const kwlist[] = { "m", 0 };
mp *xx = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmp, &xx))
goto end;
if (!MP_POSP(xx) || !MP_ODDP(xx)) VALERR("m must be positive and odd");
mm = (mpmont_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"A Montgomery reduction context.",
+"MPMont(N): a Montgomery reduction context.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
PyObject *arg, PyObject *kw)
{
mpbarrett_pyobj *mb = 0;
- char *kwlist[] = { "m", 0 };
+ static const char *const kwlist[] = { "m", 0 };
mp *xx = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmp, &xx))
goto end;
if (!MP_POSP(xx)) VALERR("m must be positive");
mb = (mpbarrett_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"A Barrett reduction context.",
+"MPBarrett(N): a Barrett reduction context.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mpreduce_pyobj *mr = 0;
mpreduce r;
- char *kwlist[] = { "m", 0 };
+ static const char *const kwlist[] = { "m", 0 };
mp *xx = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &xx))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmp, &xx))
goto end;
if (!MP_POSP(xx)) VALERR("m must be positive");
if (mpreduce_create(&r, xx)) VALERR("bad modulus (must be 2^k - ...)");
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"A reduction context for reduction modulo primes of special form.",
+"MPReduce(N): a reduction context for reduction modulo Solinas primes.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mpcrt_mod *v = 0;
Py_ssize_t n, i = 0, j;
- char *kwlist[] = { "mv", 0 };
+ static const char *const kwlist[] = { "mv", 0 };
PyObject *q = 0, *x;
mp *xx = MP_NEW, *y = MP_NEW, *g = MP_NEW;
mpmul mm;
if (PyTuple_Size(arg) > 1)
q = arg;
- else if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &q))
+ else if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &q))
goto end;
Py_INCREF(q);
if (!PySequence_Check(q)) TYERR("want a sequence of moduli");
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"A context for the solution of Chinese Remainder Theorem problems.",
+"MPCRT(SEQ): a context for solving Chinese Remainder Theorem problems.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
mp *z;
mp_pyobj *zz = 0;
int radix = 0;
- char *kwlist[] = { "x", "radix", 0 };
+ static const char *const kwlist[] = { "x", "radix", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:gf", kwlist, &x, &radix))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|i:gf", KWLIST, &x, &radix))
goto end;
if (GF_PYCHECK(x)) RETURN_OBJ(x);
if (!good_radix_p(radix, 1)) VALERR("radix out of range");
\n\
Notes:\n\
\n\
- * Use `//' for division. GFs don't have `/' division.",
+ * Use `//' for Euclidean division. `/' gives exact rational division.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
PyObject *z = 0;
mp *zz;
mptext_stringctx sc;
- char *kwlist[] = { "class", "x", "radix", 0 };
+ static const char *const kwlist[] = { "class", "x", "radix", 0 };
if (!PyArg_ParseTupleAndKeywords(arg, kw, "Os#|i:fromstring",
- kwlist, &me, &p, &len, &r))
+ KWLIST, &me, &p, &len, &r))
goto end;
if (!good_radix_p(r, 1)) VALERR("bad radix");
sc.buf = p; sc.lim = p + len;
{
gfreduce_pyobj *mr = 0;
gfreduce r;
- char *kwlist[] = { "m", 0 };
+ static const char *const kwlist[] = { "m", 0 };
mp *xx = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convgf, &xx))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convgf, &xx))
goto end;
if (MP_ZEROP(xx)) ZDIVERR("modulus is zero!");
gfreduce_create(&r, xx);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"A reduction context for reduction modulo sparse irreducible polynomials.",
+"GFReduce(N): a context for reduction modulo sparse polynomials.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mp *p = 0, *beta = 0;
gfn_pyobj *gg = 0;
- char *kwlist[] = { "p", "beta", 0 };
+ static const char *const kwlist[] = { "p", "beta", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", KWLIST,
convgf, &p, convgf, &beta))
goto end;
gg = PyObject_New(gfn_pyobj, ty);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"An object for transforming elements of binary fields between polynomial\n\
-and normal basis representations.",
+"GFN(P, BETA): an object for transforming elements of binary fields\n\
+ between polynomial and normal basis representations.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *pixie_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
pixie_pyobj *rc = 0;
- char *kwlist[] = { "socket", 0 };
+ static const char *const kwlist[] = { "socket", 0 };
char *sock = 0;
int fd;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s:new", kwlist, &sock))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s:new", KWLIST, &sock))
goto end;
if ((fd = pixie_open(sock)) < 0)
OSERR(sock);
{
unsigned mode = PMODE_READ;
char *tag;
- char *kwlist[] = { "tag", "mode", 0 };
+ static const char *const kwlist[] = { "tag", "mode", 0 };
PyObject *rc = 0;
int r;
char buf[1024];
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:read", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:read", KWLIST,
&tag, convuint, &mode))
goto end;
r = pixie_read(PIXIE_FD(me), tag, mode, buf, sizeof(buf));
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Passphrase pixie connection.",
+"Pixie([socket = ?]): passphrase pixie connection.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
char *tag;
unsigned f = PMODE_READ;
PyObject *rc = 0;
- char *kwlist[] = { "tag", "mode", 0 };
+ static const char *const kwlist[] = { "tag", "mode", 0 };
char buf[1024];
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:ppread", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:ppread", KWLIST,
&tag, convuint, &f))
goto end;
if (passphrase_read(tag, f, buf, sizeof(buf)))
static PyObject *pfilt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "x", 0 };
+ static const char *const kwlist[] = { "x", 0 };
PyObject *xobj;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &xobj))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &xobj))
return (0);
return (pfilt_pymake(ty, xobj));
}
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Small-primes filter.",
+"PrimeFilter(X): small-primes filter.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mp *x = 0;
rabin_pyobj *o = 0;
- char *kwlist[] = { "x", 0 };
+ static const char *const kwlist[] = { "x", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &x))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmp, &x))
goto end;
if (!MP_POSP(x) || MP_EVENP(x)) VALERR("must be positive and odd");
o = (rabin_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Rabin-Miller strong primality test.",
+"RabinMiller(X): Rabin-Miller strong primality test.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
PyObject *rc = 0;
int st = PGEN_ABORT;
long l;
- char *meth[] = {
- "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass"
- };
+ static const char *const meth[] =
+ { "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass" };
rq++;
if (rq > N(meth)) SYSERR("event code out of range");
pyev = pgevent_pywrap(ev);
- if ((rc = PyObject_CallMethod(pg->obj, meth[rq], "(O)", pyev)) == 0)
+ if ((rc = PyObject_CallMethod(pg->obj, (/*unconst*/ char *)meth[rq],
+ "(O)", pyev)) == 0)
goto end;
if (rc == Py_None)
st = PGEN_TRY;
{
mpw s;
pgstep_pyobj *rc = 0;
- char *kwlist[] = { "step", 0 };
+ static const char *const kwlist[] = { "step", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmpw, &s))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", KWLIST, convmpw, &s))
goto end;
rc = (pgstep_pyobj *)ty->tp_alloc(ty, 0);
rc->f.step = s;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
- "Simple prime-number stepper with small-factors filter.",
+"PrimeGenStepper(STEP): simple stepper with small-factors filter.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
PyObject *o, *fobj;
pgjump_pyobj *rc = 0;
- char *kwlist[] = { "jump", 0 };
+ static const char *const kwlist[] = { "jump", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &o) ||
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", KWLIST, &o) ||
(fobj = pfilt_pymake(pfilt_pytype, o)) == 0)
goto end;
rc = (pgjump_pyobj *)ty->tp_alloc(ty, 0);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Stepper for larger steps, with small-factors filter.",
+"PrimeGenJumper(JUMP): stepper for larger steps with small-factors filter.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *pgtest_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
pgtest_pyobj *rc = 0;
- char *kwlist[] = { 0 };
+ static const char *const kwlist[] = { 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) goto end;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
rc = (pgtest_pyobj *)ty->tp_alloc(ty, 0);
rc->pg.proc = pgen_test;
rc->pg.ctx = &rc->r;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Rabin-Miller tester.",
+"PrimeGenTester(): Rabin-Miller tester.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
struct excinfo exc = EXCINFO_INIT;
pypgev step = { { 0 } }, test = { { 0 } }, evt = { { 0 } };
unsigned nsteps = 0, ntests = 0;
- char *kwlist[] = { "start", "name", "stepper", "tester", "event",
- "nsteps", "ntests", 0 };
+ static const char *const kwlist[] =
+ { "start", "name", "stepper", "tester", "event", "nsteps", "ntests", 0 };
step.exc = &exc; step.ev.proc = pgen_filter; step.ev.ctx = &fc;
test.exc = &exc; test.ev.proc = pgen_test; test.ev.ctx = &tc;
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", KWLIST,
convmp, &x, &p, convpgev, &step,
convpgev, &test, convpgev, &evt,
convuint, &nsteps, convuint, &ntests))
struct excinfo exc = EXCINFO_INIT;
pypgev evt = { { 0 } };
PyObject *rc = 0;
- char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
+ static const char *const kwlist[] =
+ { "nbits", "name", "event", "rng", "nsteps", 0 };
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
convuint, &nbits, &name,
convpgev, &evt, convgrand, &r,
convuint, &n))
struct excinfo exc = EXCINFO_INIT;
pypgev evt = { { 0 } };
PyObject *rc = 0;
- char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
+ static const char *const kwlist[] =
+ { "nbits", "name", "event", "rng", "nsteps", 0 };
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", KWLIST,
convuint, &nbits, &name,
convpgev, &evt, convgrand, &r,
convuint, &n))
unsigned on = 0;
size_t i, nf = 0;
PyObject *rc = 0, *vec;
- char *kwlist[] = { "pbits", "qbits", "name", "event", "ievent",
- "rng", "nsteps", 0 };
+ static const char *const kwlist[] =
+ { "pbits", "qbits", "name", "event", "ievent", "rng", "nsteps", 0 };
mp *x = 0, **v = 0;
ie.exc = oe.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", KWLIST,
convuint, &pl, convuint, &ql,
&p, convpgev, &oe, convpgev, &ie,
convgrand, &r, convuint, &on))
--- /dev/null
+#! /usr/bin/python
+### -*- mode: python, coding: utf-8 -*-
+###
+### Tool for generating and verifying primality certificates
+###
+### (c) 2017 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.
+
+###--------------------------------------------------------------------------
+### Imported modules.
+
+from sys import argv, stdin, stdout, stderr
+import os as OS
+import itertools as I
+import math as M
+import optparse as OP
+
+import catacomb as C
+
+###--------------------------------------------------------------------------
+### Utilities.
+
+class ExpectedError (Exception):
+ """
+ I represent an expected error, which should be reported in a friendly way.
+ """
+ pass
+
+def prod(ff, one = 1):
+ """
+ Return ONE times the product of the elements of FF.
+
+ This is not done very efficiently.
+ """
+ return reduce(lambda prod, f: prod*f, ff, one)
+
+def parse_label(line):
+ """
+ Split LINE at an `=' character and return the left and right halves.
+
+ The returned pieces have leading and trailing whitespace trimmed.
+ """
+ eq = line.find('=')
+ if eq < 0: raise ExpectedError('expected `LABEL = ...\'')
+ return line[:eq].strip(), line[eq + 1:].strip()
+
+def parse_list(s, n):
+ l = s.split(',', n - 1)
+ if n is not None and len(l) != n:
+ raise ExpectedError('expected `,\'-separated list of %d items' % n)
+ return l
+
+def conv_int(s):
+ """Convert S to a integer."""
+ try: return C.MP(s, 0)
+ except TypeError: raise ExpectedError('invalid integer `%s\'' % s)
+
+VERBOSITY = 1
+
+class ProgressReporter (object):
+ """
+ I keep users amused while the program looks for large prime numbers.
+
+ My main strategy is the printing of incomprehensible runes. I can be
+ muffled by lowering by verbosity level.
+
+ Prime searches are recursive in nature. When a new recursive level is
+ started, call `push'; and call `pop' when the level is finished. This must
+ be done around the top level too.
+ """
+ def __init__(me):
+ """Initialize the ProgressReporter."""
+ me._level = -1
+ me._update()
+ def _update(me):
+ """
+ Update our idea of whether we're active.
+
+ We don't write inscrutable runes when inactive. The current policy is to
+ write nothing if verbosity is zero, to write runes for the top level only
+ if verbosity is 1, and to write runes always if verbosity is higher than
+ that.
+ """
+ me._active = VERBOSITY >= 2 or (VERBOSITY == 1 and me._level == 0)
+ def push(me):
+ """Push a new search level."""
+ me._level += 1
+ me._update()
+ if me._level > 0: me.p('[')
+ else: me.p(';; ')
+ def pop(me):
+ """Pop a search level."""
+ if me._level > 0: me.p(']')
+ else: me.p('\n')
+ me._level -= 1
+ me._update()
+ def p(me, ch):
+ """Print CH as a progress rune."""
+ if me._active: stderr.write(ch); stderr.flush()
+
+def combinations(r, v):
+ """
+ Return an iterator which yields all combinations of R elements from V.
+
+ V must be an indexable sequence. The each combination is returned as a
+ list, containing elements from V in their original order.
+ """
+
+ ## Set up the selection vector. C will contain the indices of the items of
+ ## V we've selected for the current combination. At all times, C contains
+ ## a strictly increasing sequence of integers in the interval [0, N).
+ n = len(v)
+ c = range(r)
+
+ while True:
+
+ ## Yield up the current combination.
+ vv = [v[i] for i in c]
+ yield vv
+
+ ## Now advance to the next one. Find the last index in C which we can
+ ## increment subject to the rules. As we iterate downwards, i will
+ ## contain the index into C, and j will be the maximum acceptable value
+ ## for the corresponding item. We'll step the last index until it
+ ## reaches the limit, and then step the next one down, resetting the last
+ ## index, and so on.
+ i, j = r, n
+ while True:
+
+ ## If i is zero here, then we've advanced everything as far as it will
+ ## go. We're done.
+ if i == 0: return
+
+ ## Move down to the next index.
+ i -= 1; j -= 1
+
+ ## If this index isn't at its maximum value, then we've found the place
+ ## to step.
+ if c[i] != j: break
+
+ ## Step this index on by one, and set the following indices to the
+ ## immediately following values.
+ j = c[i] + 1
+ while i < r: c[i] = j; i += 1; j += 1
+
+class ArgFetcher (object):
+ """
+ I return arguments from a list, reporting problems when they occur.
+ """
+ def __init__(me, argv, errfn):
+ """
+ Initialize, returning successive arguments from ARGV.
+
+ Errors are reported to ERRFN.
+ """
+ me._argv = argv
+ me._argc = len(argv)
+ me._errfn = errfn
+ me._i = 0
+ def arg(me, default = None, must = True):
+ """
+ Return the next argument.
+
+ If MUST is true, then report an error (to the ERRFN) if there are no more
+ arguments; otherwise, return the DEFAULT.
+ """
+ if me._i >= me._argc:
+ if must: me._errfn('missing argument')
+ return default
+ arg = me._argv[me._i]; me._i += 1
+ return arg
+ def int(me, default = None, must = True, min = None, max = None):
+ """
+ Return the next argument converted to an integer.
+
+ If MUST is true, then report an error (to the ERRFN) if there are no more
+ arguments; otherwise return the DEFAULT. Report an error if the next
+ argument is not a valid integer, or if the integer is beyond the MIN and
+ MAX bounds.
+ """
+ arg = me.arg(default = None, must = must)
+ if arg is None: return default
+ try: arg = int(arg)
+ except ValueError: me._errfn('bad integer')
+ if (min is not None and arg < min) or (max is not None and arg > max):
+ me._errfn('out of range')
+ return arg
+
+###--------------------------------------------------------------------------
+### Sieving for small primes.
+
+class Sieve (object):
+ """
+ I represent a collection of small primes, up to some chosen limit.
+
+ The limit is available as the `limit' attribute. Let L be this limit;
+ then, if N < L^2 is some composite, then N has at least one prime factor
+ less than L.
+ """
+
+ ## Figure out the number of bits in a (nonnegative) primitive `int'. We'll
+ ## use a list of these as our sieve.
+ _NBIT = 15
+ while type(1 << (_NBIT + 1)) == int: _NBIT += 1
+
+ def __init__(me, limit):
+ """
+ Initialize a sieve holding all primes below LIMIT.
+ """
+
+ ## The sieve is maintained in the `_bits' attribute. This is a list of
+ ## integers, used as a bitmask: let 2 < n < L be an odd integer; then bit
+ ## (n - 3)/2 will be clear iff n is prime. Let W be the value of
+ ## `_NBIT', above; then bit W i + j in the sieve is stored in bit j of
+ ## `_bits[i]'.
+
+ ## Store the limit for later inspection.
+ me.limit = limit
+
+ ## Calculate the size of sieve we'll need and initialize the bit list.
+ n = (limit - 2)/2
+ sievesz = (n + me._NBIT - 1)/me._NBIT
+ me._sievemax = sievesz*me._NBIT
+ me._bits = sievesz*[0]
+
+ ## This is standard Sieve of Eratosthenes. For each index i: if
+ ## bit i is clear, then p = 2 i + 3 is prime, so set the bits
+ ## corresponding to each multiple of p, i.e., bits (k p - 3)/2 =
+ ## (2 k i + 3 - 3)/2 = k i for k > 1.
+ for i in xrange(me._sievemax):
+ if me._bitp(i): i += 1; continue
+ p = 2*i + 3
+ if p >= limit: break
+ for j in xrange(i + p, me._sievemax, p): me._setbit(j)
+ i += 1
+
+ def _bitp(me, i): i, j = divmod(i, me._NBIT); return (me._bits[i] >> j)&1
+ def _setbit(me, i): i, j = divmod(i, me._NBIT); me._bits[i] |= 1 << j
+
+ def smallprimes(me):
+ """
+ Return an iterator over the known small primes.
+ """
+ yield 2
+ n = 3
+ for b in me._bits:
+ for j in xrange(me._NBIT):
+ if not (b&1): yield n
+ b >>= 1; n += 2
+
+## We generate the sieve on demand.
+SIEVE = None
+
+def initsieve(sievebits):
+ """
+ Generate the sieve.
+
+ Ensure that it can be used to check the primality of numbers up to (but not
+ including) 2^SIEVEBITS.
+ """
+ global SIEVE
+ if SIEVE is not None: raise ValueError('sieve already defined')
+ if sievebits < 6: sievebits = 6
+ SIEVE = Sieve(1 << (sievebits + 1)/2)
+
+###--------------------------------------------------------------------------
+### Primality checking.
+
+def small_test(p):
+ """
+ Check that P is a small prime.
+
+ If not, raise an `ExpectedError'. The `SIEVE' variable must have been
+ initialized.
+ """
+ if p < 2: raise ExpectedError('%d too small' % p)
+ if SIEVE.limit*SIEVE.limit < p:
+ raise ExpectedError('%d too large for small prime' % p)
+ for q in SIEVE.smallprimes():
+ if q*q > p: return
+ if p%q == 0: raise ExpectedError('%d divides %d' % (q, p))
+
+def pock_test(p, a, qq):
+ """
+ Check that P is prime using Pocklington's criterion.
+
+ If not, raise an `ExpectedError'.
+
+ Let Q be the product of the elements of the sequence QQ. The test works as
+ follows. Suppose p is the smallest prime factor of P. If A^{P-1} /== 1
+ (mod P) then P is certainly composite (Fermat's test); otherwise, we have
+ established that the order of A in (Z/pZ)^* divides P - 1. Next, let t =
+ A^{(P-1)/q} for some prime factor q of Q, and let g = gcd(t - 1, P). If g
+ = P then the proof is inconclusive; if 1 < g < P then g is a nontrivial
+ factor of P, so P is composite; otherwise, t has order q in (Z/pZ)^*, so
+ (Z/pZ)^* contains a subgroup of size q, and therefore q divides p - 1. If
+ QQ is a sequence of distinct primes, and the preceding criterion holds for
+ all q in QQ, then Q divides p - 1. If Q^2 < P then the proof is
+ inconclusive; otherwise, let p' be any prime dividing P/p. Then p' >= p >
+ Q, so p p' > Q^2 > P; but p p' divides P, so this is a contradiction.
+ Therefore P/p has no prime factors, and P is prime.
+ """
+
+ ## We don't actually need the distinctness criterion. Suppose that q^e
+ ## divides Q. Then gcd(t - 1, P) = 1 implies that A^{(P-1)/q^{e-1}} has
+ ## order q^e in (Z/pZ)^*, which accounts for the multiplicity.
+
+ Q = prod(qq)
+ if p < 2: raise ExpectedError('%d too small' % p)
+ if Q*Q <= p:
+ raise ExpectedError('too few Pocklington factors for %d' % p)
+ if pow(a, p - 1, p) != 1:
+ raise ExpectedError('%d is Fermat witness for %d' % (a, p))
+ for q in qq:
+ if Q%(q*q) == 0:
+ raise ExpectedError('duplicate Pocklington factor %d for %d' % (q, p))
+ g = p.gcd(pow(a, (p - 1)/q, p) - 1)
+ if g == p:
+ raise ExpectedError('%d order not multiple of %d mod %d' % (a, q, p))
+ elif g != 1:
+ raise ExpectedError('%d divides %d' % (g, p))
+
+def ecpp_test(p, a, b, x, y, qq):
+ """
+ Check that P is prime using Goldwasser and Kilian's ECPP method.
+
+ If not, raise an `ExpectedError'.
+
+ Let Q be the product of the elements of the sequence QQ. Suppose p is the
+ smallest prime factor of P. Let g = gcd(4 A^3 + 27 B^2, P). If g = P then
+ the test is inconclusive; otherwise, if g /= 1 then g is a nontrivial
+ factor of P. Define E(GF(p)) = { (x, y) | y^2 = x^3 + A x + B } U { inf }
+ to be the elliptic curve over p with short-Weierstraß coefficients A and B;
+ we have just checked that this curve is not singular. If R = (X, Y) is not
+ a point on this curve, then the test is inconclusive. If Q R is not the
+ point at infinity, then the test fails; otherwise we deduce that P has
+ Q-torsion in E. Let S = (Q/q) R for some prime factor q of Q. If S is the
+ point at infinity then the test is inconclusive; otherwise, q divides the
+ order of S in E. If QQ is a sequence of distinct primes, and the preceding
+ criterion holds for all q in QQ, then Q divides the order of S. Therefore
+ #E(p) >= Q. If Q <= (qrrt(P) + 1)^2 then the test is inconclusive.
+ Otherwise, Hasse's theorem tells us that |p + 1 - #E(p)| <= 2 sqrt(p);
+ hence we must have p + 1 + 2 sqrt(p) = (sqrt(p) + 1)^2 >= #E(p) >= Q >
+ (qrrt(P) + 1)^2; so sqrt(p) + 1 > qrrt(P) + 1, i.e., p^2 > P. As for
+ Pocklington above, if p' is any prime factor of P/p, then p p' >= p^2 > P,
+ which is a contradiction, and we conclude that P is prime.
+ """
+
+ ## This isn't going to work if gcd(P, 6) /= 1: we're going to use the
+ ## large-characteristic addition formulae.
+ g = p.gcd(6)
+ if g != 1: raise ExpectedError('%d divides %d' % (g, p))
+
+ ## We want to check that Q > (qrrt(P) + 1)^2 iff sqrt(Q) > qrrt(P) + 1; but
+ ## calculating square roots is not enjoyable (partly because we have to
+ ## deal with the imprecision). Fortunately, some algebra will help: the
+ ## condition holds iff qrrt(P) < sqrt(Q) - 1 iff P < Q^2 - 4 Q sqrt(Q) +
+ ## 6 Q - 4 sqrt(Q) + 1 = Q (Q + 6) + 1 - 4 sqrt(Q) (Q + 1) iff Q (Q + 6) -
+ ## P + 1 > 4 sqrt(Q) (Q + 1) iff (Q (Q + 6) - P + 1)^2 > 16 Q (Q + 1)^2
+ Q = prod(qq)
+ t, u = Q*(Q + 6) - p + 1, 4*(Q + 1)
+ if t*t <= Q*u*u: raise ExpectedError('too few subgroups for ECPP')
+
+ ## Construct the curve.
+ E = C.PrimeField(p).ec(a, b) # careful: may not be a prime!
+
+ ## Find the base point.
+ R = E(x, y)
+ if not R.oncurvep():
+ raise ExpectedError('(%d, %d) is not on the curve' % (x, y))
+
+ ## Check that it has Q-torsion.
+ if Q*R: raise ExpectedError('(%d, %d) not a %d-torsion point' % (x, y, Q))
+
+ ## Now check the individual factors.
+ for q in qq:
+ if Q%(q*q) == 0:
+ raise ExpectedError('duplicate ECPP factor %d for %d' % (q, p))
+ S = (Q/q)*R
+ if not S:
+ raise ExpectedError('(%d, %d) order not a multiple of %d' % (x, y, q))
+ g = p.gcd(S._z)
+ if g != 1:
+ raise ExpectedError('%d divides %d' % (g, p))
+
+###--------------------------------------------------------------------------
+### Proof steps and proofs.
+
+class BaseStep (object):
+ """
+ I'm a step in a primality proof.
+
+ I assert that a particular number is prime, and can check this.
+
+ This class provides basic protocol for proof steps, mostly to do with
+ handling labels.
+
+ The step's label is kept in its `label' attribute. It can be set by the
+ constructor, and is `None' by default. Users can modify this attribute if
+ they like. Labels beginning `$' are assumed to be internal and
+ uninteresting; other labels cause `check' lines to be written to the output
+ listing the actual number of interest.
+
+ Protocol that proof steps should provide:
+
+ label A string labelling the proof step and the associated prime
+ number.
+
+ p The prime number which this step proves to be prime.
+
+ check() Check that the proof step is actually correct, assuming that
+ any previous steps have already been verified.
+
+ out(FILE) Write an appropriate encoding of the proof step to the output
+ FILE.
+ """
+ def __init__(me, label = None, *arg, **kw):
+ """Initialize a proof step, setting a default label if necessary."""
+ super(BaseStep, me).__init__(*arg, **kw)
+ me.label = label
+ def out(me, file):
+ """
+ Write the proof step to an output FILE.
+
+ Subclasses must implement a method `_out' which actually does the work.
+ Here, we write a `check' line to verify that the proof actually applies
+ to the number we wanted, if the label says that this is an interesting
+ step.
+ """
+ me._out(file)
+ if me.label is not None and not me.label.startswith('$'):
+ file.write('check %s, %d, %d\n' % (me.label, me.p.nbits, me.p))
+
+class SmallStep (BaseStep):
+ """
+ I represent a claim that a number is a small prime.
+
+ Such claims act as the base cases in a complicated primality proof. When
+ verifying, the claim is checked by trial division using a collection of
+ known small primes.
+ """
+ def __init__(me, pp, p, *arg, **kw):
+ """
+ Initialize a small-prime step.
+
+ PP is the overall PrimeProof object of which this is a step; P is the
+ small number whose primality is asserted.
+ """
+ super(SmallStep, me).__init__(*arg, **kw)
+ me.p = p
+ def check(me):
+ """Check that the number is indeed a small prime."""
+ return small_test(me.p)
+ def _out(me, file):
+ """Write a small-prime step to the FILE."""
+ file.write('small %s = %d\n' % (me.label, me.p))
+ def __repr__(me): return 'SmallStep(%d)' % (me.p)
+ @classmethod
+ def parse(cls, pp, line):
+ """
+ Parse a small-prime step from a LINE in a proof file.
+
+ SMALL-STEP ::= `small' LABEL `=' P
+
+ PP is a PrimeProof object holding the results from the previous steps.
+ """
+ if SIEVE is None: raise ExpectedError('missing `sievebits\' line')
+ label, p = parse_label(line)
+ return cls(pp, conv_int(p), label = label)
+
+class PockStep (BaseStep):
+ """
+ I represent a Pocklington certificate for a number.
+
+ The number is not explicitly represented in a proof file. See `pock_test'
+ for the underlying mathematics.
+ """
+ def __init__(me, pp, a, R, qqi, *arg, **kw):
+ """
+ Inititialize a Pocklington step.
+
+ PP is the overall PrimeProof object of which this is a step; A is the
+ generator of a substantial subgroup of units; R is a cofactor; and QQI is
+ a sequence of labels for previous proof steps. If Q is the product of
+ the primes listed in QQI, then the number whose primality is asserted is
+ 2 Q R + 1.
+ """
+ super(PockStep, me).__init__(*arg, **kw)
+ me._a = a
+ me._R = R
+ me._qqi = qqi
+ me._qq = [pp.get_step(qi).p for qi in qqi]
+ me.p = prod(me._qq, 2*R) + 1
+ def check(me):
+ """Verify a proof step based on Pocklington's theorem."""
+ return pock_test(me.p, me._a, me._qq)
+ def _out(me, file):
+ """Write a Pocklington step to the FILE."""
+ file.write('pock %s = %d, %d, [%s]\n' % \
+ (me.label, me._a,
+ me._R, ', '.join('%s' % qi for qi in me._qqi)))
+ def __repr__(me): return 'PockStep(%d, %d, %s)' % (me._a, me._R, me._qqi)
+ @classmethod
+ def parse(cls, pp, line):
+ """
+ Parse a Pocklington step from a LINE in a proof file.
+
+ POCK-STEP ::= `pock' LABEL `=' A `,' R `,' `[' Q-LIST `]'
+ Q-LIST ::= Q [`,' Q-LIST]
+
+ PP is a PrimeProof object holding the results from the previous steps.
+ """
+ label, rest = parse_label(line)
+ a, R, qq = parse_list(rest, 3)
+ qq = qq.strip()
+ if not qq.startswith('[') or not qq.endswith(']'):
+ raise ExpectedError('missing `[...]\' around Pocklington factors')
+ return cls(pp, conv_int(a), conv_int(R),
+ [q.strip() for q in qq[1:-1].split(',')], label = label)
+
+class ECPPStep (BaseStep):
+ """
+ I represent a Goldwasser--Kilian ECPP certificate for a number.
+ """
+ def __init__(me, pp, p, a, b, x, y, qqi, *arg, **kw):
+ """
+ Inititialize an ECPP step.
+
+ PP is the overall PrimeProof object of which this is a step; P is the
+ number whose primality is asserted; A and B are the short Weierstraß
+ curve coefficients; X and Y are the base point coordinates; and QQI is a
+ sequence of labels for previous proof steps.
+ """
+ super(ECPPStep, me).__init__(*arg, **kw)
+ me._a, me._b = a, b
+ me._x, me._y = x, y
+ me._qqi = qqi
+ me._qq = [pp.get_step(qi).p for qi in qqi]
+ me.p = p
+ def check(me):
+ """Verify a proof step based on Goldwasser and Kilian's theorem."""
+ return ecpp_test(me.p, me._a, me._b, me._x, me._y, me._qq)
+ def _out(me, file):
+ """Write an ECPP step to the FILE."""
+ file.write('ecpp %s = %d, %d, %d, %d, %d, [%s]\n' % \
+ (me.label, me.p, me._a, me._b, me._x, me._y,
+ ', '.join('%s' % qi for qi in me._qqi)))
+ def __repr__(me):
+ return 'ECPPstep(%d, %d, %d, %d, %d, %s)' % \
+ (me.p, me._a, me._b, me._x, me._y, me._qqi)
+ @classmethod
+ def parse(cls, pp, line):
+ """
+ Parse an ECPP step from a LINE in a proof file.
+
+ ECPP-STEP ::= `ecpp' LABEL `=' P `,' A `,' B `,' X `,' Y `,'
+ `[' Q-LIST `]'
+ Q-LIST ::= Q [`,' Q-LIST]
+
+ PP is a PrimeProof object holding the results from the previous steps.
+ """
+ label, rest = parse_label(line)
+ p, a, b, x, y, qq = parse_list(rest, 6)
+ qq = qq.strip()
+ if not qq.startswith('[') or not qq.endswith(']'):
+ raise ExpectedError('missing `[...]\' around ECPP factors')
+ return cls(pp, conv_int(p), conv_int(a), conv_int(b),
+ conv_int(x), conv_int(y),
+ [q.strip() for q in qq[1:-1].split(',')], label = label)
+
+def check(pp, line):
+ """
+ Handle a `check' line in a proof file.
+
+ CHECK ::= `check' LABEL, B, N
+
+ Verify that the proof step with the given LABEL asserts the primality of
+ the integer N, and that 2^{B-1} <= N < 2^B.
+ """
+ label, nb, p = parse_list(line, 3)
+ label, nb, p = label.strip(), conv_int(nb), conv_int(p)
+ pi = pp.get_step(label).p
+ if pi != p:
+ raise ExpectedError('check failed: %s = %d /= %d' % (label, pi, p))
+ if p.nbits != nb:
+ raise ExpectedError('check failed: nbits(%s) = %d /= %d' % \
+ (label, p.nbits, nb))
+ if VERBOSITY: print ';; %s = %d [%d]' % (label, p, nb)
+
+def setsievebits(pp, line):
+ """
+ Handle a `sievebits' line in a proof file.
+
+ SIEVEBITS ::= `sievebits' N
+
+ Ensure that the verifier is willing to accept small primes up to 2^N.
+ """
+ initsieve(int(line))
+
+class PrimeProof (object):
+ """
+ I represent a proof of primality for one or more numbers.
+
+ I can encode my proof as a line-oriented text file, in a simple format, and
+ read such a proof back to check it.
+ """
+
+ ## A table to dispatch on keywords read from a file.
+ STEPMAP = { 'small': SmallStep.parse,
+ 'pock': PockStep.parse,
+ 'ecpp': ECPPStep.parse,
+ 'sievebits': setsievebits,
+ 'check': check }
+
+ def __init__(me):
+ """
+ Initialize a proof object.
+ """
+ me._steps = {} # Maps labels to steps.
+ me._stepseq = [] # Sequence of labels, in order.
+ me._pmap = {} # Maps primes to steps.
+ me._i = 0
+
+ def addstep(me, step):
+ """
+ Add a new STEP to the proof.
+
+ The STEP may have a label already. If not, a new internal label is
+ chosen. The proof step is checked before being added to the proof. The
+ label is returned.
+ """
+
+ ## If there's already a step for this prime, and the new step doesn't
+ ## have a label, then return the old one instead.
+ if step.label is None:
+ try: return me._pmap[step.p]
+ except KeyError: pass
+
+ ## Make sure the step is actually correct.
+ step.check()
+
+ ## Generate a label if the step doesn't have one already.
+ if step.label is None: step.label = '$t%d' % me._i; me._i += 1
+
+ ## If the label is already taken then we have a problem.
+ if step.label in me._steps:
+ raise ExpectedError('duplicate label `%s\'' % step.label)
+
+ ## Store the proof step.
+ me._pmap[step.p] = step.label
+ me._steps[step.label] = step
+ me._stepseq.append(step.label)
+ return step.label
+
+ def get_step(me, label):
+ """
+ Check that LABEL labels a known step, and return that step.
+ """
+ try: return me._steps[label]
+ except KeyError: raise ExpectedError('unknown label `%s\'' % label)
+
+ def write(me, file):
+ """
+ Write the proof to the given FILE.
+ """
+
+ ## Prefix the main steps with a `sievebits' line.
+ file.write('sievebits %d\n' % (2*(SIEVE.limit.bit_length() - 1)))
+
+ ## Write the steps out one by one.
+ for label in me._stepseq: me._steps[label].out(file)
+
+ def read(me, file):
+ """
+ Read a proof from a given FILE.
+
+ FILE ::= {STEP | CHECK | SIEVEBITS} [FILE]
+ STEP ::= SMALL-STEP | POCK-STEP
+
+ Comments (beginning `;') and blank lines are ignored. Other lines begin
+ with a keyword.
+ """
+ lastp = None
+ for lno, line in enumerate(file, 1):
+ line = line.strip()
+ if line.startswith(';'): continue
+ ww = line.split(None, 1)
+ if not ww: continue
+ w = ww[0]
+ if len(ww) > 1: tail = ww[1]
+ else: tail = ''
+ try:
+ try: op = me.STEPMAP[w]
+ except KeyError:
+ raise ExpectedError('unrecognized keyword `%s\'' % w)
+ step = op(me, tail)
+ if step is not None:
+ me.addstep(step)
+ lastp = step.p
+ except ExpectedError, e:
+ raise ExpectedError('%s:%d: %s' % (file.name, lno, e.message))
+ return lastp
+
+###--------------------------------------------------------------------------
+### Finding provable primes.
+
+class BasePrime (object):
+ """
+ I represent a prime number which has been found and can be proven.
+
+ This object can eventually be turned into a sequence of proof steps and
+ added to a PrimeProof. This isn't done immediately, because some
+ prime-search strategies want to build a pool of provable primes and will
+ then select some subset of them to actually construct the number of final
+ interest. This way, we avoid cluttering the output proof with proofs of
+ uninteresting numbers.
+
+ Protocol required.
+
+ p The prime number in question.
+
+ label(LABEL) Associate LABEL with this prime, and the corresponding proof
+ step. A label can be set in the constructor, or later using
+ this method.
+
+ register(PP) Register the prime with a PrimeProof, adding any necessary
+ proof steps. Returns the label of the proof step for this
+ number.
+
+ _mkstep(PP, **KW)
+ Return a proof step for this prime.
+ """
+ def __init__(me, label = None, *args, **kw):
+ """Initialize a provable prime number object."""
+ super(BasePrime, me).__init__(*args, **kw)
+ me._index = me._pp = None
+ me._label = label
+ def label(me, label):
+ """Set this number's LABEL."""
+ me._label = label
+ def register(me, pp):
+ """
+ Register the prime's proof steps with PrimeProof PP.
+
+ Return the final step's label.
+ """
+ if me._pp is not None:
+ assert me._pp == pp
+ else:
+ me._pp = pp
+ me._index = pp.addstep(me._mkstep(pp, label = me._label))
+ ##try: me._index = pp.addstep(me._mkstep(pp, label = me._label))
+ ##except: raise RuntimeError('generated proof failed sanity check')
+ return me._index
+
+class SmallPrime (BasePrime):
+ """I represent a prime small enough to be checked in isolation."""
+ def __init__(me, p, *args, **kw):
+ super(SmallPrime, me).__init__(*args, **kw)
+ me.p = p
+ def _mkstep(me, pp, **kw):
+ return SmallStep(pp, me.p, **kw)
+
+class PockPrime (BasePrime):
+ """I represent a prime proven using Pocklington's theorem."""
+ def __init__(me, p, a, qq, *args, **kw):
+ super(PockPrime, me).__init__(*args, **kw)
+ me.p = p
+ me._a = a
+ me._qq = qq
+ def _mkstep(me, pp, **kw):
+ return PockStep(pp, me._a, (me.p - 1)/prod((q.p for q in me._qq), 2),
+ [q.register(pp) for q in me._qq], **kw)
+
+def gen_small(nbits, label = None, p = None):
+ """
+ Return a new small prime.
+
+ The prime will be exactly NBITS bits long. The proof step will have the
+ given LABEL attached. Report progress to the ProgressReporter P.
+ """
+ while True:
+
+ ## Pick a random NBITS-bit number.
+ n = C.rand.mp(nbits, 1)
+ assert n.nbits == nbits
+
+ ## If it's probably prime, then check it against the small primes we
+ ## know. If it passes then we're done. Otherwise, try again.
+ if n.primep():
+ for q in SIEVE.smallprimes():
+ if q*q > n: return SmallPrime(n, label = label)
+ if n%q == 0: break
+
+def gen_pock(nbits, nsubbits = 0, label = None, p = ProgressReporter()):
+ """
+ Return a new prime provable using Pocklington's theorem.
+
+ The prime N will be exactly NBITS long, of the form N = 2 Q R + 1. If
+ NSUBBITS is nonzero, then each prime factor of Q will be NSUBBITS bits
+ long; otherwise a suitable default will be chosen. The proof step will
+ have the given LABEL attached. Report progress to the ProgressReporter P.
+
+ The prime numbers this function returns are a long way from being uniformly
+ distributed.
+ """
+
+ ## Pick a suitable value for NSUBBITS if we don't have one.
+ if not nsubbits:
+
+ ## This is remarkably tricky. Picking about 1/3 sqrt(NBITS) factors
+ ## seems about right for large numbers, but there's serious trouble
+ ## lurking for small sizes.
+ nsubbits = int(3*M.sqrt(nbits))
+ if nbits < nsubbits + 3: nsubbits = nbits//2 + 1
+ if nbits == 2*nsubbits: nsubbits += 1
+
+ ## Figure out how many subgroups we'll need.
+ npiece = ((nbits + 1)//2 + nsubbits - 1)//nsubbits
+ p.push()
+
+ ## Keep searching...
+ while True:
+
+ ## Come up with a collection of known prime factors.
+ p.p('!'); qq = [gen(nsubbits, p = p) for i in xrange(npiece)]
+ Q = prod(q.p for q in qq)
+
+ ## Come up with bounds on the cofactor. If we're to have N = 2 Q R + 1,
+ ## and 2^{B-1} <= N < 2^B, then we must have 2^{B-2}/Q <= R < 2^{B-1}/Q.
+ Rbase = (C.MP(0).setbit(nbits - 2) + Q - 1)//Q
+ Rwd = C.MP(0).setbit(nbits - 2)//Q
+
+ ## Probe the available space of cofactors. If the space is kind of
+ ## narrow, then we want to give up quickly if we're not finding anything
+ ## suitable.
+ step = 0
+ while step < Rwd:
+ step += 1
+
+ ## Pick a random cofactor and examine the number we ended up with.
+ ## Make sure it really does have the length we expect.
+ R = C.rand.range(Rwd) + Rbase
+ n = 2*Q*R + 1
+ assert n.nbits == nbits
+
+ ## As a complication, if NPIECE is 1, it's just about possible that Q^2
+ ## <= n, in which case this isn't going to work.
+ if Q*Q < n: continue
+
+ ## If n has small factors, then pick another cofactor.
+ if C.PrimeFilter.smallfactor(n) == C.PGEN_FAIL: continue
+
+ ## Work through the small primes to find a suitable generator. The
+ ## value 2 is almost always acceptable, so don't try too hard here.
+ for a in I.islice(SIEVE.smallprimes(), 16):
+
+ ## First, try the Fermat test. If that fails, then n is definitely
+ ## composite.
+ if pow(a, n - 1, n) != 1: p.p('.'); break
+ p.p('*')
+
+ ## Work through the subgroup orders, checking that suitable powers of
+ ## a generate the necessary subgroups.
+ for q in qq:
+ if n.gcd(pow(a, (n - 1)/q.p, n) - 1) != 1:
+ p.p('@'); ok = False; break
+ else:
+ ok = True
+
+ ## we're all good.
+ if ok: p.pop(); return PockPrime(n, a, qq, label = label)
+
+def gen(nbits, label = None, p = ProgressReporter()):
+ """
+ Generate a prime number with NBITS bits.
+
+ Give it the LABEL, and report progress to P.
+ """
+ if SIEVE.limit >> (nbits + 1)/2: g = gen_small
+ else: g = gen_pock
+ return g(nbits, label = label, p = p)
+
+def gen_limlee(nbits, nsubbits,
+ label = None, qlfmt = None, p = ProgressReporter()):
+ """
+ Generate a Lim--Lee prime with NBITS bits.
+
+ Let p be the prime. Then we'll have p = 2 q_0 q_1 ... q_k, with all q_i at
+ least NSUBBITS bits long, and all but q_k exactly that long.
+
+ The prime will be given the LABEL; progress is reported to P. The factors
+ q_i will be labelled by filling in the `printf'-style format string QLFMT
+ with the argument i.
+ """
+
+ ## Figure out how many factors (p - 1)/2 will have.
+ npiece = nbits//nsubbits
+ if npiece < 2: raise ExpectedError('too few pieces')
+
+ ## Decide how big to make the pool of factors.
+ poolsz = max(3*npiece + 5, 25) # Heuristic from GnuPG
+
+ ## Prepare for the main loop.
+ disp = nstep = 0
+ qbig = None
+ p.push()
+
+ ## Try to make a prime.
+ while True:
+ p.p('!')
+
+ ## Construct a pool of NSUBBITS-size primes. There's a problem with very
+ ## small sizes: we might not be able to build a pool of distinct primes.
+ pool = []; qmap = {}
+ for i in xrange(poolsz):
+ for j in xrange(64):
+ q = gen(nsubbits, p = p)
+ if q.p not in qmap: break
+ else:
+ raise ExpectedError('insufficient diversity')
+ qmap[q.p] = q
+ pool.append(q)
+
+ ## Work through combinations of factors from the pool.
+ for qq in combinations(npiece - 1, pool):
+
+ ## Construct the product of the selected factors.
+ qsmall = prod(q.p for q in qq)
+
+ ## Maybe we'll need to replace the large factor. Try not to do this
+ ## too often. DISP measures the large factor's performance at
+ ## producing candidates with the right length. If it looks bad then
+ ## we'll have to replace it.
+ if 3*disp*disp > nstep*nstep:
+ qbig = None
+ if disp < 0: p.p('<')
+ else: p.p('>')
+
+ ## If we don't have a large factor, then make one.
+ if qbig is None:
+ qbig = gen(nbits - qsmall.nbits, p = p)
+ disp = 0; nstep = 0
+
+ ## We have a candidate. Calculate it and make sure it has the right
+ ## length.
+ n = 2*qsmall*qbig.p + 1
+ nstep += 1
+ if n.nbits < nbits: disp -= 1
+ elif n.nbits > nbits: disp += 1
+ elif C.PrimeFilter.smallfactor(n) == C.PGEN_FAIL: pass
+ else:
+
+ ## The candidate has passed the small-primes test. Now check it
+ ## against Pocklington.
+ for a in I.islice(SIEVE.smallprimes(), 16):
+
+ ## Fermat test.
+ if pow(a, n - 1, n) != 1: p.p('.'); break
+ p.p('*')
+
+ ## Find a generator of a sufficiently large subgroup.
+ if n.gcd(pow(a, (n - 1)/qbig.p, n) - 1) != 1: p.p('@'); continue
+ ok = True
+ for q in qq:
+ if n.gcd(pow(a, (n - 1)/q.p, n) - 1) != 1:
+ p.p('@'); ok = False; break
+
+ ## We're done.
+ if ok:
+
+ ## Label the factors.
+ qq.append(qbig)
+ if qlfmt:
+ for i, q in enumerate(qq): q.label(qlfmt % i)
+
+ ## Return the number we found.
+ p.pop(); return PockPrime(n, a, qq, label = label)
+
+###--------------------------------------------------------------------------
+### Main program.
+
+def __main__():
+ global VERBOSITY
+
+ ## Prepare an option parser.
+ op = OP.OptionParser(
+ usage = '''\
+pock [-qv] [-s SIEVEBITS] CMD ARGS...
+ gen NBITS
+ ll NBITS NSUBBITS
+ check [FILE]''',
+ description = 'Generate or verify certified prime numbers.')
+ op.add_option('-v', '--verbose', dest = 'verbosity',
+ action = 'count', default = 1,
+ help = 'print mysterious runes while looking for prime numbers')
+ op.add_option('-q', '--quiet', dest = 'quietude',
+ action = 'count', default = 0,
+ help = 'be quiet while looking for prime numbers')
+ op.add_option('-s', '--sievebits', dest = 'sievebits',
+ type = 'int', default = 32,
+ help = 'size (in bits) of largest small prime')
+ opts, argv = op.parse_args()
+ VERBOSITY = opts.verbosity - opts.quietude
+ p = ProgressReporter()
+ a = ArgFetcher(argv, op.error)
+
+ ## Process arguments and do what the user asked.
+ w = a.arg()
+
+ if w == 'gen':
+ ## Generate a prime with no special structure.
+ initsieve(opts.sievebits)
+ nbits = a.int(min = 4)
+ pp = PrimeProof()
+ p = gen(nbits, 'p', p = p)
+ p.register(pp)
+ pp.write(stdout)
+
+ elif w == 'll':
+ ## Generate a Lim--Lee prime.
+ initsieve(opts.sievebits)
+ nbits = a.int(min = 4)
+ nsubbits = a.int(min = 4, max = nbits)
+ pp = PrimeProof()
+ p = gen_limlee(nbits, nsubbits, 'p', 'q_%d', p = p)
+ p.register(pp)
+ pp.write(stdout)
+
+ elif w == 'check':
+ ## Check an existing certificate.
+ fn = a.arg(default = '-', must = False)
+ if fn == '-': f = stdin
+ else: f = open(fn, 'r')
+ pp = PrimeProof()
+ p = pp.read(f)
+
+ else:
+ raise ExpectedError("unknown command `%s'" % w)
+
+if __name__ == '__main__':
+ prog = OS.path.basename(argv[0])
+ try: __main__()
+ except ExpectedError, e: exit('%s: %s' % (prog, e.message))
+ except IOError, e: exit('%s: %s' % (prog, e))
+
+###----- That's all, folks --------------------------------------------------
--- /dev/null
+.\" -*-nroff-*-
+.\"
+.\" Describe the primality certificate generator and checker
+.\"
+.\" (c) 2016 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.
+.
+.ie t \{\
+. if \n(.g \{\
+. fam P
+. \}
+. ds o \(bu
+. ds ss \s7\v'-4p'
+. ds se \v'4p'\s0
+. ds us \s7\v'2p'
+. ds ue \v'-2p'\s0
+. ds *e \(*e
+. ds mo \(mo
+. ds sr \(sr
+. ds cu \(cu
+. ds ca \(ca
+. ds iy \(if
+. ds == \(==
+. ds .. \&.\h'2p'.\h'2p'.\&
+. ds /= \h'(\w'\*(=='-\w'/')/2'/\h'-(\w'\*(=='+\w'/')/2'\*(==
+.\}
+.el \{\
+. ds o o
+. ds ss ^
+. ds se
+. ds us _
+. ds ue
+. ds *e \fIepsilon\fP
+. ds mo in
+. ds sr sqrt
+. ds cu union
+. ds ca isect
+. ds iy infty
+. ds == ==
+. ds .. \&...\&
+. ds /= /==
+.\}
+.de hP
+.IP
+\h'-\w'\fB\\$1\ \fP'u'\fB\\$1\ \fP\c
+..
+.
+.TH pock 1 "28 May 2017" "Straylight/Edgeware" "Catacomb cryptographic library"
+.SH NAME
+pock \- generate and verify primality certificates
+.
+.\"--------------------------------------------------------------------------
+.SH SYNOPSIS
+.
+.B pock
+.RB [ \-qv ]
+.I command
+.IR [ arguments ...]
+.PP
+Subcommands:
+.RS
+.br
+.B gen
+.I nbits
+.br
+.B ll
+.I nbits
+.I nsubbits
+.br
+.B check
+.RI [ file ]
+.RE
+.
+.\"--------------------------------------------------------------------------
+.SH DESCRIPTION
+.
+Many cryptographic protocols make use of large prime numbers.
+The usual way of determining primality in such circumstances
+is due to Rabin and Miller.
+Given a candidate
+.I n
+and a
+.I witness
+2 \(<=
+.I a
+<
+.IR n ,
+the test answers either `composite' or `unknown'.
+If
+.I n
+is prime then the test answers `unknown' for every witness
+.IR a ;
+if
+.I n
+is in fact composite
+then the test answers `composite'
+for at least three quarters of the possible witnesses.
+If
+.I n
+is a composite,
+then the witnesses
+.I a
+for which the test reports `unknown'
+are called
+.IR liars .
+.PP
+Naively, then,
+to reduce the probability of falsely accepting a composite
+below some bound \*(*e,
+one must perform
+\-(log\*(us2\*(ue \*(*e)/2
+iterations of the test,
+with independent, uniformly distributed witnesses.
+This is especially slow when high security levels are wanted,
+both because tests take longer on larger candidate numbers,
+and because one must do more tests
+to reach the necessary higher confidence level.
+.PP
+The above is a worst-case bound:
+very few composite numbers
+.I n
+have anywhere near
+.IR n /4
+liars.
+In situations such as RSA key generation,
+the user generating the prime number is the only one
+who must be convinced of the number's primality,
+and they have valuable additional knowledge:
+specifically that the candidate has been chosen at random
+according to some suitable probability distribution.
+In this case, one needs many fewer iterations,
+and the number of iterations needed
+.I decreases
+with the size of the candidate being tested.
+.PP
+But in cases where many users must share some large prime parameter,
+each of them must test the proposed prime separately,
+and often they must pessimistically assume
+that the number was chosen maliciously,
+and the worst-case
+.IR n /4
+bound is the best one can do using the Rabin\(enMiller test.
+For large candidates,
+this is inconveniently slow.
+(Also, many implementations incorrectly use
+a number of iterations suitable for randomly chosen primes
+for testing candidates of unknown provenance.)
+.PP
+There
+.I are
+stronger probabilistic tests.
+A combination of Rabin\(enMiller and
+Grantham's Frobenius test
+is known as the
+Baillie\(enPSW test
+(after Baillie, Pomerance, Selfridge, and Wagstaff);
+there are
+.I no
+known composites which pass this test,
+nor is it known how to construct any.
+On the other hand, it's been conjectured that
+infinitely many Baillie\(enPSW pseudoprimes exist.
+While it may be reasonable to assume
+the strength of the Baillie\(enPSW test,
+it must be borne in mind that this
+.I does
+constitute a security assumption.
+.PP
+By contrast,the
+.B pock
+program will generate prime numbers
+of sizes suitable for use in cryptography,
+along with a
+.I certificate of primality
+which can be independently verified fairly efficiently.
+Specifically, verifying a proof takes a little longer
+than a single iteration of the Rabin\(enMiller probabilistic test.
+It can also verify such certificates.
+.PP
+Note that the primes selected by
+.B pock
+are a long way from uniformly distributed.
+Indeed, they have somewhat unusual structure,
+but it seems unlikely that this structure
+renders them unsuitable for e.g., discrete-logarithm cryptography.
+.
+.SS "Command line"
+The following options are recognized.
+.TP
+.B "\-h, \-\-help"
+Write help text to standard output and exit with status 0.
+.TP
+.B "\-q, \-\-quiet"
+Be less verbose during prime generation or certificate verification.
+.TP
+.B "\-v, \-\-verbose"
+Be more verbose during prime generation or certificate verification.
+.TP
+.BI "\-s, \-\-sievebits " b
+When generating certificates,
+require that the verifier can check numbers smaller than
+.RI 2\*(ss b \*(se
+without assistance.
+Larger values lead to sightly shorter proofs,
+but spend more time at startup constructing a sieve;
+smaller values lead to somewhat longer proofs,
+but spend less time constructing the sieve.
+The default is 32,
+which seems to work well in practice.
+.
+.SS "gen"
+The
+.B gen
+command generates a prime
+.I p
+which is
+.I nbits
+long (i.e.,
+.RI 2\*(ss nbits \-1\*(se
+<
+.I p
+<
+.RI 2\*(ss nbits \*(se,
+and writes a certificate to standard output.
+By default, mysterious runes are written to standard error
+to keep the user amused and informed about the operation's progress;
+the
+.B \-q
+option suppresses the runes;
+the
+.B \-v
+option produces more detailed runes.
+.
+.SS "ll"
+The
+.B ll
+command generates a Lim\(enLee prime
+.I p
+=
+2
+.IR q \*(us0\*(ue
+.IR q \*(us1\*(ue
+\*(..
+.IR q \*(us k \*(ue
++
+1
+which is
+.I nbits
+long (i.e.,
+.RI 2\*(ss nbits \-1\*(se
+<
+.I p
+<
+.RI 2\*(ss nbits \*(se,
+such that each
+.IR q \*(us i \*(ue
+is an
+.IR nsubbits -bit
+prime, for
+0 \(<=
+.I i
+<
+.IR k ,
+and
+.IR q \*(us k \*(ue
+is an
+.IR nsubbits -bit
+prime,
+and writes a certificate to standard output.
+By default, mysterious runes are written to standard error
+to keep the user amused and informed about the operation's progress;
+the
+.B \-q
+option suppresses the runes;
+the
+.B \-v
+option produces more detailed runes.
+.
+.SS "check"
+The
+.B check
+command reads a primality certificate from the named
+.I file
+or from standard input,
+and checks it.
+By default,
+each
+.B check
+line in the certificate causes a line
+.IP
+.B ;;
+.I label
+.B =
+.I n
+.BI [ b ]
+.PP
+to be printed to standard output,
+listing the prime's
+.IR label ,
+value
+.IR n ,
+and length
+.I b
+in bits;
+this behaviour is inhibited by the
+.B \-q
+option.
+.
+.SS Runes
+The following mysterious runes are printed during prime searches.
+This information is provided for diagnostic purposes
+and to satisfy idle curiosity:
+later versions may print different runes,
+or use the same rune characters to mean different things.
+.TP
+.B !
+Started to generate a large prime.
+The next step is to generate a number of smaller primes.
+Usually, this will only need to be done once.
+.TP
+.B .
+Candidate failed a Fermat test.
+.TP
+.B *
+Candidate passed a Fermat test.
+This is usually the last rune for a prime search.
+.TP
+.B @
+A candidate generator failed to generate the necessary subgroup.
+This is unusual.
+.TP
+.B <
+For Lim\(enLee primes,
+discarding the large prime
+because it produces results which are too small.
+.TP
+.B >
+For Lim\(enLee primes,
+discarding the large prime
+because it produces results which are too large.
+.TP
+.B [
+Starting a subsidiary prime search.
+.TP
+.B ]
+Finished a subsidiary prime search.
+.
+.\"--------------------------------------------------------------------------
+.SH CERTIFICATE FORMAT
+.
+A certificate consists of a number of lines.
+Blank lines,
+and lines beginning with a
+.RB ` ; ',
+are ignored.
+Other lines are as follows.
+.TP
+.BI "sievebits " b
+Declares that the verifier is expected to be able to check
+primes smaller than
+.RI 2\*(ss b \*(se
+for primality for itself.
+A
+.B sievebits
+line must appear before the first
+.B small
+line.
+.TP
+.BI "small " label " = " p
+Asserts that
+.I p
+is a small prime,
+and associates it with the
+.IR label .
+It is an error if the label has been assigned by a previous line.
+It is required that
+1 <
+.I p
+<
+.RI 2\*(ss b \*(se
+and that
+.I p
+is prime.
+Such small primes constitute the leaves of a proof tree.
+.TP
+.BI "pock " label " = " a ", " R ", [" i ", " j ", \fR\*(..\fB]"
+Asserts that a number
+.I n
+(defined below) is prime by Pocklington's criterion,
+and associates it with the
+.IR label .
+It is an error if the label has been assigned by a previous line.
+.RS
+.PP
+The strings
+.IR i ,
+.IR j ,
+\*(..
+must be labels assigned by earlier lines.
+For each such label
+.IR i ,
+let
+.IR q \*(us i \*(ue
+be the associated prime.
+Let
+.I Q
+=
+.IR q \*(us i \*(ue
+.IR q \*(us j \*(ue
+\*(..
+be the product of these primes.
+Let
+.I n
+=
+.RI 2 QR
++
+1.
+It is required that:
+.hP 1.
+The
+.IR q \*(us i \*(ue
+are distinct.
+.hP 2.
+.IR Q \*(ss2\*(se
+\(>=
+.IR n .
+.hP 3.
+.IR a \*(ss n \-1\*(se
+\*(==
+1
+(mod
+.IR n ).
+.hP 4.
+.RI gcd( a \*(ss( n \-1)/ q \*(se
+\-
+1,
+.IR n )
+=
+1
+for each prime
+.IR q
+dividing
+.IR Q .
+.PP
+To see why this works, let
+.I p
+be the smallest prime factor of
+.IR n .
+From
+.B 3
+we see that
+the order of
+.I a
+in
+.RB ( Z /\fIp Z )\*(ss\(**\*(se
+divides
+.I n
+\-
+1.
+Consider some prime
+.I q
+dividing
+.I Q
+and let
+.I t
+=
+.IR a \*(ss( n \-1)/ q \*(se;
+then
+.I t
+has order dividing
+.IR q .
+From
+.BR 4 ,
+we have
+.I t
+\*(/=
+1
+(mod
+.IR p ),
+and hence
+.I t
+has order precisely
+.I q
+in
+.RB ( Z /\fIp Z )\*(ss\(**\*(se.
+This implies that
+.I q
+divides
+.I p
+\-
+1.
+Since this holds for each prime
+.I q
+dividing
+.IR Q ,
+and,
+from
+.BR 1 ,
+these primes are distinct,
+we deduce that
+.I Q
+divides
+.I p
+\-
+1
+and hence that
+.I p
+>
+.IR Q .
+Let
+.IR p \(fm
+be any prime factor of
+.IR n / p .
+Then
+.IR p \(fm
+\(>=
+.I p
+>
+.I Q
+so,
+from
+.BR 2 ,
+.IR pp \(fm
+>
+.IR Q \*(ss2\*(se
+\(>=
+.IR n ;
+but
+.IR pp \(fm
+divides
+.I n
+so this is a contradiction.
+We must conclude that
+.IR p \(fm
+does not exist,
+and
+.I n
+must be prime.
+.RE
+.TP
+.BI "ecpp " label " = " n ", " A ", " B ", " x ", " y ", [" i ", " j ", \fR\*(..\fB]"
+Asserts that the number
+.I n
+is prime by Goldwasser and Kilian's ECPP method,
+and associates it with the
+.IR label .
+It is an error if the label has been assigned by a previous line.
+.RS
+.PP
+The strings
+.IR i ,
+.IR j ,
+\*..
+must be labels assigned by earlier lines.
+For each such label
+.IR i ,
+let
+.IR q \*(us i \*(ue
+be the associated prime.
+Let
+.I Q
+=
+.IR q \*(us i \*(ue
+.IR q \*(us j \*(ue
+\*(..
+be the product of these primes.
+Define
+.I E\*(usn\*(ue
+= {
+.RI ( x ", " y )
+\*(mo
+.RB ( Z /\fIn Z )\*(ss2\*(se
+|
+.IR y \*(ss2\*(se
+=
+.IR x \*(ss3\*(se
++
+.I Ax
++
+.I B
+}
+\*(cu
+{ \*(iy };
+if
+.I n
+is prime and the curve is not singular
+then this is the elliptic curve over
+.RI GF( n )
+with short-Weierstrass coefficients
+.I A
+and
+.IR B .
+Let
+.I R
+=
+.RI ( x ,
+.IR y ).
+It is required that:
+.hP 1.
+.I g
+=
+.RI gcd(4 a \*(ss3\*(se
++
+.RI 27 b \*(ss2\*(se,
+.IR n )
+= 1.
+.hP 2.
+.I R
+\*(mo
+.IR E\*(usn\*(ue ;
+i.e.,
+.IR y \*(ss2\*(se
+\*(==
+.IR x \*(ss3\*(se
++
+.I Ax
++
+.I B
+(mod
+.IR n ).
+.hP 3. The
+.I q\*(usi\*(ue
+are distinct.
+.hP 4.
+.IR QR ,
+the elliptic-curve scalar product of the point
+.I R
+by the integer
+.IR Q ,
+calculated as if
+.I E
+is a true elliptic curve,
+is the point at infinity.
+.hP 5.
+.RI ( Q / q ) R
+is finite for each prime
+.I q
+dividing
+.IR Q .
+.hP 6.
+.I Q
+>
+.RI ( n \*(ss1/4\*(se
++ 1)\*(ss2\*(se.
+.PP
+To see why this test works, let
+.I p
+be the smallest prime factor of
+.IR n ,
+and let
+.I E\*(usp\*(ue
+= {
+.RI ( x ", " y )
+\*(mo
+.RI GF( p )\*(ss2\*(se
+|
+.IR y \*(ss2\*(se
+=
+.IR x \*(ss3\*(se
++
+.I Ax
++
+.I B
+}
+\*(cu
+{ \*(iy }.
+From
+.BR 1 ,
+.I g
+= 1,
+.I E\*(usp\*(ue
+is an elliptic curve.
+(If 1 <
+.I g
+<
+.I n
+then
+.I g
+is a proper factor of
+.I n
+and
+.I n
+is certainly not prime;
+if
+.I g
+=
+.I n
+then the curve will be singular and the test fails.)
+From
+.BR 2 ,
+.I R
+is a point on
+.IR E\*(usp\*(ue .
+From
+.BR 4 ,
+.I R
+has
+.IR Q -torsion
+in
+.IR E\*(usp\*(ue .
+Consider some prime
+.I q
+dividing
+.I Q
+and let
+.I T
+=
+.RI ( Q/q ) R ;
+then
+.I T
+has torsion dividing
+.IR q .
+From
+.BR 5 ,
+.RI ( Q/q ) R
+\(!= 0,
+and hence
+.I T
+has order precisely
+.I q
+in
+.IR E\*(usp\*(ue .
+This implies that
+.I q
+divides
+.RI # E\*(usp\*(ue .
+Since this holds for each prime
+.I q
+dividing
+.IR Q ,
+and, from
+.BR 3 ,
+the
+.I q
+are distinct,
+we deduce that
+.I Q
+divides
+.RI # E\*(usp\*(ue
+and hence that
+.RI # E\*(usp\*(ue
+\(>=
+.IR Q .
+Hasse's theorem tells us that
+.RI | p
++ 1 \-
+.RI # E\*(usp\*(ue |
+\(<=
+.RI 2\*(sr p ,
+so, in particular,
+.RI # E\*(usp\*(ue
+\-
+.I p
+\- 1
+\(<=
+.RI 2\*(sr p ,
+whence
+.I p
++ 1 +
+.RI 2\*(sr p
+=
+.RI (\*(sr p
++ 1)\*(ss2\*(se
+\(>=
+.RI # E\*(usp\*(ue
+\(>=
+.IR Q
+>
+.RI ( n \*(ss1/4\*(se
++ 1)\*(ss2\*(se
+(from
+.BR 6 );
+so
+.IR p\*(ss2\*(se
+>
+.IR n .
+Let
+.IR p \(fm
+be any prime factor of
+.IR n / p .
+Then
+.IR p \(fm
+\(>=
+.I p
+and
+.IR pp \(fm
+\(>=
+.IR p \*(ss2\*(se
+>
+.IR n ;
+but
+.IR pp \(fm
+divides
+.I n
+so this is a contradiction.
+We must conclude that
+.IR p \(fm
+does not exist,
+and
+.I n
+must be prime.
+.PP
+Note that
+.B pock
+currently cannot generate proofs which use
+.BR ecpp ,
+though it will verify them.
+.RE
+.TP
+.BI "check " label ", " b ", " p
+Verify that the prime associated with the
+.I label
+is equal to
+.I p
+and that it is
+.I b
+bits long;
+i.e., that
+.RI 2\*(ss b \-1\*(se
+\(<=
+.I p
+<
+.RI 2\*(ss b \*(se.
+Unless
+inhibited by
+.BR \-q ,
+the label and value are printed to stdout during verification.
+.
+.\"--------------------------------------------------------------------------
+.SH "SEE ALSO"
+.BR key (1).
+.SH AUTHOR
+Mark Wooding, <mdw@distorted.org.uk>
+.
+.\"----- That's all, folks --------------------------------------------------
{
PyObject *G, *p, *rng = rand_pyobj, *hash = sha_pyobj;
PyObject *rc = 0;
- char *kwlist[] = { "G", "p", "hash", "rng", 0 };
+ static const char *const kwlist[] = { "G", "p", "hash", "rng", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", KWLIST,
group_pytype, &G,
ge_pytype, &p,
gchash_pytype, &hash,
static PyObject *dsameth_beginhash(PyObject *me, PyObject *arg)
{
if (!PyArg_ParseTuple(arg, ":beginhash")) return (0);
- return (ghash_pywrap(DSA_HASH(me), gdsa_beginhash(DSA_D(me)), f_freeme));
+ return (ghash_pywrap(DSA_HASH(me), gdsa_beginhash(DSA_D(me))));
}
static PyObject *dsameth_endhash(PyObject *me, PyObject *arg)
Py_ssize_t n;
mp *k = 0;
PyObject *rc = 0;
- char *kwlist[] = { "msg", "k", 0 };
+ static const char *const kwlist[] = { "msg", "k", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:sign", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:sign", KWLIST,
&p, &n, convmp, &k))
goto end;
if (n != DSA_D(me)->h->hashsz)
{
PyObject *G, *p = 0, *u, *rng = rand_pyobj, *hash = sha_pyobj;
PyObject *rc = 0;
- char *kwlist[] = { "G", "u", "p", "hash", "rng", 0 };
+ static const char *const kwlist[] = { "G", "u", "p", "hash", "rng", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", KWLIST,
group_pytype, &G,
&u,
ge_pytype, &p,
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"DSA public key information.",
+"DSAPub(GROUP, P, [hash = sha], [rng = rand]): DSA public key.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"DSA private key information.",
+"DSAPriv(GROUP, U, [p = u G], [hash = sha], [rng = rand]): DSA private key.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
PyObject *G, *p, *rng = rand_pyobj, *hash = has160_pyobj;
PyObject *rc = 0;
- char *kwlist[] = { "G", "p", "hash", "rng", 0 };
+ static const char *const kwlist[] = { "G", "p", "hash", "rng", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", KWLIST,
group_pytype, &G,
ge_pytype, &p,
gchash_pytype, &hash,
{
PyObject *G, *u, *p = 0, *rng = rand_pyobj, *hash = has160_pyobj;
PyObject *rc = 0;
- char *kwlist[] = { "G", "u", "p", "hash", "rng", 0 };
+ static const char *const kwlist[] = { "G", "u", "p", "hash", "rng", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", KWLIST,
group_pytype, &G,
&u,
ge_pytype, &p,
static PyObject *kcdsameth_beginhash(PyObject *me, PyObject *arg)
{
if (!PyArg_ParseTuple(arg, ":beginhash")) return (0);
- return (ghash_pywrap(DSA_HASH(me), gkcdsa_beginhash(DSA_D(me)), f_freeme));
+ return (ghash_pywrap(DSA_HASH(me), gkcdsa_beginhash(DSA_D(me))));
}
static PyObject *kcdsameth_endhash(PyObject *me, PyObject *arg)
Py_ssize_t n;
mp *k = 0;
PyObject *r = 0, *rc = 0;
- char *kwlist[] = { "msg", "k", 0 };
+ static const char *const kwlist[] = { "msg", "k", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:sign", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:sign", KWLIST,
&p, &n, convmp, &k))
goto end;
if (n != DSA_D(me)->h->hashsz)
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"KCDSA public key information.",
+"KCDSAPub(GROUP, P, [hash = sha], [rng = rand]): KCDSA public key.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"KCDSA private key information.",
+"KCDSAPriv(GROUP, U, [p = u G], [hash = sha], [rng = rand]): KCDSA private key.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
rsa_pub rp = { 0 };
rsapub_pyobj *o;
- char *kwlist[] = { "n", "e", 0 };
+ static const char *const kwlist[] = { "n", "e", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", KWLIST,
convmp, &rp.n, convmp, &rp.e))
goto end;
if (!MP_ODDP(rp.n)) VALERR("RSA modulus must be even");
{
rsa_priv rp = { 0 };
PyObject *rng = Py_None;
- char *kwlist[] =
+ static const char *const kwlist[] =
{ "n", "e", "d", "p", "q", "dp", "dq", "q_inv", "rng", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&O&O&O&O&O&O&O&O:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&O&O&O&O&O&O&O&O:new", KWLIST,
convmp, &rp.n, convmp, &rp.e,
convmp, &rp.d,
convmp, &rp.p, convmp, &rp.q,
PyObject *rng = RSA_RNG(me);
mp *x = 0;
PyObject *rc = 0;
- char *kwlist[] = { "x", "rng", 0 };
+ static const char *const kwlist[] = { "x", "rng", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O:privop", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O:privop", KWLIST,
convmp, &x, &rng))
goto end;
if (rng != Py_None && !GRAND_PYCHECK(rng))
mp *e = 0;
struct excinfo exc = EXCINFO_INIT;
pypgev evt = { { 0 } };
- char *kwlist[] = { "class", "nbits", "event", "rng", "nsteps", "e", 0 };
+ static const char *const kwlist[] =
+ { "class", "nbits", "event", "rng", "nsteps", "e", 0 };
PyObject *rc = 0;
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", KWLIST,
&me, convuint, &nbits, convpgev, &evt,
convgrand, &r, convuint, &n,
convmp, &e))
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"RSA public key information.",
+"RSAPub(N, E): RSA public key.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"RSA private key information.",
+"RSAPriv(..., [rng = rand]): RSA private key.\n\
+ Keywords: n, e, d, p, q, dp, dq, q_inv; must provide enough",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
octet *b = 0;
size_t sz;
mp *x;
- char *kwlist[] = { "msg", "nbits", "ep", "rng", 0 };
+ static const char *const kwlist[] = { "msg", "nbits", "ep", "rng", 0 };
p1.r = &rand_global; ep = 0; epsz = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|s#O&:encode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|s#O&:encode", KWLIST,
&m, &msz, convulong, &nbits,
&ep, &epsz, convgrand, &p1.r))
goto end;
octet *b = 0;
size_t sz;
mp *x = 0;
- char *kwlist[] = { "ct", "nbits", "ep", "rng", 0 };
+ static const char *const kwlist[] = { "ct", "nbits", "ep", "rng", 0 };
p1.r = &rand_global; ep = 0; epsz = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|s#O&:decode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|s#O&:decode", KWLIST,
convmp, &x, convulong, &nbits,
&ep, &epsz, convgrand, &p1.r))
goto end;
octet *b = 0;
size_t sz;
mp *x;
- char *kwlist[] = { "msg", "nbits", "ep", "rng", 0 };
+ static const char *const kwlist[] = { "msg", "nbits", "ep", "rng", 0 };
p1.r = &rand_global; ep = 0; epsz = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|s#O&:encode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|s#O&:encode", KWLIST,
&m, &msz, convulong, &nbits,
&ep, &epsz, convgrand, &p1.r))
goto end;
octet *b = 0;
size_t sz;
mp *x = 0;
- char *kwlist[] = { "msg", "sig", "nbits", "ep", "rng", 0 };
+ static const char *const kwlist[] =
+ { "msg", "sig", "nbits", "ep", "rng", 0 };
p1.r = &rand_global; ep = 0; epsz = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&|s#O&:decode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&O&|s#O&:decode", KWLIST,
&hukairz, convmp, &x, convulong, &nbits,
&ep, &epsz, convgrand, &p1.r))
goto end;
octet *b = 0;
size_t sz;
mp *x;
- char *kwlist[] = { "msg", "nbits", "mgf", "hash", "ep", "rng", 0 };
+ static const char *const kwlist[] =
+ { "msg", "nbits", "mgf", "hash", "ep", "rng", 0 };
o.r = &rand_global; o.cc = &sha_mgf; o.ch = &sha; ep = 0; epsz = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|O&O&s#O&:encode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|O&O&s#O&:encode", KWLIST,
&m, &msz, convulong, &nbits,
convgccipher, &o.cc,
convgchash, &o.ch,
octet *b = 0;
size_t sz;
mp *x = 0;
- char *kwlist[] = { "ct", "nbits", "mgf", "hash", "ep", "rng", 0 };
+ static const char *const kwlist[] =
+ { "ct", "nbits", "mgf", "hash", "ep", "rng", 0 };
o.r = &rand_global; o.cc = &sha_mgf; o.ch = &sha; ep = 0; epsz = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|O&O&s#O&:decode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|O&O&s#O&:decode", KWLIST,
convmp, &x, convulong, &nbits,
convgccipher, &o.cc,
convgchash, &o.ch,
octet *b = 0;
size_t sz;
mp *x = 0;
- char *kwlist[] = { "msg", "nbits", "mgf", "hash", "saltsz", "rng", 0 };
+ static const char *const kwlist[] =
+ { "msg", "nbits", "mgf", "hash", "saltsz", "rng", 0 };
p.cc = &sha_mgf; p.ch = &sha; p.r = &rand_global; p.ssz = (size_t)-1;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|O&O&O&O&:encode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&|O&O&O&O&:encode", KWLIST,
&m, &msz, convulong, &nbits,
convgccipher, &p.cc,
convgchash, &p.ch,
size_t sz;
int n;
mp *x = 0;
- char *kwlist[] =
+ static const char *const kwlist[] =
{ "msg", "sig", "nbits", "mgf", "hash", "saltsz", "rng", 0 };
p.cc = &sha_mgf; p.ch = &sha; p.r = &rand_global; p.ssz = (size_t)-1;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&O&|O&O&O&O&:decode", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&O&|O&O&O&O&:decode", KWLIST,
&m, &msz, convmp, &x, convulong, &nbits,
convgccipher, &p.cc,
convgchash, &p.ch,
int ph = phdflt; \
PyObject *rc = 0; \
octet pp[ED##_PUBSZ]; \
- char *kwlist[] = { "key", "msg", "pub", "perso", "phflag", 0 }; \
+ static const char *const kwlist[] = \
+ { "key", "msg", "pub", "perso", "phflag", 0 }; \
if (!PyArg_ParseTupleAndKeywords(arg, kw, \
"s#s#|s#s#O&:" #ed "_sign", \
- kwlist, \
+ KWLIST, \
&k, &ksz, &m, &msz, &p, &psz, \
&c, &csz, convbool, &ph)) \
goto end; \
Py_ssize_t psz, csz = 0, msz, ssz; \
int ph = phdflt; \
PyObject *rc = 0; \
- char *kwlist[] = { "pub", "msg", "sig", "perso", "phflag", 0 }; \
+ static const char *const kwlist[] = \
+ { "pub", "msg", "sig", "perso", "phflag", 0 }; \
if (!PyArg_ParseTupleAndKeywords(arg, kw, \
"s#s#s#|s#O&:" #ed "_verify", \
- kwlist, \
+ KWLIST, \
&p, &psz, &m, &msz, &s, &ssz, \
&c, &csz, convbool, &ph)) \
goto end; \
def cmd_create(av):
## Default crypto-primitive selections.
- cipher = 'blowfish-cbc'
- hash = 'rmd160'
+ cipher = 'rijndael-cbc'
+ hash = 'sha256'
mac = None
## Parse the options.
--- /dev/null
+.\" -*-nroff-*-
+.\"
+.\" Describe the password safe
+.\"
+.\" (c) 2016 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.
+.
+.ie t \{\
+. if \n(.g \{\
+. fam P
+. \}
+. ds o \(bu
+.\}
+.el \{\
+. ds o o
+.\}
+.
+.de hP
+.IP
+\h'-\w'\fB\\$1\ \fP'u'\fB\\$1\ \fP\c
+..
+.
+.TH pwsafe 1 "13 May 2016" "Straylight/Edgeware" "Catacomb cryptographic library"
+.SH NAME
+pwsafe \- store passwords somewhat securely
+.
+.\"--------------------------------------------------------------------------
+.SH SYNOPSIS
+.
+.B pwsafe
+.RB [ \-f
+.IR file ]
+.I command
+.RI [ arguments
+\&...]
+.PP
+Subcommands:
+'RS
+.B changepp
+.br
+.B copy
+.I dest-file
+.RI [ glob-pattern ]
+.br
+.B create
+.RB [ \-c
+.IR cipher ]
+.RB [ \-d
+.IR db-type ]
+.RB [ \-h
+.IR hash ]
+.RB [ \-m
+.IR mac ]
+.RI [ pp-tag ]
+.br
+.B delete
+.I tag
+.br
+.RB [ find ]
+.I label
+.br
+.B list
+.RI [ glob-pattern ]
+.br
+.B store
+.I label
+.RI [ value ]
+.br
+.B to-pixie
+.RI [ label
+.RI [ pixie-tag ]]
+.br
+.B xfer
+.RB [ \-d
+.IR db-type ]
+.I dest-file
+.RE
+.
+.\"--------------------------------------------------------------------------
+.SH DESCRIPTION
+.
+The
+.B pwsafe
+command maintains a database of passwords
+or other short-ish textual secrets.
+Each password is identified by a
+.IR label .
+The database is ultimately protected by a master password.
+It should quite difficult for an adversary
+who has the database file(s)
+but not your master password
+to find out what any of the stored passwords are,
+or even what the labels are.
+.PP
+The
+.B pwsafe
+program will prompt you for the password as necessary.
+If you are running the Catacomb
+.BR pixie (1)
+then it will first ask the pixie for any necessary passwords,
+and use the pixie to remember the master password for a short while.
+.PP
+A number of database backends are available.
+.TP
+.B gdbm
+Uses the GDBM database library to store a database as a single file.
+Provided for compatibility;
+not recommended for new databases.
+.TP
+.B sqlite
+Uses the SQLite3 library to store a database as a single file.
+SQLite3 has good performance and integrity properties.
+.TP
+.B flat
+Stores the password database as a flat text file.
+Not recommended for large databases because performance will be bad,
+but the simple format admits easy hacking.
+.TP
+.B dir
+Stores the password database as a directory structure.
+This uses much more disk space than the alternatives,
+and enumerating passwords is slow,
+but the directory structure can easily be managed by
+a version control system such as Git.
+.PP
+The following command-line options are available.
+.TP
+.B "\-h, \-\-help"
+Print a help summary to standard output,
+and exit with status zero.
+.TP
+.B "\-v, \-\-version"
+Print the program's version number to standard output,
+and exit with status zero.
+.TP
+.B "\-u, \-\-usage"
+Print a very terse usage summary to standard output,
+and exit with status zero.
+.TP
+.BI "\-f, \-\-file=" file
+Use
+.I file
+as the password database file or directory.
+If this is not specified,
+then the value of the
+.B PWSAFE
+environment variable is used;
+if that too is unset, then the default
+.IB home /.pwsafe \fR,
+is used, where
+.I home
+is the value of the
+.B HOME
+environment variable.
+It is a fatal error if
+.B HOME
+is unset.
+.PP
+The provided commands are described in their own sections below.
+.
+.SS "create"
+Create a new, empty password database.
+As a safety check,
+the file/directory named by the top-level
+.B \-f
+option (or default value)
+must not exist.
+.PP
+You will be prompted (twice) for a master password for the database.
+.PP
+The optional positional argument is the tag
+by which the database's master password
+will be known to the passphrase pixie.
+The default tag is
+.BR pwsafe .
+.PP
+The following options are accepted.
+.TP
+.BI "\-c, \-\-cipher=" cipher
+Use the Catacomb
+.I cipher
+to encrypt blobs.
+Run
+.B catcrypt show cipher
+for a list.
+The default is
+.BR rijndael-cbc .
+.TP
+.BI "\-d, \-\-database=" db-type
+Use the
+.I db-type
+database backend.
+See above for a list of the supported backends.
+Note that
+.B gdbm
+and
+.B sqlite
+depend on external modules, and may not be available.
+The default is
+.BR flat .
+.TP
+.BI "\-h, \-\-hash=" hash
+Use the Catacomb
+.I hash
+for key derivation and password-label mangling.
+Run
+.B catcrypt show hash
+for a list.
+The default is
+.BR sha256 .
+.TP
+.BI "\-m, \-\-mac=" mac
+Use the Catacomb
+.I mac
+to protect the integrity of blobs.
+Run
+.B catcrypt show mac
+for a list.
+The default is
+.IR hash -hmac
+where
+.I hash
+is the hash function chosen by the
+.B \-h
+option.
+.
+.SS "changepp"
+Change the master password for a database.
+This will
+.I not
+re-encrypt all of the records,
+so its utility is somewhat limited.
+See also the
+.B copy
+command.
+The program will prompt you for
+the existing master password (if it's not known by the pixie)
+and the new one (twice, always).
+.
+.SS "copy"
+Copy password records from the
+.I file
+to the
+.I dest-file
+which must be an existing password database.
+If a
+.B glob-pattern
+is given,
+then only records whose
+.I label
+matches the pattern are copied;
+otherwise all password records are copied.
+Any existing passwords in the destination database with the same labels
+will be overwritten.
+.PP
+The destination need not use the same database backend
+or cryptographic parameters as the source.
+.PP
+You will be prompted for the necessary master passwords.
+.
+.SS "delete"
+Delete the password with the given
+.I label
+from the database.
+An error is reported if there is no such password.
+.PP
+You will be prompted for master password if necessary.
+.
+.SS "find"
+Write the password with the given label to standard output,
+followed by a newline.
+.PP
+You will be prompted for master password if necessary.
+.PP
+This is the default operation:
+as a convenience,
+you can write
+.IP
+.B pwsafe
+.I label
+.PP
+rather than
+.IP
+.B pwsafe
+.B find
+.I label
+.PP
+if the
+.I label
+isn't the same as any of
+.BR pwsafe 's
+command names.
+.
+.SS "list"
+Write the labels of the passwords in the database,
+one per line,
+to standard output.
+(If labels contain newline characters,
+you will end up with a mess.)
+If a
+.I glob-pattern
+is supplied,
+then only labels which match the pattern are written.
+.PP
+You will be prompted for master password if necessary.
+.
+.SS "store"
+Store a password, associating it with the given
+.IR label .
+.PP
+If a
+.I value
+is supplied on the command line,
+then it is used as the password value.
+(Note that command-line arguments can be seen
+by other users of the system,
+and may be recorded by the shell.
+This is usually a bad idea.)
+.PP
+As a special case, if the
+.I value
+is
+.BR \- ,
+then the password is read from the first line of standard input;
+the trailing newline is removed.
+The author commonly writes
+.IP
+.BI "gorp -fbase64 | pwsafe store " label " \-"
+.PP
+to set random passwords.
+.PP
+Finally, if no
+.I value
+is given,
+then
+.B pwsafe
+will prompt twice for the password.
+.PP
+You will be prompted for the master password if necessary
+.I before
+the new password value is fetched.
+.PP
+If there is an existing password with the same
+.I label
+then it is overwritten.
+.
+.SS "topixie"
+With no arguments,
+store
+.I all
+of the passwords in the database in the pixie,
+with correspondingly named tags.
+This is probably a bad idea.
+.PP
+With a
+.IR label ,
+store only the labelled password in the pixie.
+With a
+.IR pixie-tag ,
+use that as the tag;
+otherwise use the
+.IR label .
+.PP
+You will be prompted for the master password if necessary.
+.
+.SS "xfer"
+Create a new database containing all of the records of an existing one.
+.PP
+This works at the storage-backend level.
+The new database contains exactly the same metadata and passwords
+as the original.
+It is
+.I not
+necessary to enter a password:
+the blobs are simply copied over without being decrypted.
+.PP
+The following options are accepted.
+.TP
+.BI "\-d, \-\-database=" db-type
+Use the
+.I db-type
+database backend.
+See above for a list of the supported backends.
+Note that
+.B gdbm
+and
+.B sqlite
+depend on external modules, and may not be available.
+The default is
+.BR flat .
+.
+.\"--------------------------------------------------------------------------
+.SH TECHNICAL DETAILS
+.
+The password database contains two kinds of records:
+.I metadata records
+hold important information about the database itself,
+and particularly the various cryptographic options
+chosen when the database was created,
+and the various internal keys used to secure the database;
+while
+.I password records
+actually store your encrypted passwords.
+The various backends store these kinds records in different ways;
+see below for the gory details.
+.
+.SS Metadata
+The metadata records are as follows.
+.TP
+.B cipher
+The symmetric cipher used to encrypt data.
+This names a Catacomb
+.B cipher
+class.
+.TP
+.B hash
+The hash function used in various places.
+This names a Catacomb
+.B hash
+class.
+.TP
+.B key
+A blob,
+protected by the
+.I derived
+keys (see below),
+containing the
+.I main
+secrecy and integrity keys.
+The blob payload consists of the main secrecy and integrity keys,
+each prefixed by its 16-bit length (in network byte order)
+and concatenated.
+.TP
+.B mac
+The message authentication code used to protect integrity.
+This names a Catacomb
+.B mac
+class.
+.TP
+.B magic
+A blob containing a string
+used to construct the database keys for password records;
+see below.
+The magic string is chosen at random
+when the database is created,
+and never changes;
+it is the same length as the chosen hash function's output.
+The blob is protected by the
+.I main
+keys.
+.TP
+.B salt
+A random string
+mixed into the key derivation process.
+.TP
+.B tag
+The passphrase tag,
+used to identify the master password
+to the passphrase
+.BR pixie (1).
+.
+.SS Keys
+The following keys are used.
+.TP
+The \fImaster password\fP
+Remembered (hopefully) by the user;
+used to unlock the
+.I main
+keys.
+.TP
+The \fIderived\fP keys
+A secrecy and integrity pair,
+derived from the
+.I master password
+and
+salt using a hash function.
+.TP
+The \fImain\fP keys
+A secrecy and integrity pair,
+kept in a blob in the database
+(the
+.B key
+metadata item)
+protected by the
+.I derived
+keys.
+The main keys are generated at random
+when the database is created
+and they never change;
+the Catacomb default key lengths are used.
+.
+.SS Deriving keys from the master password
+The keys used for protecting the
+.I main
+secrecy and integrity keys
+are derived by hashing strings of the form
+.IB purpose : password \e0 salt \fR,
+where
+.I purpose
+is
+.B cipher
+or
+.B mac
+to derive the secrecy and integrity keys, respectively.
+The
+.I salt
+string is the value of the
+.B salt
+metadata item described below.
+.PP
+No attempt is made to make the key derivation slow;
+.B pwsafe
+takes the view that you are have been specifically targetted for attack
+by a well-resourced adversary,
+and that you
+.I will
+lose if your password is guessable.
+.
+.SS Making a blob
+A
+.I blob
+contains a
+.IR payload ,
+protecting its secrecy and integrity.
+A blob is constructed using a pair of secrecy and integrity keys;
+most blobs are protected with the
+.I main
+keys;
+the main keys themselves are protected with the
+.I derived
+keys.
+.PP
+The steps to construct a blob are as follows.
+.hP 1.
+Choose a random IV of the appropriate length for the chosen
+.BR cipher .
+.hP 2.
+Encrypt the blob payload
+using the chosen
+.B cipher
+with the secrecy key
+and the IV from step 1,
+to form a ciphertext.
+Prefix the ciphertext with the IV
+to form an augmented ciphertext.
+.hP 3.
+Compute a tag over the augmented ciphertext from step 2
+using the chosen
+.B mac
+with the integrity key.
+Prefix the augmented ciphertext with the tag
+to form the blob.
+.PP
+(It seems more usual to put the tag on the end of the ciphertext,
+but that turned out to be pointlessly harder to implement.)
+.
+.SS Password records
+Conceptually,
+password records are indexed with a textual
+.I label
+chosen by the user.
+But users may want to not only keep their passwords secret,
+but also information about
+.I which
+passwords they have.
+The
+.B pwsafe
+program attempts to maintain the privacy of password record labels,
+but it isn't completely successful, as we shall see.
+Most critically,
+the database backends tend to leak information about
+the
+.I order
+in which records were added into the database.
+.PP
+At the database backend,
+the key used for looking up a password record is a hash,
+in binary:
+specifically, it's a hash of
+the record label
+prefixed by the
+.I magic
+string which is the payload of the blob stored in the
+.B magic
+metadata record.
+.PP
+The value of the password record is a blob,
+protected by the
+.I main
+keys,
+whose payload consists of
+.hP \*o
+the 16-bit network-byte-order length of the record label;
+.hP \*o
+the record label itself;
+.hP \*o
+the 16-bit network-byte-order length of the password;
+.hP \*o
+the password itself; and
+.hP \*o
+zero or more zero-valued octets,
+so as to make the payload a multiple of 256 octets long.
+.PP
+The padding serves to conceal the length of the label and password
+from an adversary who has obtained a copy of the database.
+.
+.SS Backend formats
+The various password-database backends
+represent the records described above as follows.
+.TP
+.B gdbm
+A GDBM-backed database is stored in a single file.
+A metadata record with key
+.I r
+and value
+.I v
+is stored in a GDBM record also named
+.IR r ,
+and with value
+.I v ;
+a password record with hash
+.I h
+and blob
+.I b
+is stored in a GDBM record named
+.BI $ h
+with value
+.IR b ,
+both in raw binary.
+.TP
+.B sqlite
+A SQLite-backed database is stored in a single file.
+It contains two tables,
+named
+.B meta
+and
+.BR passwd .
+The
+.B meta
+table has a primary key
+.B name
+and a further column
+.BR value ;
+a metadata record with key
+.I r
+and value
+.I v
+is held in a
+.B meta
+record
+with
+.B name
+.I r
+and
+.B value
+.IR v ;
+additionally, there is a record with
+.B name
+.B $version
+whose
+.B value
+is the schema version;
+this is currently always 0.
+The
+.B passwd
+table has a primary key
+.B label
+and a further column
+.BR payload ;
+a password record with hash
+.I h
+and blob
+.I b
+is stored in a
+.B passwd
+record with
+.B label
+.IR h
+and
+.B payload
+.IR b ,
+both in raw binary.
+.TP
+.B flat
+A flat-file-backed database is stored in a single file,
+with one record per line.
+The first line must be exactly
+.RS
+.IP
+.B "### pwsafe password database"
+.PP
+Blank lines and lines beginning with a
+.RB ` # '
+are ignored.
+.PP
+A metadata record named
+.I r
+with value
+.I v
+is stored as a line of the form
+.IB r\fR\(fm = v\fR\(fm
+where
+.IR r \fR\(fm
+and
+.IR v \fR\(fm
+are encodings of the strings
+.I r
+and
+.I v
+respectively.
+If
+.I r
+consists only of letters, digits,
+and the punctuation characters
+.RB ` \- ',
+.RB ` _ ',
+.RB ` : ',
+.RB ` . ',
+and
+.RB ` / '
+then
+.IR r \fR\(fm
+is simply
+.IR r ;
+otherwise
+.IR r \fR\(fm
+is formed by (simultaneously) replacing
+each space character in
+.I r
+with
+.RB ` + '
+and each other character
+which is not a letter, digit, or
+one of the punctuation characters listed above
+with
+.RB ` % '
+followed by that character's ASCII code in hex,
+and prefixing the whole lot by
+.RB ` ! '.
+Similarly,
+if
+.I v
+consists of letters, digits,
+and the punctuation characters listed above,
+then
+.IR v \fR\(fm
+is simply
+.IR v ;
+otherwise
+.IR v \fR\(fm
+consists of a
+.RB ` ? '
+followed by the base64 encoding of
+.IR v ,
+without any trailing
+.RB ` = '
+characters.
+.PP
+A password record with hash
+.I h
+and blob
+.I b
+is stored as a line of the form
+.BI $ h\fR\(fm = b\fR\(fm
+where
+.IR h \(fm
+and
+.IR b \(fm
+are the base64 encodings of
+.I h
+and
+.I b
+respectively,
+without trailing
+.RB ` = '
+characters.
+.PP
+The records may appear in any order.
+The file is completely rewritten when any change is made;
+if the file is named
+.I f
+then this is done by writing the new contents to
+.IB f .new
+and then renaming
+.IB f .new
+to
+.IR f .
+.RE
+.TP
+.B dir
+A directory-backed database is stored as a directory,
+named
+.I d
+in the sequel.
+The directory must contain a file
+.IB d /meta
+whose first line is
+.RS
+.IP
+.B "### pwsafe password directory metadata"
+.PP
+and directories
+.IB d /pw
+and
+.IB d /tmp \fR.
+.PP
+Metadata records are stored in file
+.IB d /meta
+with one record per line,
+exactly as for the
+.B file
+backend described above.
+.PP
+A password record with hash
+.I h
+and blob
+.I b
+is stored as file named
+.IB d /pw/ h \fR\(fm
+where
+.IR h \(fm
+is the base64 encodings of
+.I h
+without trailing
+.RB ` = '
+characters,
+and with all
+.RB ` / '
+characters
+replaced by
+.RB ` . 's,
+whose content is
+.IR b .
+.PP
+The directory
+.IB d /tmp/
+is used in an unspecified manner
+when creating new password-record files.
+The
+.IB d /meta
+and
+.IB d /pw/ h \fR\(fm
+files are updated by creating a new temporary file and renaming.
+.RE
+.
+.\"--------------------------------------------------------------------------
+.
+.SH BUGS
+This is quite an old program,
+though the manpage is new.
+It provides more footguns than is ideal.
+.
+.SH SEE ALSO
+.BR catcrypt (1),
+.BR pixie (1).
+.
+.SH AUTHOR
+Mark Wooding, <mdw@distorted.org.uk>
+.
+.\"----- That's all, folks --------------------------------------------------
{
size_t l;
mpw o = 0;
- char *kwlist[] = { "bits", "or", 0 };
+ static const char *const kwlist[] = { "bits", "or", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:mp", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:mp", KWLIST,
convszt, &l, convmpw, &o))
goto end;
if (grand_check(me)) return (0);
static PyObject *grmeth_seedrand(PyObject *me, PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { "rng", 0 };
+ static const char *const kwlist[] = { "rng", 0 };
grand *r = GRAND_R(me);
grand *rr = &rand_global;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:seedrand", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:seedrand", KWLIST,
convgrand, &rr) ||
grand_check(me) || checkop(r, GRAND_SEEDRAND, "seedrand"))
goto end;
static PyObject *lcrand_pynew(PyTypeObject *me, PyObject *arg, PyObject *kw)
{
uint32 n = 0;
- char *kwlist[] = { "seed", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist, convu32, &n))
+ static const char *const kwlist[] = { "seed", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", KWLIST, convu32, &n))
return (0);
return (grand_dopywrap(lcrand_pytype, lcrand_create(n), f_freeme));
}
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Linear congruential generator.",
+"LCRand([seed = 0]): linear congruential generator.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *fibrand_pynew(PyTypeObject *me, PyObject *arg, PyObject *kw)
{
uint32 n = 0;
- char *kwlist[] = { "seed", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist, convu32, &n))
+ static const char *const kwlist[] = { "seed", 0 };
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", KWLIST, convu32, &n))
return (0);
return (grand_dopywrap(fibrand_pytype, fibrand_create(n), f_freeme));
}
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Fibonacci generator.",
+"FibRand([seed = 0]): Fibonacci generator.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *truerand_pynew(PyTypeObject *ty,
PyObject *arg, PyObject *kw)
{
- char *kwlist[] = { 0 };
+ static const char *const kwlist[] = { 0 };
grand *r;
PyObject *rc = 0;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) goto end;
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
r = rand_create();
r->ops->misc(r, RAND_NOISESRC, &noise_source);
r->ops->misc(r, RAND_SEED, 160);
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"True random number source.",
+"TrueRand(): true random number source.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
static PyObject *gcrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
const gccrand_info *info = GCCRAND_INFO(ty);
- static char *kwlist[] = { "key", 0 };
+ static const char *const kwlist[] = { "key", 0 };
char *k;
Py_ssize_t n;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &n))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &k, &n))
goto end;
if (keysz(n, info->keysz) != n) VALERR("bad key length");
return (grand_dopywrap(ty, info->func(k, n), f_freeme));
{
const gccrand_info *info = GCCRAND_INFO(ty);
uint32 i = 0;
- static char *kwlist[] = { "key", "i", 0 };
+ static const char *const kwlist[] = { "key", "i", 0 };
char *k;
Py_ssize_t n;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", KWLIST,
&k, &n, convu32, &i))
goto end;
if (keysz(n, info->keysz) != n) VALERR("bad key length");
static PyObject *gcnrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
const gccrand_info *info = GCCRAND_INFO(ty);
- static char *kwlist[] = { "key", "nonce", 0 };
+ static const char *const kwlist[] = { "key", "nonce", 0 };
char *k, *n;
Py_ssize_t ksz, nsz;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#:new", KWLIST,
&k, &ksz, &n, &nsz))
goto end;
if (keysz(ksz, info->keysz) != ksz) VALERR("bad key length");
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 };
+ static const char
+ *const kwlist_shake[] = { "key", "func", "perso", 0 },
+ *const 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,
+ ? !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#s#:new",
+ (/*unconst*/ char **)kwlist_shake,
&k, &ksz, &f, &fsz, &p, &psz)
- : !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#:new", kwlist_func,
+ : !PyArg_ParseTupleAndKeywords(arg, kw, "s#|s#:new",
+ (/*unconst*/ char **)kwlist_func,
&k, &ksz, &p, &psz))
goto end;
if (keysz(ksz, info->keysz) != ksz) VALERR("bad key length");
int ksz, ssz;
const gchash *hco = &md5, *hci = &sha;
PyObject *rc = 0;
- char *kwlist[] = { "key", "seed", "ohash", "ihash", 0 };
+ static const char *const kwlist[] = { "key", "seed", "ohash", "ihash", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", KWLIST,
&k, &ksz, &s, &ssz,
convgchash, &hco, convgchash, &hci))
goto end;
int ksz, ssz;
const gcmac *mc = &sha_hmac;
PyObject *rc = 0;
- char *kwlist[] = { "key", "seed", "mac", 0 };
+ static const char *const kwlist[] = { "key", "seed", "mac", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&:new", KWLIST,
&k, &ksz, &s, &ssz,
convgcmac, &mc))
goto end;
int ksz, ssz;
const gcmac *mcl = &md5_hmac, *mcr = &sha_hmac;
PyObject *rc = 0;
- char *kwlist[] = { "key", "seed", "lmac", "rmac", 0 };
+ static const char *const kwlist[] = { "key", "seed", "lmac", "rmac", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|O&O&:new", KWLIST,
&k, &ksz, &s, &ssz,
convgcmac, &mcl, convgcmac, &mcr))
goto end;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Random number generator for SSL master secret.",
+"SSLRand(KEY, SEED, [ohash = md5], [ihash = sha]):\n\
+ RNG for SSL master secret.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"TLS data expansion function.",
+"TLSDataExpansion(KEY, SEED, [mac = sha_hmac]):\n\
+ TLS data expansion function.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"TLS pseudorandom function.",
+"TLSPRF(KEY, SEED, [lmac = md5_hmac], [rmac = sha_hmac]):\n\
+ TLS pseudorandom function.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
char *p;
int sz;
PyObject *rc = 0;
- char *kwlist[] = { "seed", 0 };
+ static const char *const kwlist[] = { "seed", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &sz))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", KWLIST, &p, &sz))
goto end;
rc = grand_dopywrap(ty, dsarand_create(p, sz), f_freeme);
end:
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Pseudorandom number generator for constructing DSA parameters.",
+"DSARand(SEED): pseudorandom number generator for DSA parameters.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mp *n = 0, *x = MP_TWO;
PyObject *rc = 0;
- char *kwlist[] = { "n", "x", 0 };
+ static const char *const kwlist[] = { "n", "x", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", KWLIST,
convmp, &n, convmp, &x))
goto end;
rc = grand_dopywrap(ty, bbs_rand(n, x), f_freeme);
static int bbsset_x(PyObject *me, PyObject *val, void *hunoz)
{
mp *x = 0; grand *r = GRAND_R(me); int rc = -1; if (!val) NIERR("__del__");
- if ((x = getmp(val)) == 0) goto end; r->ops->misc(r, BBS_SET, x); rc = 0;
+ if ((x = getmp(val)) == 0) goto end;
+ r->ops->misc(r, BBS_SET, x); rc = 0;
end: mp_drop(x); return (rc);
}
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Blum-Blum-Shub strong pseudorandom number generator.",
+"BlumBlumShub(N, [x = 2]): Blum-Blum-Shub pseudorandom number generator.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
mp *p = 0, *q = 0, *n = 0, *x = MP_TWO;
bbspriv_pyobj *rc = 0;
- char *kwlist[] = { "n", "p", "q", "seed", 0 };
+ static const char *const kwlist[] = { "n", "p", "q", "seed", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&O&O&O&:new", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&O&O&O&:new", KWLIST,
convmp, &n, convmp, &p, convmp, &q,
convmp, &x))
goto end;
pypgev evt = { { 0 } };
unsigned nbits, n = 0;
grand *r = &rand_global;
- char *kwlist[] = { "class", "nbits", "event", "rng", "nsteps", "seed", 0 };
+ static const char *const kwlist[] =
+ { "class", "nbits", "event", "rng", "nsteps", "seed", 0 };
bbspriv_pyobj *rc = 0;
evt.exc = &exc;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO&|O&O&O&O&:generate", KWLIST,
&me, convuint, &nbits, convpgev, &evt,
convgrand, &r, convuint, &n, convmp, &x))
goto end;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Blum-Blum-Shub strong pseudorandom generator, with private key.",
+"BBSPriv(..., seed = 2]): Blum-Blum-Shub, with private key.\n\
+ Keywords: n, p, q; must provide at least two",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
import distutils.core as DC
import mdwsetup as MS
-MS.pkg_config('catacomb', '2.3.0.1+4')
-MS.pkg_config('mLib', '2.0.4')
+MS.pkg_config('catacomb', '2.5.0')
+MS.pkg_config('mLib', '2.2.2.1')
cat = DC.Extension('catacomb._base',
['catacomb.c', 'bytestring.c', 'buffer.c',
author_email = 'mdw@distorted.org.uk',
license = 'GNU General Public License',
packages = ['catacomb'],
- scripts = ['pwsafe'],
+ scripts = ['pock', 'pwsafe'],
+ data_files = [('share/man/man1', ['pock.1', 'pwsafe.1'])],
genfiles = [MS.Generate('algorithms.h')],
unittest_dir = "t",
unittests = ["t-misc", "t-algorithms", "t-bytes", "t-buffer",
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,
+ static const char *const 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");
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Binary field secret sharing: split secret into shares.",
+"GFShareSplit(THRESHOLD, SECRET, [rng = rand]): binary-field sharing:\n\
+ split secret into shares.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
{
unsigned t, sz;
gfshare_pyobj *s;
- char *kwlist[] = { "threshold", "size", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+ static const char *const 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");
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Binary field secret sharing: join shares to recover secret.",
+"GFShareJoin(THRESHOLD, SIZE): binary field sharing:\n\
+ join shares to recover secret.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
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&O&:new", kwlist,
+ static const char *const kwlist[] =
+ { "threshold", "secret", "modulus", "rng", 0 };
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|O&O&:new", KWLIST,
convuint, &t, convmp, &sec,
convmp, &m, convgrand, &r))
goto end;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Prime field secret sharing: split secret into shares.",
+"ShareSplit(THRESHOLD, SECRET, [modulus = ?], [rng = rand]):\n\
+ prime field secret sharing: split secret into shares.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
unsigned t;
mp *m = 0;
share_pyobj *s;
- char *kwlist[] = { "threshold", "modulus", 0 };
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist,
+ static const char *const 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");
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Prime field secret sharing: join shares to recover secret.",
+"ShareJoin(THRESHOLD, MODULUS): prime field secret sharing:\n\
+ join shares to recover secret.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
return (rc);
}
-static char *def_kwlist[] = { "key", "default", 0 };
+static const char *const def_kwlist[] = { "key", "default", 0 };
PyObject *gmapmeth_get(PyObject *me, PyObject *arg, PyObject *kw)
{
PyObject *k, *def = Py_None, *v;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get", def_kwlist, &k, &def))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get",
+ (/*unconst*/ char **)def_kwlist,
+ &k, &def))
return (0);
if ((v = PyObject_GetItem(me, k)) != 0) return (v);
PyErr_Clear();
PyObject *k, *def = Py_None, *v;
if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:setdefault",
- def_kwlist, &k, &def))
+ (/*unconst*/ char **)def_kwlist,
+ &k, &def))
return (0);
if ((v = PyObject_GetItem(me, k)) != 0) return (v);
PyErr_Clear();
{
PyObject *k, *def = 0, *v;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:pop", def_kwlist, &k, &def))
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:pop",
+ (/*unconst*/ char **)def_kwlist,
+ &k, &def))
return (0);
if ((v = PyObject_GetItem(me, k)) != 0) {
PyObject_DelItem(me, k);