Ticket #3: diff-ecdsa.txt

File diff-ecdsa.txt, 39.7 KB (added by zooko, at 2009-03-03T04:29:17Z)
Line 
1--- old-from_zaula_new_and_improved/pycryptopp/publickey/ecdsamodule.cpp        2009-03-02 14:23:06.000000000 -0700
2+++ new-from_zaula_new_and_improved/pycryptopp/publickey/ecdsamodule.cpp        2009-03-02 14:23:09.000000000 -0700
3@@ -1,9 +1,12 @@
4 /**
5  * ecdsamodule.cpp -- Python wrappers around Crypto++'s
6- * ECDSA(1363)/EMSA1(SHA-256), more precisely: <a
7- * href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a> with GF(P)
8- * ("ECP") as the elliptic curve group parameters and SHA-256 as the hash
9- * function
10+ * ECDSA(1363)/EMSA1(Tiger) -- <a
11+ * href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a>.
12+ *
13+ * The keys (192-bit) use the curve ASN1::secp192r1() and Tiger as the hash
14+ * function.  There is a custom Key Derivation Protocol to generate private
15+ * (signing) keys from unguessable seeds -- see source code for details and
16+ * doc string for usage.
17  */
18 
19 #include <Python.h>
20@@ -19,37 +22,105 @@
21 #include "osrng.h"
22 #include "eccrypto.h"
23 #include "oids.h"
24+#include "tiger.h"
25+#include "sha.h"
26+#include "pubkey.h"
27+
28+// for _dump
29+#include <iostream>
30+#include "ecp.h"
31+#include "hex.h"
32+
33+/* The ECDSA key size that pycryptopp currently supports -- you should do your
34+   own research, and I recommend http://keylength.com , but basically this is
35+   probably secure for most purposes for at least the next few years, and
36+   possibly for longer. */
37+static const int SMALL_KEY_SIZE_BITS=192;
38 
39 USING_NAMESPACE(CryptoPP)
40 
41 PyDoc_STRVAR(ecdsa__doc__,
42-"ecdsa -- ECDSA(1363)/EMSA1(SHA-256) signatures\n\
43+"ecdsa -- ECDSA(1363)/EMSA1(Tiger) signatures\n\
44+\n\
45+To create a new ECDSA signing key (deterministically from a 12-byte seed), construct an instance of the class, passing the seed as argument, i.e. SigningKey(seed).  If you call serialize() on that instance, you'll get that seed back.\n\
46 \n\
47-To create a new ECDSA signing key from the operating system's random number generator, call generate().\n\
48-To deserialize an ECDSA signing key from a string, call create_signing_key_from_string().\n\
49+To get a verifying key from a signing key, call get_verifying_key() on the signing key instance.\n\
50 \n\
51-To get an ECDSA verifying key from an ECDSA signing key, call get_verifying_key() on the signing key.\n\
52-To deserialize an ECDSA verifying key from a string, call create_verifying_key_from_string().");
53+To deserialize an ECDSA verifying key from a string, call VerifyingKey(serialized_verifying_key).");
54 
55 static PyObject *ecdsa_error;
56 
57 typedef struct {
58     PyObject_HEAD
59-
60-    /* internal */
61-    ECDSA<ECP, SHA256>::Verifier *k;
62+    ECDSA<ECP, SHA1>::Verifier k;
63 } VerifyingKey;
64 
65 PyDoc_STRVAR(VerifyingKey__doc__,
66 "an ECDSA verifying key");
67 
68+struct VerifyingKey_type;
69+static PyObject*
70+VerifyingKey_alloc(PyTypeObject* typ, Py_ssize_t nitems) {
71+    VerifyingKey* k = new VerifyingKey();
72+    if (!k)
73+        return PyErr_NoMemory();
74+
75+    memset(k, 0, sizeof(PyObject));
76+    k->ob_refcnt = 1;
77+    k->ob_type = typ;
78+
79+    return reinterpret_cast<PyObject*>(k);
80+}
81+
82 static void
83-VerifyingKey_dealloc(VerifyingKey* self) {
84-    if (self->k)
85-        delete self->k;
86-    self->ob_type->tp_free((PyObject*)self);
87+VerifyingKey_free(void* self) {
88+    delete reinterpret_cast<VerifyingKey*>(self);
89+}
90+
91+static PyObject *
92+VerifyingKey__dump(VerifyingKey *self, PyObject *dummy) {
93+    const CryptoMaterial& x = self->k.GetMaterial();
94+    std::cout << x.GetValueNames();
95+    Py_RETURN_NONE;
96+}
97+
98+static int
99+VerifyingKey___init__(PyObject* self, PyObject* args, PyObject* kwdict) {
100+    static const char *kwlist[] = { "serializedverifyingkey", NULL };
101+    const char *serializedverifyingkey;
102+    Py_ssize_t serializedverifyingkeysize = 0;
103+
104+    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:VerifyingKey__init__", const_cast<char**>(kwlist), &serializedverifyingkey, &serializedverifyingkeysize))
105+        return NULL;
106+    assert (serializedverifyingkeysize >= 0);
107+
108+    if (serializedverifyingkeysize != 25) {
109+        PyErr_Format(ecdsa_error, "Precondition violation: size in bits is required to be %d (for %d-bit key), but it was %d", 25, SMALL_KEY_SIZE_BITS, serializedverifyingkeysize);
110+        return -1;
111+    }
112+
113+    VerifyingKey *mself = reinterpret_cast<VerifyingKey*>(self);
114+
115+    StringSource ss(reinterpret_cast<const byte*>(serializedverifyingkey), serializedverifyingkeysize, true);
116+
117+    ECP::Element element;
118+    DL_GroupParameters_EC<ECP> params(ASN1::secp192r1());
119+    params.SetPointCompression(true);
120+    try {
121+      element = params.DecodeElement(reinterpret_cast<const byte*>(serializedverifyingkey), true);
122+      mself->k = ECDSA<ECP, SHA1>::Verifier(params, element);
123+    } catch (InvalidDataFormat le) {
124+      PyErr_Format(ecdsa_error, "Serialized verifying key was corrupted.  Crypto++ gave this exception: %s", le.what());
125+      return -1;
126+    }
127+
128+    return 0;
129 }
130 
131+PyDoc_STRVAR(VerifyingKey__dump__doc__,
132+
133+"Print to stdout some descriptions of the math pieces.");
134+
135 static PyObject *
136 VerifyingKey_verify(VerifyingKey *self, PyObject *args, PyObject *kwdict) {
137     static const char *kwlist[] = { "msg", "signature", NULL };
138@@ -62,14 +133,7 @@
139     assert (msgsize >= 0);
140     assert (signaturesize >= 0);
141 
142-    Py_ssize_t sigsize = self->k->SignatureLength();
143-    if (sigsize != signaturesize)
144-        return PyErr_Format(ecdsa_error, "Precondition violation: signatures are required to be of size %zu, but it was %zu", sigsize, signaturesize);
145-    assert (sigsize >= 0);
146-
147-    assert (signaturesize == sigsize);
148-
149-    if (self->k->VerifyMessage(reinterpret_cast<const byte*>(msg), msgsize, reinterpret_cast<const byte*>(signature), signaturesize))
150+    if (self->k.VerifyMessage(reinterpret_cast<const byte*>(msg), msgsize, reinterpret_cast<const byte*>(signature), signaturesize))
151         Py_RETURN_TRUE;
152     else
153         Py_RETURN_FALSE;
154@@ -80,14 +144,17 @@
155 
156 static PyObject *
157 VerifyingKey_serialize(VerifyingKey *self, PyObject *dummy) {
158-    std::string outstr;
159-    StringSink ss(outstr);
160-    self->k->DEREncode(ss);
161-    PyStringObject* result = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(outstr.c_str(), outstr.size()));
162-    if (!result)
163-        return NULL;
164+    const DL_PublicKey_EC<ECP>* pubkey;
165+    pubkey = dynamic_cast<const DL_PublicKey_EC<ECP>*>(&(self->k.GetPublicKey()));
166+    const DL_GroupParameters_EC<ECP>& params = pubkey->GetGroupParameters();
167 
168-    return reinterpret_cast<PyObject*>(result);
169+    Py_ssize_t len = params.GetEncodedElementSize(true);
170+//   params.SetPointCompression(true);
171+    PyObject* result = PyString_FromStringAndSize(NULL, len);
172+
173+    params.EncodeElement(true, pubkey->GetPublicElement(), reinterpret_cast<byte*>(PyString_AS_STRING(result)));
174+
175+    return result;
176 }
177 
178 PyDoc_STRVAR(VerifyingKey_serialize__doc__,
179@@ -97,6 +164,7 @@
180 static PyMethodDef VerifyingKey_methods[] = {
181     {"verify", reinterpret_cast<PyCFunction>(VerifyingKey_verify), METH_KEYWORDS, VerifyingKey_verify__doc__},
182     {"serialize", reinterpret_cast<PyCFunction>(VerifyingKey_serialize), METH_NOARGS, VerifyingKey_serialize__doc__},
183+    {"_dump", reinterpret_cast<PyCFunction>(VerifyingKey__dump), METH_NOARGS, VerifyingKey__dump__doc__},
184     {NULL},
185 };
186 
187@@ -106,7 +174,7 @@
188     "ecdsa.VerifyingKey", /*tp_name*/
189     sizeof(VerifyingKey),             /*tp_basicsize*/
190     0,                         /*tp_itemsize*/
191-    reinterpret_cast<destructor>(VerifyingKey_dealloc), /*tp_dealloc*/
192+    0,                         /*tp_dealloc*/
193     0,                         /*tp_print*/
194     0,                         /*tp_getattr*/
195     0,                         /*tp_setattr*/
196@@ -123,42 +191,179 @@
197     0,                         /*tp_as_buffer*/
198     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
199     VerifyingKey__doc__,           /* tp_doc */
200-    0,                        /* tp_traverse */
201-    0,                        /* tp_clear */
202-    0,                        /* tp_richcompare */
203-    0,                        /* tp_weaklistoffset */
204-    0,                        /* tp_iter */
205-    0,                        /* tp_iternext */
206+    0,                               /* tp_traverse */
207+    0,                               /* tp_clear */
208+    0,                               /* tp_richcompare */
209+    0,                               /* tp_weaklistoffset */
210+    0,                               /* tp_iter */
211+    0,                               /* tp_iternext */
212     VerifyingKey_methods,             /* tp_methods */
213+    0,                         /* tp_members */
214+    0,                         /* tp_getset */
215+    0,                         /* tp_base */
216+    0,                         /* tp_dict */
217+    0,                         /* tp_descr_get */
218+    0,                         /* tp_descr_set */
219+    0,                         /* tp_dictoffset */
220+    VerifyingKey___init__,       /* tp_init */
221+    VerifyingKey_alloc,          /* tp_alloc */
222+    0,                         /* tp_new */
223+    VerifyingKey_free            /* tp_free */
224 };
225 
226-/** This function is only for internal use by ecdsamodule.cpp. */
227-static VerifyingKey*
228-VerifyingKey_construct() {
229-    VerifyingKey *self = reinterpret_cast<VerifyingKey*>(VerifyingKey_type.tp_alloc(&VerifyingKey_type, 0));
230-    if (!self)
231-        return NULL;
232-    self->k = NULL;
233-    return self;
234-}
235-
236 PyDoc_STRVAR(SigningKey__doc__,
237 "an ECDSA signing key");
238 
239 typedef struct {
240     PyObject_HEAD
241-
242-    /* internal */
243-    ECDSA<ECP, SHA256>::Signer *k;
244+    ECDSA<ECP, SHA1>::Signer k;
245 } SigningKey;
246 
247+struct SigningKey_type;
248+static PyObject*
249+SigningKey_alloc(PyTypeObject* typ, Py_ssize_t nitems) {
250+    SigningKey* k = new SigningKey();
251+    if (!k)
252+        return PyErr_NoMemory();
253+
254+    memset(k, 0, sizeof(PyObject));
255+    k->ob_refcnt = 1;
256+    k->ob_type = typ;
257+
258+    return reinterpret_cast<PyObject*>(k);
259+}
260+
261 static void
262-SigningKey_dealloc(SigningKey* self) {
263-    if (self->k)
264-        delete self->k;
265-    self->ob_type->tp_free((PyObject*)self);
266+SigningKey_free(void* self) {
267+    delete reinterpret_cast<SigningKey*>(self);
268 }
269 
270+static const char* TAG_AND_SALT = "102:pycryptopp v0.5.3 key derivation algorithm using Tiger hash to generate ECDSA 192-bit secret exponents," \
271+    "16:H1yGNvUONoc0FD1d,";
272+static const size_t TAG_AND_SALT_len = 127;
273+
274+static int
275+SigningKey___init__(PyObject* self, PyObject* args, PyObject* kwdict) {
276+    static const char *kwlist[] = { "seed", NULL };
277+    const char* seed;
278+    int seedlen;
279+    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:SigningKey___init__", const_cast<char**>(kwlist), &seed, &seedlen)) {
280+        return -1;
281+    }
282+
283+    if (seedlen != 12) {
284+        PyErr_Format(ecdsa_error, "Precondition violation: seed is required to be of length 12, but it was %d", seedlen);
285+        return -1;
286+    }
287+
288+    OID curve;
289+    Integer grouporderm1;
290+    byte privexpbytes[24] = {0};
291+    Integer privexponentm1;
292+    privexponentm1.Decode(privexpbytes, sizeof(privexpbytes)); assert (priveexponentm1 == 0); // just checking..
293+
294+    curve = ASN1::secp192r1();
295+    grouporderm1 = DL_GroupParameters_EC<ECP>(curve).GetGroupOrder() - 1;
296+    Tiger t;
297+
298+    t.Update(reinterpret_cast<const byte*>(TAG_AND_SALT), TAG_AND_SALT_len);
299+    t.Update(reinterpret_cast<const byte*>(seed), seedlen);
300+    t.TruncatedFinal(privexpbytes, Tiger::DIGESTSIZE);
301+    privexponentm1.Decode(privexpbytes, sizeof(privexpbytes));
302+
303+    while (privexponentm1 >= grouporderm1) {
304+        Tiger t2;
305+        t2.Update(reinterpret_cast<const byte*>(TAG_AND_SALT), TAG_AND_SALT_len);
306+        std::cerr << "WHEE " << sizeof(privexpbytes) << "\n";std::cerr.flush();
307+        t2.Update(privexpbytes, sizeof(privexpbytes));
308+        t2.TruncatedFinal(privexpbytes, Tiger::DIGESTSIZE);
309+        privexponentm1.Decode(privexpbytes, sizeof(privexpbytes));
310+    }
311+
312+    SigningKey* mself = reinterpret_cast<SigningKey*>(self);
313+    mself->k.AccessKey().Initialize(curve, privexponentm1+1);
314+
315+    return 0;
316+}
317+
318+PyDoc_STRVAR(SigningKey__init____doc__,
319+"Create a signing key (192 bits) deterministically from the given seed.\n\
320+\n\
321+This implies that if someone can guess the seed then they can learn the signing key.  A good way to get an unguessable seed is os.urandom(12).\n\
322+\n\
323+@param seed seed\n\
324+\n\
325+@precondition len(seed) >= ceil(sizeinbits/16.0)");
326+
327+static PyObject *
328+SigningKey__dump(SigningKey *self, PyObject *dummy) {
329+    const DL_GroupParameters_EC<ECP>& gp = self->k.GetKey().GetGroupParameters();
330+    std::cout << "whee " << gp.GetEncodedElementSize(true) << "\a";
331+    std::cout << "booo " << gp.GetEncodedElementSize(false) << "\n";
332+
333+    ECPPoint p = gp.GetSubgroupGenerator();
334+    std::cout << "generator " << p.x << ", " << p.y << "\n";
335+
336+    std::cout << "GroupOrder: ";
337+    std::cout << gp.GetGroupOrder();
338+    std::cout << "\n";
339+
340+    std::string s;
341+    StringSink* ss = new StringSink(s);
342+    HexEncoder he(ss);
343+    std::cout << "AlgorithmID: ";
344+    gp.GetAlgorithmID().DEREncode(he);
345+    std::cout << s << "\n";
346+
347+    const ECP& ec = gp.GetCurve();
348+    Integer fieldsize = ec.FieldSize();
349+    std::cout << "field size " << fieldsize.BitCount() << " " << fieldsize.ByteCount() << " " << ec.FieldSize() << "\n";
350+    std::cout << "Curve: ";
351+    std::cout << "curve field max element bit length: " << ec.GetField().MaxElementBitLength() << "\n";
352+    std::cout << "curve field modulus: " << ec.GetField().GetModulus() << "\n";
353+    std::cout << "curve A: " << ec.GetA() << ", curve B: " << ec.GetB();
354+
355+    const ECP::Field& f = ec.GetField();
356+    std::cout << "curve field modulus: " << f.GetModulus() << "\n";
357+    std::cout << "curve field identity: " << f.Identity() << "\n";
358+
359+    std::string cfs;
360+    StringSink* cfss = new StringSink(cfs);
361+    HexEncoder cfhe(cfss);
362+    f.DEREncode(cfhe);
363+    std::cout << "curve field derencoding: " << cfs << "\n";
364+
365+    const CryptoMaterial& cm = self->k.GetMaterial();
366+    Integer i;
367+    cm.GetValue("SubgroupOrder", i);
368+    std::cout << "\n";
369+    std::cout << "SubgroupOrder: ";
370+    std::cout << i;
371+    std::cout << "\n";
372+    ECP::Element e;
373+    cm.GetValue("SubgroupGenerator", e);
374+    std::cout << "SubgroupGenerator: ";
375+    std::cout << e.x << ", " << e.y;
376+    std::cout << "\n";
377+
378+    std::cout << "private key: ";
379+
380+    const PrivateKey& privkey = self->k.GetPrivateKey();
381+
382+    std::cout << privkey.GetValueNames() << "\n";
383+
384+    Integer privi;
385+    privkey.GetValue("PrivateExponent", privi);
386+    std::cout << privi << "\n";
387+    std::cout << "numbits: " << privi.BitCount() << "\n";
388+    std::cout << "numbytes: " << privi.ByteCount() << "\n";
389+
390+    Py_RETURN_NONE;
391+}
392+
393+PyDoc_STRVAR(SigningKey__dump__doc__,
394+"Print to stdout some descriptions of the math pieces.");
395+
396 static PyObject *
397 SigningKey_sign(SigningKey *self, PyObject *msgobj) {
398     const char *msg;
399@@ -166,22 +371,32 @@
400     PyString_AsStringAndSize(msgobj, const_cast<char**>(&msg), reinterpret_cast<Py_ssize_t*>(&msgsize));
401     assert (msgsize >= 0);
402 
403-    Py_ssize_t sigsize = self->k->SignatureLength();
404+    Py_ssize_t sigsize;
405+    sigsize = self->k.SignatureLength();
406+
407     PyStringObject* result = reinterpret_cast<PyStringObject*>(PyString_FromStringAndSize(NULL, sigsize));
408     if (!result)
409         return NULL;
410     assert (sigsize >= 0);
411 
412     AutoSeededRandomPool randpool(false);
413-    Py_ssize_t siglengthwritten = self->k->SignMessage(
414-        randpool,
415-        reinterpret_cast<const byte*>(msg),
416-        msgsize,
417-        reinterpret_cast<byte*>(PyString_AS_STRING(result)));
418+
419+    Py_ssize_t siglengthwritten;
420+    try {
421+        siglengthwritten = self->k.SignMessage(
422+            randpool,
423+            reinterpret_cast<const byte*>(msg),
424+            msgsize,
425+            reinterpret_cast<byte*>(PyString_AS_STRING(result)));
426+    } catch (InvalidDataFormat le) {
427+        Py_DECREF(result);
428+        return PyErr_Format(ecdsa_error, "Signing key was corrupted.  Crypto++ gave this exception: %s", le.what());
429+    }
430+
431     if (siglengthwritten < sigsize)
432         fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was shorter than expected.");
433     else if (siglengthwritten > sigsize) {
434-        fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was longer than expected, so invalid memory was overwritten.");
435+        fprintf(stderr, "%s: %d: %s: %s", __FILE__, __LINE__, "SigningKey_sign", "INTERNAL ERROR: signature was longer than expected, so memory was invalidly overwritten.");
436         abort();
437     }
438     assert (siglengthwritten >= 0);
439@@ -190,43 +405,30 @@
440 }
441 
442 PyDoc_STRVAR(SigningKey_sign__doc__,
443-"Return a signature on the argument.");
444+     "Return a signature on the argument."); //XXX  If randseed is not None then it is required to be an  "); // XXX randseed!
445 
446 static PyObject *
447 SigningKey_get_verifying_key(SigningKey *self, PyObject *dummy) {
448-    VerifyingKey *verifier = reinterpret_cast<VerifyingKey*>(VerifyingKey_construct());
449+    VerifyingKey *verifier = PyObject_New(VerifyingKey, &VerifyingKey_type);
450+
451     if (!verifier)
452         return NULL;
453 
454-    verifier->k = new ECDSA<ECP, SHA256>::Verifier(*(self->k));
455-    if (!verifier->k)
456-        return PyErr_NoMemory();
457+    ECDSA<ECP, SHA1>::Verifier* kp;
458+    kp = new ECDSA<ECP, SHA1>::Verifier(self->k);
459+
460+    verifier->k = (*kp);
461+
462     return reinterpret_cast<PyObject*>(verifier);
463 }
464 
465 PyDoc_STRVAR(SigningKey_get_verifying_key__doc__,
466 "Return the corresponding verifying key.");
467 
468-static PyObject *
469-SigningKey_serialize(SigningKey *self, PyObject *dummy) {
470-    Py_ssize_t len = self->k->GetKey().GetGroupParameters().GetSubgroupOrder().ByteCount();
471-    PyObject* result = PyString_FromStringAndSize(NULL, len);
472-
473-    const DL_PrivateKey_EC<ECP>& privkey = dynamic_cast<const DL_PrivateKey_EC<ECP>&>(self->k->GetPrivateKey());
474-
475-    privkey.GetPrivateExponent().Encode(reinterpret_cast<byte*>(PyString_AS_STRING(result)), len);
476-
477-    return result;
478-}
479-
480-PyDoc_STRVAR(SigningKey_serialize__doc__,
481-"Return a string containing the key material.  The string can be passed to \n\
482-create_signing_key_from_string() to instantiate a new copy of this key.");
483-
484 static PyMethodDef SigningKey_methods[] = {
485     {"sign", reinterpret_cast<PyCFunction>(SigningKey_sign), METH_O, SigningKey_sign__doc__},
486+    {"_dump", reinterpret_cast<PyCFunction>(SigningKey__dump), METH_NOARGS, SigningKey__dump__doc__},
487     {"get_verifying_key", reinterpret_cast<PyCFunction>(SigningKey_get_verifying_key), METH_NOARGS, SigningKey_get_verifying_key__doc__},
488-    {"serialize", reinterpret_cast<PyCFunction>(SigningKey_serialize), METH_NOARGS, SigningKey_serialize__doc__},
489     {NULL},
490 };
491 
492@@ -236,7 +438,7 @@
493     "ecdsa.SigningKey", /*tp_name*/
494     sizeof(SigningKey),             /*tp_basicsize*/
495     0,                         /*tp_itemsize*/
496-    (destructor)SigningKey_dealloc, /*tp_dealloc*/
497+    0,                         /*tp_dealloc*/
498     0,                         /*tp_print*/
499     0,                         /*tp_getattr*/
500     0,                         /*tp_setattr*/
501@@ -251,143 +453,34 @@
502     0,                         /*tp_getattro*/
503     0,                         /*tp_setattro*/
504     0,                         /*tp_as_buffer*/
505-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
506-    SigningKey__doc__,           /* tp_doc */
507-    0,                        /* tp_traverse */
508-    0,                        /* tp_clear */
509-    0,                        /* tp_richcompare */
510-    0,                        /* tp_weaklistoffset */
511-    0,                        /* tp_iter */
512-    0,                        /* tp_iternext */
513-    SigningKey_methods             /* tp_methods */
514+    Py_TPFLAGS_DEFAULT,        /*tp_flags*/
515+    SigningKey__doc__,         /* tp_doc */
516+    0,                               /* tp_traverse */
517+    0,                               /* tp_clear */
518+    0,                               /* tp_richcompare */
519+    0,                               /* tp_weaklistoffset */
520+    0,                               /* tp_iter */
521+    0,                               /* tp_iternext */
522+    SigningKey_methods,             /* tp_methods */
523+    0,                         /* tp_members */
524+    0,                         /* tp_getset */
525+    0,                         /* tp_base */
526+    0,                         /* tp_dict */
527+    0,                         /* tp_descr_get */
528+    0,                         /* tp_descr_set */
529+    0,                         /* tp_dictoffset */
530+    SigningKey___init__,       /* tp_init */
531+    SigningKey_alloc,          /* tp_alloc */
532+    0,                         /* tp_new */
533+    SigningKey_free            /* tp_free */
534 };
535 
536-/** This function is only for internal use by ecdsamodule.cpp. */
537-static SigningKey*
538-SigningKey_construct() {
539-    SigningKey *self = reinterpret_cast<SigningKey*>(SigningKey_type.tp_alloc(&SigningKey_type, 0));
540-    if (!self)
541-        return NULL;
542-    self->k = NULL;
543-    return self;
544-}
545-
546-/* The smaller ECDSA key size that pycryptopp supports -- you should do your
547-   own research, and I recommend http://keylength.com , but basically this is
548-   probably secure for most purposes for at least the next few years, and
549-   possibly for longer. */
550-static const int SMALL_KEY_SIZE_BITS=192;
551-
552-/* The larger ECDSA key size that pycryptopp supports -- you should do your
553-   own research, and I recommend http://keylength.com , but basically this is
554-   probably secure for many years, unless there is a surprising breakthrough in
555-   the theory of elliptic curve cryptography. */
556-static const int LARGE_KEY_SIZE_BITS=521;
557-
558-static PyObject *
559-generate(PyObject *dummy, PyObject *args, PyObject *kwdict) {
560-    static const char *kwlist[] = {
561-        "sizeinbits",
562-        NULL
563-    };
564-    int sizeinbits;
565-
566-    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "i:generate", const_cast<char**>(kwlist), &sizeinbits))
567-        return NULL;
568-
569-    if (sizeinbits != SMALL_KEY_SIZE_BITS && sizeinbits != LARGE_KEY_SIZE_BITS)
570-        return PyErr_Format(ecdsa_error, "Precondition violation: size in bits is required to be either %d or %d, but it was %d", SMALL_KEY_SIZE_BITS, LARGE_KEY_SIZE_BITS, sizeinbits);
571-
572-    AutoSeededRandomPool osrng(false);
573-    SigningKey *signer = SigningKey_construct();
574-    if (!signer)
575-        return NULL;
576-
577-    OID curve;
578-    if (sizeinbits == 192)
579-        curve = ASN1::secp192r1();
580-    else
581-        curve = ASN1::secp521r1();
582-
583-    signer->k = new ECDSA<ECP, SHA256>::Signer(osrng, curve);
584-    if (!signer->k)
585-        return PyErr_NoMemory();
586-    return reinterpret_cast<PyObject*>(signer);
587-}
588-
589-PyDoc_STRVAR(generate__doc__,
590-"Create a signing key using the operating system's random number generator.\n\
591-\n\
592-@param sizeinbits size of the key in bits\n\
593-\n\
594-@precondition sizeinbits in (192, 521)");
595-
596-static PyObject *
597-create_verifying_key_from_string(PyObject *dummy, PyObject *args, PyObject *kwdict) {
598-    static const char *kwlist[] = {
599-        "serializedverifyingkey",
600-        NULL
601-    };
602-    const char *serializedverifyingkey;
603-    Py_ssize_t serializedverifyingkeysize = 0;
604-
605-    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:create_verifying_key_from_string", const_cast<char**>(kwlist), &serializedverifyingkey, &serializedverifyingkeysize))
606-        return NULL;
607-    assert (serializedverifyingkeysize >= 0);
608-
609-    VerifyingKey *verifier = reinterpret_cast<VerifyingKey*>(VerifyingKey_construct());
610-    if (!verifier)
611-        return NULL;
612-    StringSource ss(reinterpret_cast<const byte*>(serializedverifyingkey), serializedverifyingkeysize, true);
613-
614-    verifier->k = new ECDSA<ECP, SHA256>::Verifier(ss);
615-    if (!verifier->k)
616-        return PyErr_NoMemory();
617-    return reinterpret_cast<PyObject*>(verifier);
618-}
619-
620 PyDoc_STRVAR(create_verifying_key_from_string__doc__,
621-"Create a verifying key from its serialized state.");
622-
623-static PyObject *
624-create_signing_key_from_string(PyObject *dummy, PyObject *args, PyObject *kwdict) {
625-    static const char *kwlist[] = {
626-        "serializedsigningkey",
627-        NULL
628-    };
629-    const char *serializedsigningkey;
630-    Py_ssize_t serializedsigningkeysize = 0;
631-
632-    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "t#:create_signing_key_from_string", const_cast<char**>(kwlist), &serializedsigningkey, &serializedsigningkeysize))
633-        return NULL;
634-    if (serializedsigningkeysize != 24 && serializedsigningkeysize != 66)
635-        return PyErr_Format(ecdsa_error, "Precondition violation: size in bytes of the serialized signing key is required to be either %d (for %d-bit keys) or %d (for %d-bit keys), but it was %d", 24, SMALL_KEY_SIZE_BITS, 66, LARGE_KEY_SIZE_BITS, serializedsigningkeysize);
636-
637-
638-    SigningKey *verifier = SigningKey_construct();
639-    if (!verifier)
640-        return NULL;
641-
642-    OID curve;
643-    if (serializedsigningkeysize == 24)
644-        curve = ASN1::secp192r1();
645-    else
646-        curve = ASN1::secp521r1();
647-    Integer privexponent(reinterpret_cast<const byte*>(serializedsigningkey), serializedsigningkeysize);
648-
649-    verifier->k = new ECDSA<ECP, SHA256>::Signer(curve, privexponent);
650-    if (!verifier->k)
651-        return PyErr_NoMemory();
652-    return reinterpret_cast<PyObject*>(verifier);
653-}
654-
655-PyDoc_STRVAR(create_signing_key_from_string__doc__,
656-"Create a signing key from its serialized state.");
657+"Create a verifying key from its serialized state.\n\
658+\n\
659+@precondition Length of serialized key is required to be 24 (for 192-bit key)."); //XXX actually 25 length
660 
661 static PyMethodDef ecdsa_functions[] = {
662-    {"generate", reinterpret_cast<PyCFunction>(generate), METH_KEYWORDS, generate__doc__},
663-    {"create_verifying_key_from_string", reinterpret_cast<PyCFunction>(create_verifying_key_from_string), METH_KEYWORDS, create_verifying_key_from_string__doc__},
664-    {"create_signing_key_from_string", reinterpret_cast<PyCFunction>(create_signing_key_from_string), METH_KEYWORDS, create_signing_key_from_string__doc__},
665     {NULL, NULL, 0, NULL}  /* sentinel */
666 };
667 
668@@ -399,8 +492,10 @@
669     PyObject *module;
670     PyObject *module_dict;
671 
672+    VerifyingKey_type.tp_new = PyType_GenericNew;
673     if (PyType_Ready(&VerifyingKey_type) < 0)
674         return;
675+    SigningKey_type.tp_new = PyType_GenericNew;
676     if (PyType_Ready(&SigningKey_type) < 0)
677         return;
678 
679diff -rN -u old-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py new-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py
680--- old-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py       2009-03-02 14:23:06.000000000 -0700
681+++ new-from_zaula_new_and_improved/pycryptopp/test/test_ecdsa.py       2009-03-02 14:23:09.000000000 -0700
682@@ -2,10 +2,39 @@
683 
684 import random
685 
686+import os
687+SEED = os.environ.get('REPEATABLE_RANDOMNESS_SEED', None)
688+
689+if SEED is None:
690+    # Generate a seed which is fairly short (to ease cut-and-paste, writing it
691+    # down, etc.).  Note that Python's random module's seed() function is going
692+    # to take the hash() of this seed, which is a 32-bit value (currently) so
693+    # there is no point in making this seed larger than 32 bits.  Make it 30
694+    # bits, which conveniently fits into six base-32 chars.  Include a separator
695+    # because chunking facilitates memory (including working and short-term
696+    # memory) in humans.
697+    chars = "ybndrfg8ejkmcpqxot1uwisza345h769" # Zooko's choice, rationale in "DESIGN" doc in z-base-32 project
698+    SEED = ''.join([random.choice(chars) for x in range(3)] + ['-'] + [random.choice(chars) for x in range(3)])
699+
700+import logging
701+logging.info("REPEATABLE_RANDOMNESS_SEED: %s\n" % SEED)
702+logging.info("In order to reproduce this run of the code, set the environment variable \"REPEATABLE_RANDOMNESS_SEED\" to %s before executing.\n" % SEED)
703+random.seed(SEED)
704+
705+def seed_which_refuses(a):
706+    logging.warn("I refuse to reseed to %s -- I already seeded with %s.\n" % (a, SEED,))
707+    return
708+random.seed = seed_which_refuses
709+
710+from random import randrange
711+
712 import unittest
713 
714 from pycryptopp.publickey import ecdsa
715 
716+def randstr(n, rr=randrange):
717+    return ''.join([chr(rr(0, 256)) for x in xrange(n)])
718+
719 from base64 import b32encode
720 def ab(x): # debuggery
721     if len(x) >= 3:
722@@ -17,102 +46,186 @@
723     elif len(x) == 0:
724         return "%s:%s" % (len(x), "--empty--",)
725 
726-def randstr(n):
727-    return ''.join(map(chr, map(random.randrange, [0]*n, [256]*n)))
728+def div_ceil(n, d):
729+    """
730+    The smallest integer k such that k*d >= n.
731+    """
732+    return (n/d) + (n%d != 0)
733+
734+KEYBITS=192
735+
736+# The number of bytes required for a seed to have the same security level as a
737+# key in this elliptic curve: 2 bits of public key per bit of security.
738+SEEDBITS=div_ceil(192, 2)
739+SEEDBYTES=div_ceil(SEEDBITS, 8)
740+
741+# The number of bytes required to encode a public key in this elliptic curve.
742+PUBKEYBYTES=div_ceil(KEYBITS, 8)+1 # 1 byte for the sign of the y component
743+
744+# The number of bytes requires to encode a signature in this elliptic curve.
745+SIGBITS=KEYBITS*2
746+SIGBYTES=div_ceil(SIGBITS, 8)
747 
748-KEYSIZE=192 # The choices are 192 or 521 -- they are both secure, and 192 makes for faster unit tests.
749 class Signer(unittest.TestCase):
750-    def test_generate_bad_size(self):
751+    def test_construct_from_same_seed_is_reproducible(self):
752+        seed = randstr(SEEDBYTES)
753+        signer1 = ecdsa.SigningKey(seed)
754+        self.failUnlessEqual(signer1.serialize(), seed)
755+        signer2 = ecdsa.SigningKey(seed)
756+        self.failUnlessEqual(signer1.serialize(), signer2.serialize())
757+        self.failUnlessEqual(signer1.get_verifying_key().serialize(), signer2.get_verifying_key().serialize())
758+
759+        # ... and using different seeds constructs a different private key.
760+        seed3 = randstr(SEEDBYTES)
761+        assert seed3 != seed, "Internal error in Python random module's PRNG (or in pycryptopp's hacks to it to facilitate testing) -- got two identical strings from randstr(%s)" % SEEDBYTES
762+        signer3 = ecdsa.SigningKey(seed3)
763+        self.failUnlessEqual(signer3.serialize(), seed3)
764+        self.failUnlessEqual(signer1.serialize(), signer3.serialize())
765+        self.failIfEqual(signer1.get_verifying_key().serialize(), signer3.get_verifying_key().serialize())
766+
767+        # Also try the all-zeroes string just because bugs sometimes are
768+        # data-dependent on zero or cause bogus zeroes.
769+        seed4 = '\x00'*SEEDBYTES
770+        assert seed4 != seed, "Internal error in Python random module's PRNG (or in pycryptopp's hacks to it to facilitate testing) -- got the all-zeroes string from randstr(%s)" % SEEDBYTES
771+        signer4 = ecdsa.SigningKey(seed4)
772+        self.failUnlessEqual(signer4.serialize(), seed4)
773+        self.failUnlessEqual(signer4.serialize(), signer1.serialize())
774+        self.failIfEqual(signer4.get_verifying_key().serialize(), signer1.get_verifying_key().serialize())
775+
776+        signer5 = ecdsa.SigningKey(seed4)
777+        self.failUnlessEqual(signer5.serialize(), seed4)
778+        self.failUnlessEqual(signer5.serialize(), signer4.serialize())
779+        self.failUnlessEqual(signer5.get_verifying_key().serialize(), signer4.get_verifying_key().serialize())
780+
781+    def test_construct_short_seed(self):
782         try:
783-            signer = ecdsa.generate(KEYSIZE-1)
784+            signer = ecdsa.SigningKey("\x00\x00\x00")
785         except ecdsa.Error, le:
786-            self.failUnless("size in bits is required to be " in str(le), le)
787+            self.failUnless("seed is required to be of length >=" in str(le), le)
788         else:
789-            self.fail("Should have raised error from size being too small.")
790+           self.fail("Should have raised error from seed being too short.")
791+
792+    def test_construct_bad_arg_type(self):
793         try:
794-            signer = ecdsa.generate(sizeinbits=KEYSIZE-1)
795-        except ecdsa.Error, le:
796-            self.failUnless("size in bits is required to be " in str(le), le)
797+            signer = ecdsa.SigningKey(1)
798+        except TypeError, le:
799+            self.failUnless("must be string" in str(le), le)
800         else:
801-            self.fail("Should have raised error from size being too small.")
802+           self.fail("Should have raised error from seed being of the wrong type.")
803 
804-    def test_generate(self):
805-        signer = ecdsa.generate(KEYSIZE)
806-        # Hooray!  It didn't raise an exception!  We win!
807-        signer = ecdsa.generate(sizeinbits=KEYSIZE)
808-        # Hooray!  It didn't raise an exception!  We win!
809-
810-    def test_sign(self):
811-        signer = ecdsa.generate(KEYSIZE)
812-        result = signer.sign("abc")
813-        self.failUnlessEqual(len(result), 2*((KEYSIZE+7)/8))
814-        # TODO: test against someone's official test vectors.
815+class Verifier(unittest.TestCase):
816+    def test_from_signer_and_serialize_and_deserialize(self):
817+        seed = randstr(SEEDBYTES)
818+        signer = ecdsa.SigningKey(seed)
819+
820+        verifier = signer.get_verifying_key()
821+        s1 = verifier.serialize()
822+        self.failUnlessEqual(len(s1), PUBKEYBYTES)
823+        verifier2 = ecdsa.create_verifying_key_from_string(s1)
824+        s2 = verifier.serialize()
825+        self.failUnlessEqual(s1, s2)
826+
827+def flip_one_bit(s):
828+    i = randrange(0, len(s))
829+    result = s[:i] + chr(ord(s[i])^(0x01<<randrange(0, 8))) + s[i+1:]
830+    assert result != s, "Internal error -- flip_one_bit() produced the same string as its input: %s == %s" % (result, s)
831+    return result
832+
833+def randmsg():
834+    # Choose a random message size from a range probably large enough to
835+    # exercise any different code paths which depend on the message length.
836+    randmsglen = randrange(0, SIGBYTES*2+2)
837+    return randstr(randmsglen)
838 
839 class SignAndVerify(unittest.TestCase):
840-    def _help_test_sign_and_check(self, signer, verifier, msg):
841+    def _help_test_sign_and_check_good_keys(self, signer, verifier):
842+        msg = randmsg()
843+
844         sig = signer.sign(msg)
845-        self.failUnlessEqual(len(sig), 2*((KEYSIZE+7)/8))
846+        self.failUnlessEqual(len(sig), SIGBYTES)
847         self.failUnless(verifier.verify(msg, sig))
848 
849-    def test_sign_and_check_a(self):
850-        signer = ecdsa.generate(KEYSIZE)
851-        verifier = signer.get_verifying_key()
852-        return self._help_test_sign_and_check(signer, verifier, "a")
853-
854-    def _help_test_sign_and_check_random(self, signer, verifier):
855-        for i in range(3):
856-            l = random.randrange(0, 2**10)
857-            msg = randstr(l)
858-            self._help_test_sign_and_check(signer, verifier, msg)
859-
860-    def test_sign_and_check_random(self):
861-        signer = ecdsa.generate(KEYSIZE)
862-        verifier = signer.get_verifying_key()
863-        return self._help_test_sign_and_check_random(signer, verifier)
864-
865-    def _help_test_sign_and_failcheck(self, signer, verifier, msg):
866-        sig = signer.sign("a")
867-        sig = sig[:-1] + chr(ord(sig[-1])^0x01)
868-        self.failUnless(not verifier.verify(msg, sig))
869+        # Now flip one bit of the signature and make sure that the signature doesn't check.
870+        badsig = flip_one_bit(sig)
871+        self.failIf(verifier.verify(msg, badsig))
872+
873+        # Now generate a random signature and make sure that the signature doesn't check.
874+        badsig = randstr(len(sig))
875+        assert badsig != sig, "Internal error -- randstr() produced the same string twice: %s == %s" % (badsig, sig)
876+        self.failIf(verifier.verify(msg, badsig))
877+
878+        # Now flip one bit of the message and make sure that the original signature doesn't check.
879+        badmsg = flip_one_bit(msg)
880+        self.failIf(verifier.verify(badmsg, sig))
881+
882+        # Now generate a random message and make sure that the original signature doesn't check.
883+        badmsg = randstr(len(msg))
884+        assert badmsg != msg, "Internal error -- randstr() produced the same string twice: %s == %s" % (badmsg, msg)
885+        self.failIf(verifier.verify(badmsg, sig))
886+
887+    def _help_test_sign_and_check_bad_keys(self, signer, verifier):
888+        """
889+        Make sure that this signer/verifier pair cannot produce and verify signatures.
890+        """
891+        msg = randmsg()
892 
893-    def test_sign_and_failcheck_a(self):
894-        signer = ecdsa.generate(KEYSIZE)
895-        verifier = signer.get_verifying_key()
896-        return self._help_test_sign_and_failcheck(signer, verifier, "a")
897-
898-    def _help_test_sign_and_failcheck_random(self, signer, verifier):
899-        for i in range(3):
900-            l = random.randrange(0, 2**10)
901-            msg = randstr(l)
902-            self._help_test_sign_and_failcheck(signer, verifier, msg)
903+        sig = signer.sign(msg)
904+        self.failUnlessEqual(len(sig), SIGBYTES)
905+        self.failIf(verifier.verify(msg, sig))
906 
907-    def test_sign_and_failcheck_random(self):
908-        signer = ecdsa.generate(KEYSIZE)
909-        verifier = signer.get_verifying_key()
910-        return self._help_test_sign_and_failcheck_random(signer, verifier)
911+    def test(self):
912+        seed = randstr(SEEDBYTES)
913+        sys.stdout.write("xxx 0\n");sys.stdout.flush()
914+        signer = ecdsa.SigningKey(seed)
915+        sys.stdout.write("xxx 1\n");sys.stdout.flush()
916+        verifier = signer.get_verifying_key()
917+        sys.stdout.write("xxx 2\n");sys.stdout.flush()
918+        self._help_test_sign_and_check_good_keys(signer, verifier)
919+        sys.stdout.write("xxx 3\n");sys.stdout.flush()
920+
921+        vstr = verifier.serialize()
922+        verifier2 = ecdsa.create_verifying_key_from_string(vstr)
923+        self._help_test_sign_and_check_good_keys(signer, verifier2)
924+       
925+        signer2 = ecdsa.SigningKey(seed)
926+        self._help_test_sign_and_check_good_keys(signer2, verifier2)
927+         
928+        verifier3 = signer2.get_verifying_key()
929+        self._help_test_sign_and_check_good_keys(signer, verifier3)
930 
931-    def test_serialize_and_deserialize_verifying_key_and_test(self):
932-        signer = ecdsa.generate(KEYSIZE)
933-        verifier = signer.get_verifying_key()
934-        serstr = verifier.serialize()
935-        verifier = None
936-        newverifier = ecdsa.create_verifying_key_from_string(serstr)
937-        self._help_test_sign_and_check(signer, newverifier, "a")
938-        self._help_test_sign_and_check_random(signer, newverifier)
939-        self._help_test_sign_and_failcheck(signer, newverifier, "a")
940-        self._help_test_sign_and_failcheck_random(signer, newverifier)
941+        # Now test various ways that the keys could be corrupted or ill-matched.
942 
943-    def test_serialize_and_deserialize_signing_key_and_test(self):
944-        signer = ecdsa.generate(KEYSIZE)
945-        verifier = signer.get_verifying_key()
946-        serstr = signer.serialize()
947-        signer = None
948-        newsigner = ecdsa.create_signing_key_from_string(serstr)
949-        self._help_test_sign_and_check(newsigner, verifier, "a")
950-        self._help_test_sign_and_check_random(newsigner, verifier)
951-        self._help_test_sign_and_failcheck(newsigner, verifier, "a")
952-        self._help_test_sign_and_failcheck_random(newsigner, verifier)
953+        # Flip one bit of the public key.
954+        badvstr = flip_one_bit(vstr)
955+        try:
956+            badverifier = ecdsa.create_verifying_key_from_string(badvstr)
957+        except ecdsa.Error, le:
958+            # Ok, fine, the verifying key was corrupted and Crypto++ detected this fact.
959+            pass
960+        else:
961+            self._help_test_sign_and_check_bad_keys(signer, badverifier)
962 
963+        # Randomize all bits of the public key.
964+        badvstr = randstr(len(vstr))
965+        assert badvstr != vstr, "Internal error -- randstr() produced the same string twice: %s == %s" % (badvstr, vstr)
966+        try:
967+            badverifier = ecdsa.create_verifying_key_from_string(badvstr)
968+        except ecdsa.Error, le:
969+            # Ok, fine, the key was corrupted and Crypto++ detected this fact.
970+            pass
971+        else:
972+            self._help_test_sign_and_check_bad_keys(signer, badverifier)
973+       
974+        # Flip one bit of the private key.
975+        badseed = flip_one_bit(seed)
976+        badsigner = ecdsa.SigningKey(badseed)
977+        self._help_test_sign_and_check_bad_keys(badsigner, verifier)
978+
979+        # Randomize all bits of the private key.
980+        badseed = randstr(len(seed))
981+        assert badseed != seed, "Internal error -- randstr() produced the same string twice: %s == %s" % (badseed, seed)
982+        badsigner = ecdsa.SigningKey(badseed)
983+        self._help_test_sign_and_check_bad_keys(badsigner, verifier)
984 
985 if __name__ == "__main__":
986     unittest.main()