]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
copy RSA from PyCrypto into the allmydata/ tree, we'll use it eventually
authorBrian Warner <warner@lothar.com>
Thu, 16 Aug 2007 00:36:39 +0000 (17:36 -0700)
committerBrian Warner <warner@lothar.com>
Thu, 16 Aug 2007 00:36:39 +0000 (17:36 -0700)
setup.py
src/allmydata/Crypto/PublicKey/RSA.py [new file with mode: 0644]
src/allmydata/Crypto/PublicKey/__init__.py [new file with mode: 0644]
src/allmydata/Crypto/PublicKey/pubkey.py [new file with mode: 0644]
src/allmydata/Crypto/_fastmath.c [new file with mode: 0644]

index 2fc54ea9c79d9de958b178a0ea8b6728d410242d..f2da9a3039c78ac8bf5cbb2e39e41351a45dd771 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -85,7 +85,8 @@ setup(name='allmydata-tahoe',
       packages=["allmydata", "allmydata.test", "allmydata.util",
                 "allmydata.scripts",
                 "allmydata.Crypto", "allmydata.Crypto.Cipher",
-                "allmydata.Crypto.Hash", "allmydata.Crypto.Util"],
+                "allmydata.Crypto.Hash", "allmydata.Crypto.Util",
+                "allmydata.Crypto.PublicKey"],
       package_dir={ "allmydata": "src/allmydata",},
       scripts = ["bin/allmydata-tahoe"],
       package_data={ 'allmydata': ['web/*.xhtml', 'web/*.html', 'web/*.css'] },
@@ -98,5 +99,7 @@ setup(name='allmydata-tahoe',
           Extension("allmydata.Crypto.Hash.SHA256",
                     include_dirs=["src/allmydata/Crypto"],
                     sources=["src/allmydata/Crypto/SHA256.c"]),
+          Extension("allmydata.Crypto.PublicKey._fastmath",
+                    sources=["src/allmydata/Crypto/_fastmath.c"]),
           ],
       )
diff --git a/src/allmydata/Crypto/PublicKey/RSA.py b/src/allmydata/Crypto/PublicKey/RSA.py
new file mode 100644 (file)
index 0000000..6453373
--- /dev/null
@@ -0,0 +1,257 @@
+#
+#   RSA.py : RSA encryption/decryption
+#
+#  Part of the Python Cryptography Toolkit
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence.  This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+__revision__ = "$Id: RSA.py,v 1.20 2004/05/06 12:52:54 akuchling Exp $"
+
+from allmydata.Crypto.PublicKey import pubkey
+from allmydata.Crypto.Util import number
+
+_fastmath = None
+try:
+    from allmydata.Crypto.PublicKey import _fastmath
+except ImportError:
+    pass
+
+class error (Exception):
+    pass
+
+def generate(bits, randfunc, progress_func=None):
+    """generate(bits:int, randfunc:callable, progress_func:callable)
+
+    Generate an RSA key of length 'bits', using 'randfunc' to get
+    random data and 'progress_func', if present, to display
+    the progress of the key generation.
+    """
+    obj=RSAobj()
+
+    # Generate the prime factors of n
+    if progress_func:
+        progress_func('p,q\n')
+    p = q = 1L
+    while number.size(p*q) < bits:
+        p = pubkey.getPrime(bits/2, randfunc)
+        q = pubkey.getPrime(bits/2, randfunc)
+
+    # p shall be smaller than q (for calc of u)
+    if p > q:
+        (p, q)=(q, p)
+    obj.p = p
+    obj.q = q
+
+    if progress_func:
+        progress_func('u\n')
+    obj.u = pubkey.inverse(obj.p, obj.q)
+    obj.n = obj.p*obj.q
+
+    obj.e = 65537L
+    if progress_func:
+        progress_func('d\n')
+    obj.d=pubkey.inverse(obj.e, (obj.p-1)*(obj.q-1))
+
+    assert bits <= 1+obj.size(), "Generated key is too small"
+
+    return obj
+
+def construct(tuple):
+    """construct(tuple:(long,) : RSAobj
+    Construct an RSA object from a 2-, 3-, 5-, or 6-tuple of numbers.
+    """
+
+    obj=RSAobj()
+    if len(tuple) not in [2,3,5,6]:
+        raise error, 'argument for construct() wrong length'
+    for i in range(len(tuple)):
+        field = obj.keydata[i]
+        setattr(obj, field, tuple[i])
+    if len(tuple) >= 5:
+        # Ensure p is smaller than q 
+        if obj.p>obj.q:
+            (obj.p, obj.q)=(obj.q, obj.p)
+
+    if len(tuple) == 5:
+        # u not supplied, so we're going to have to compute it.
+        obj.u=pubkey.inverse(obj.p, obj.q)
+
+    return obj
+
+class RSAobj(pubkey.pubkey):
+    keydata = ['n', 'e', 'd', 'p', 'q', 'u']
+    def _encrypt(self, plaintext, K=''):
+        if self.n<=plaintext:
+            raise error, 'Plaintext too large'
+        return (pow(plaintext, self.e, self.n),)
+
+    def _decrypt(self, ciphertext):
+        if (not hasattr(self, 'd')):
+            raise error, 'Private key not available in this object'
+        if self.n<=ciphertext[0]:
+            raise error, 'Ciphertext too large'
+        return pow(ciphertext[0], self.d, self.n)
+
+    def _sign(self, M, K=''):
+        return (self._decrypt((M,)),)
+
+    def _verify(self, M, sig):
+        m2=self._encrypt(sig[0])
+        if m2[0]==M:
+            return 1
+        else: return 0
+
+    def _blind(self, M, B):
+        tmp = pow(B, self.e, self.n)
+        return (M * tmp) % self.n
+
+    def _unblind(self, M, B):
+        tmp = pubkey.inverse(B, self.n)
+        return  (M * tmp) % self.n
+
+    def can_blind (self):
+        """can_blind() : bool
+        Return a Boolean value recording whether this algorithm can
+        blind data.  (This does not imply that this
+        particular key object has the private information required to
+        to blind a message.)
+        """
+        return 1
+
+    def size(self):
+        """size() : int
+        Return the maximum number of bits that can be handled by this key.
+        """
+        return number.size(self.n) - 1
+
+    def has_private(self):
+        """has_private() : bool
+        Return a Boolean denoting whether the object contains
+        private components.
+        """
+        if hasattr(self, 'd'):
+            return 1
+        else: return 0
+
+    def publickey(self):
+        """publickey(): RSAobj
+        Return a new key object containing only the public key information.
+        """
+        return construct((self.n, self.e))
+
+class RSAobj_c(pubkey.pubkey):
+    keydata = ['n', 'e', 'd', 'p', 'q', 'u']
+
+    def __init__(self, key):
+        self.key = key
+
+    def __getattr__(self, attr):
+        if attr in self.keydata:
+            return getattr(self.key, attr)
+        else:
+            if self.__dict__.has_key(attr):
+                self.__dict__[attr]
+            else:
+                raise AttributeError, '%s instance has no attribute %s' % (self.__class__, attr)
+
+    def __getstate__(self):
+        d = {}
+        for k in self.keydata:
+            if hasattr(self.key, k):
+                d[k]=getattr(self.key, k)
+        return d
+
+    def __setstate__(self, state):
+        n,e = state['n'], state['e']
+        if not state.has_key('d'):
+            self.key = _fastmath.rsa_construct(n,e)
+        else:
+            d = state['d']
+            if not state.has_key('q'):
+                self.key = _fastmath.rsa_construct(n,e,d)
+            else:
+                p, q, u = state['p'], state['q'], state['u']
+                self.key = _fastmath.rsa_construct(n,e,d,p,q,u)
+
+    def _encrypt(self, plain, K):
+        return (self.key._encrypt(plain),)
+
+    def _decrypt(self, cipher):
+        return self.key._decrypt(cipher[0])
+
+    def _sign(self, M, K):
+        return (self.key._sign(M),)
+
+    def _verify(self, M, sig):
+        return self.key._verify(M, sig[0])
+
+    def _blind(self, M, B):
+        return self.key._blind(M, B)
+
+    def _unblind(self, M, B):
+        return self.key._unblind(M, B)
+
+    def can_blind (self):
+        return 1
+
+    def size(self):
+        return self.key.size()
+
+    def has_private(self):
+        return self.key.has_private()
+
+    def publickey(self):
+        return construct_c((self.key.n, self.key.e))
+
+def generate_c(bits, randfunc, progress_func = None):
+    # Generate the prime factors of n
+    if progress_func:
+        progress_func('p,q\n')
+
+    p = q = 1L
+    while number.size(p*q) < bits:
+        p = pubkey.getPrime(bits/2, randfunc)
+        q = pubkey.getPrime(bits/2, randfunc)
+
+    # p shall be smaller than q (for calc of u)
+    if p > q:
+        (p, q)=(q, p)
+    if progress_func:
+        progress_func('u\n')
+    u=pubkey.inverse(p, q)
+    n=p*q
+
+    e = 65537L
+    if progress_func:
+        progress_func('d\n')
+    d=pubkey.inverse(e, (p-1)*(q-1))
+    key = _fastmath.rsa_construct(n,e,d,p,q,u)
+    obj = RSAobj_c(key)
+
+##    print p
+##    print q
+##    print number.size(p), number.size(q), number.size(q*p),
+##    print obj.size(), bits
+    assert bits <= 1+obj.size(), "Generated key is too small"
+    return obj
+
+
+def construct_c(tuple):
+    key = apply(_fastmath.rsa_construct, tuple)
+    return RSAobj_c(key)
+
+object = RSAobj
+
+generate_py = generate
+construct_py = construct
+
+if _fastmath:
+    #print "using C version of RSA"
+    generate = generate_c
+    construct = construct_c
+    error = _fastmath.error
diff --git a/src/allmydata/Crypto/PublicKey/__init__.py b/src/allmydata/Crypto/PublicKey/__init__.py
new file mode 100644 (file)
index 0000000..0d4dfa3
--- /dev/null
@@ -0,0 +1,17 @@
+"""Public-key encryption and signature algorithms.
+
+Public-key encryption uses two different keys, one for encryption and
+one for decryption.  The encryption key can be made public, and the
+decryption key is kept private.  Many public-key algorithms can also
+be used to sign messages, and some can *only* be used for signatures.
+
+Crypto.PublicKey.DSA      Digital Signature Algorithm. (Signature only)
+Crypto.PublicKey.ElGamal  (Signing and encryption)
+Crypto.PublicKey.RSA      (Signing, encryption, and blinding)
+Crypto.PublicKey.qNEW     (Signature only)
+
+"""
+
+__all__ = ['RSA']
+__revision__ = "$Id: __init__.py,v 1.4 2003/04/03 20:27:13 akuchling Exp $"
+
diff --git a/src/allmydata/Crypto/PublicKey/pubkey.py b/src/allmydata/Crypto/PublicKey/pubkey.py
new file mode 100644 (file)
index 0000000..091a9c9
--- /dev/null
@@ -0,0 +1,173 @@
+#
+#   pubkey.py : Internal functions for public key operations
+#
+#  Part of the Python Cryptography Toolkit
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence.  This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+__revision__ = "$Id: pubkey.py,v 1.11 2003/04/03 20:36:14 akuchling Exp $"
+
+import types, warnings
+from allmydata.Crypto.Util.number import bignum, bytes_to_long, \
+     long_to_bytes, error
+
+# Basic public key class
+class pubkey:
+    def __init__(self):
+        pass
+
+    def __getstate__(self):
+        """To keep key objects platform-independent, the key data is
+        converted to standard Python long integers before being
+        written out.  It will then be reconverted as necessary on
+        restoration."""
+        d=self.__dict__
+        for key in self.keydata:
+            if d.has_key(key): d[key]=long(d[key])
+        return d
+
+    def __setstate__(self, d):
+        """On unpickling a key object, the key data is converted to the big
+number representation being used, whether that is Python long
+integers, MPZ objects, or whatever."""
+        for key in self.keydata:
+            if d.has_key(key): self.__dict__[key]=bignum(d[key])
+
+    def encrypt(self, plaintext, K):
+        """encrypt(plaintext:string|long, K:string|long) : tuple
+        Encrypt the string or integer plaintext.  K is a random
+        parameter required by some algorithms.
+        """
+        wasString=0
+        if isinstance(plaintext, types.StringType):
+            plaintext=bytes_to_long(plaintext) ; wasString=1
+        if isinstance(K, types.StringType):
+            K=bytes_to_long(K)
+        ciphertext=self._encrypt(plaintext, K)
+        if wasString: return tuple(map(long_to_bytes, ciphertext))
+        else: return ciphertext
+
+    def decrypt(self, ciphertext):
+        """decrypt(ciphertext:tuple|string|long): string
+        Decrypt 'ciphertext' using this key.
+        """
+        wasString=0
+        if not isinstance(ciphertext, types.TupleType):
+            ciphertext=(ciphertext,)
+        if isinstance(ciphertext[0], types.StringType):
+            ciphertext=tuple(map(bytes_to_long, ciphertext)) ; wasString=1
+        plaintext=self._decrypt(ciphertext)
+        if wasString: return long_to_bytes(plaintext)
+        else: return plaintext
+
+    def sign(self, M, K):
+        """sign(M : string|long, K:string|long) : tuple
+        Return a tuple containing the signature for the message M.
+        K is a random parameter required by some algorithms.
+        """
+        if (not self.has_private()):
+            raise error, 'Private key not available in this object'
+        if isinstance(M, types.StringType): M=bytes_to_long(M)
+        if isinstance(K, types.StringType): K=bytes_to_long(K)
+        return self._sign(M, K)
+
+    def verify (self, M, signature):
+        """verify(M:string|long, signature:tuple) : bool
+        Verify that the signature is valid for the message M;
+        returns true if the signature checks out.
+        """
+        if isinstance(M, types.StringType): M=bytes_to_long(M)
+        return self._verify(M, signature)
+
+    # alias to compensate for the old validate() name
+    def validate (self, M, signature):
+        warnings.warn("validate() method name is obsolete; use verify()",
+                      DeprecationWarning)
+
+    def blind(self, M, B):
+        """blind(M : string|long, B : string|long) : string|long
+        Blind message M using blinding factor B.
+        """
+        wasString=0
+        if isinstance(M, types.StringType):
+            M=bytes_to_long(M) ; wasString=1
+        if isinstance(B, types.StringType): B=bytes_to_long(B)
+        blindedmessage=self._blind(M, B)
+        if wasString: return long_to_bytes(blindedmessage)
+        else: return blindedmessage
+
+    def unblind(self, M, B):
+        """unblind(M : string|long, B : string|long) : string|long
+        Unblind message M using blinding factor B.
+        """
+        wasString=0
+        if isinstance(M, types.StringType):
+            M=bytes_to_long(M) ; wasString=1
+        if isinstance(B, types.StringType): B=bytes_to_long(B)
+        unblindedmessage=self._unblind(M, B)
+        if wasString: return long_to_bytes(unblindedmessage)
+        else: return unblindedmessage
+
+
+    # The following methods will usually be left alone, except for
+    # signature-only algorithms.  They both return Boolean values
+    # recording whether this key's algorithm can sign and encrypt.
+    def can_sign (self):
+        """can_sign() : bool
+        Return a Boolean value recording whether this algorithm can
+        generate signatures.  (This does not imply that this
+        particular key object has the private information required to
+        to generate a signature.)
+        """
+        return 1
+
+    def can_encrypt (self):
+        """can_encrypt() : bool
+        Return a Boolean value recording whether this algorithm can
+        encrypt data.  (This does not imply that this
+        particular key object has the private information required to
+        to decrypt a message.)
+        """
+        return 1
+
+    def can_blind (self):
+        """can_blind() : bool
+        Return a Boolean value recording whether this algorithm can
+        blind data.  (This does not imply that this
+        particular key object has the private information required to
+        to blind a message.)
+        """
+        return 0
+
+    # The following methods will certainly be overridden by
+    # subclasses.
+
+    def size (self):
+        """size() : int
+        Return the maximum number of bits that can be handled by this key.
+        """
+        return 0
+
+    def has_private (self):
+        """has_private() : bool
+        Return a Boolean denoting whether the object contains
+        private components.
+        """
+        return 0
+
+    def publickey (self):
+        """publickey(): object
+        Return a new key object containing only the public information.
+        """
+        return self
+
+    def __eq__ (self, other):
+        """__eq__(other): 0, 1
+        Compare us to other for equality.
+        """
+        return self.__getstate__() == other.__getstate__()
diff --git a/src/allmydata/Crypto/_fastmath.c b/src/allmydata/Crypto/_fastmath.c
new file mode 100644 (file)
index 0000000..7fe7abe
--- /dev/null
@@ -0,0 +1,804 @@
+
+/*
+ *  _fastmath.c: Accelerator module that uses GMP for faster numerics.
+ *
+ * Part of the Python Cryptography Toolkit
+ *
+ * Distribute and use freely; there are no restrictions on further 
+ * dissemination and usage except those imposed by the laws of your 
+ * country of residence.
+ *
+ * $Id: _fastmath.c,v 1.13 2003/04/04 19:20:29 jbontje Exp $
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <Python.h>
+#include <longintrepr.h>                               /* for conversions */
+#include <gmp.h>
+
+void
+longObjToMPZ (mpz_t m, PyLongObject * p)
+{
+       int size, i;
+       mpz_t temp, temp2;
+       mpz_init (temp);
+       mpz_init (temp2);
+       if (p->ob_size > 0)
+               size = p->ob_size;
+       else
+               size = -p->ob_size;
+       for (i = 0; i < size; i++)
+       {
+               mpz_set_ui (temp, p->ob_digit[i]);
+               mpz_mul_2exp (temp2, temp, SHIFT * i);
+               mpz_add (m, m, temp2);
+       }
+       mpz_clear (temp);
+       mpz_clear (temp2);
+}
+
+PyObject *
+mpzToLongObj (mpz_t m)
+{
+       /* borrowed from gmpy */
+       int size = (mpz_sizeinbase (m, 2) + SHIFT - 1) / SHIFT;
+       int i;
+       mpz_t temp;
+       PyLongObject *l = _PyLong_New (size);
+       if (!l)
+               return NULL;
+       mpz_init_set (temp, m);
+       for (i = 0; i < size; i++)
+       {
+               l->ob_digit[i] = (digit) (mpz_get_ui (temp) & MASK);
+               mpz_fdiv_q_2exp (temp, temp, SHIFT);
+       }
+       i = size;
+       while ((i > 0) && (l->ob_digit[i - 1] == 0))
+               i--;
+       l->ob_size = i;
+       mpz_clear (temp);
+       return (PyObject *) l;
+}
+
+typedef struct
+{
+       PyObject_HEAD mpz_t y;
+       mpz_t g;
+       mpz_t p;
+       mpz_t q;
+       mpz_t x;
+}
+dsaKey;
+
+typedef struct
+{
+       PyObject_HEAD mpz_t n;
+       mpz_t e;
+       mpz_t d;
+       mpz_t p;
+       mpz_t q;
+       mpz_t u;
+}
+rsaKey;
+
+PyObject *rsaKey_new (PyObject *, PyObject *);
+PyObject *dsaKey_new (PyObject *, PyObject *);
+
+static void dsaKey_dealloc (dsaKey *);
+static PyObject *dsaKey_getattr (dsaKey *, char *);
+static PyObject *dsaKey__sign (dsaKey *, PyObject *);
+static PyObject *dsaKey__verify (dsaKey *, PyObject *);
+static PyObject *dsaKey_size (dsaKey *, PyObject *);
+static PyObject *dsaKey_has_private (dsaKey *, PyObject *);
+
+static void rsaKey_dealloc (rsaKey *);
+static PyObject *rsaKey_getattr (rsaKey *, char *);
+static PyObject *rsaKey__encrypt (rsaKey *, PyObject *);
+static PyObject *rsaKey__decrypt (rsaKey *, PyObject *);
+static PyObject *rsaKey__verify (rsaKey *, PyObject *);
+static PyObject *rsaKey__blind (rsaKey *, PyObject *);
+static PyObject *rsaKey__unblind (rsaKey *, PyObject *);
+static PyObject *rsaKey_size (rsaKey *, PyObject *);
+static PyObject *rsaKey_has_private (rsaKey *, PyObject *);
+
+static int
+dsaSign (dsaKey * key, mpz_t m, mpz_t k, mpz_t r, mpz_t s)
+{
+       mpz_t temp;
+       if (mpz_cmp_ui (k, 2) < 0 || mpz_cmp (k, key->q) >= 0)
+       {
+               return 1;
+       }
+       mpz_init (temp);
+       mpz_powm (r, key->g, k, key->p);
+       mpz_mod (r, r, key->q);
+       mpz_invert (s, k, key->q);
+       mpz_mul (temp, key->x, r);
+       mpz_add (temp, m, temp);
+       mpz_mul (s, s, temp);
+       mpz_mod (s, s, key->q);
+       mpz_clear (temp);
+       return 0;
+}
+
+static int
+dsaVerify (dsaKey * key, mpz_t m, mpz_t r, mpz_t s)
+{
+       int result;
+       mpz_t u1, u2, v1, v2, w;
+       if (mpz_cmp_ui (r, 0) <= 0 || mpz_cmp (r, key->q) >= 0 ||
+           mpz_cmp_ui (s, 0) <= 0 || mpz_cmp (s, key->q) >= 0)
+               return 0;
+       mpz_init (u1);
+       mpz_init (u2);
+       mpz_init (v1);
+       mpz_init (v2);
+       mpz_init (w);
+       mpz_invert (w, s, key->q);
+       mpz_mul (u1, m, w);
+       mpz_mod (u1, u1, key->q);
+       mpz_mul (u2, r, w);
+       mpz_mod (u2, u2, key->q);
+       mpz_powm (v1, key->g, u1, key->p);
+       mpz_powm (v2, key->y, u2, key->p);
+       mpz_mul (w, v1, v2);
+       mpz_mod (w, w, key->p);
+       mpz_mod (w, w, key->q);
+       if (mpz_cmp (r, w) == 0)
+               result = 1;
+       else
+               result = 0;
+       mpz_clear (u1);
+       mpz_clear (u2);
+       mpz_clear (v1);
+       mpz_clear (v2);
+       mpz_clear (w);
+       return result;
+}
+
+
+static int
+rsaEncrypt (rsaKey * key, mpz_t v)
+{
+       if (mpz_cmp (v, key->n) >= 0)
+       {
+               return 1;
+       }
+       mpz_powm (v, v, key->e, key->n);
+       return 0;
+}
+
+static int
+rsaDecrypt (rsaKey * key, mpz_t v)
+{
+    mpz_t m1, m2, h;
+       if (mpz_cmp (v, key->n) >= 0)
+       {
+               return 1;
+       }
+       if (mpz_size (key->d) == 0)
+       {
+               return 2;
+       }
+
+    if ((mpz_size (key->p) != 0) && (mpz_size (key->q) != 0) && 
+        (mpz_size (key->u) != 0))
+    {
+        /* fast path */
+        mpz_init(m1);
+        mpz_init(m2);
+        mpz_init(h);
+
+        /* m1 = c ^ (d mod (p-1)) mod p */
+        mpz_sub_ui(h, key->p, 1);
+        mpz_fdiv_r(h, key->d, h);
+        mpz_powm(m1, v, h, key->p);
+        /* m2 = c ^ (d mod (q-1)) mod q */
+        mpz_sub_ui(h, key->q, 1);
+        mpz_fdiv_r(h, key->d, h);
+        mpz_powm(m2, v, h, key->q);
+        /* h = u * ( m2 - m1 ) mod q */
+        mpz_sub(h, m2, m1);
+        if (mpz_sgn(h)==-1)
+            mpz_add(h, h, key->q);
+        mpz_mul(h, key->u, h);
+        mpz_mod(h, h, key->q);
+        /* m = m2 + h * p */
+        mpz_mul(h, h, key->p);
+        mpz_add(v, m1, h);
+        /* ready */
+
+        mpz_clear(m1);
+        mpz_clear(m2);
+        mpz_clear(h);
+        return 0;
+    }
+
+    /* slow */
+       mpz_powm (v, v, key->d, key->n);
+       return 0;
+}
+
+static int
+rsaBlind (rsaKey * key, mpz_t v, mpz_t b)
+{
+    if (mpz_cmp (v, key->n) >= 0)
+        {
+            return 1;
+        }
+    if (mpz_cmp (b, key->n) >= 0)
+        {
+            return 2;
+        }
+    mpz_powm (b, b, key->e, key->n);
+    mpz_mul (v, v, b);
+    mpz_mod (v, v, key->n);
+    return 0;
+}
+
+static int
+rsaUnBlind (rsaKey * key, mpz_t v, mpz_t b)
+{
+    if (mpz_cmp (v, key->n) >= 0)
+        {
+            return 1;
+        }
+    if (mpz_cmp (b, key->n) >= 0)
+        {
+            return 2;
+        }
+    if (!mpz_invert (b, b, key->n))
+        {
+            return 3;
+        }
+    mpz_mul (v, v, b);
+    mpz_mod (v, v, key->n);
+    return 0;
+}
+
+static PyTypeObject dsaKeyType = {
+       PyObject_HEAD_INIT (NULL) 0,
+       "dsaKey",
+       sizeof (dsaKey),
+       0,
+       (destructor) dsaKey_dealloc,    /* dealloc */
+       0,                              /* print */
+       (getattrfunc) dsaKey_getattr,   /* getattr */
+       0,                              /* setattr */
+       0,                              /* compare */
+       0,                              /* repr */
+       0,                              /* as_number */
+       0,                              /* as_sequence */
+       0,                              /* as_mapping */
+       0,                              /* hash */
+       0,                              /* call */
+};
+
+static PyMethodDef dsaKey__methods__[] = {
+       {"_sign", (PyCFunction) dsaKey__sign, METH_VARARGS, 
+        "Sign the given long."},
+       {"_verify", (PyCFunction) dsaKey__verify, METH_VARARGS,
+        "Verify that the signature is valid."},
+       {"size", (PyCFunction) dsaKey_size, METH_VARARGS,
+        "Return the number of bits that this key can handle."},
+       {"has_private", (PyCFunction) dsaKey_has_private, METH_VARARGS,
+        "Return 1 or 0 if this key does/doesn't have a private key."},
+       {NULL, NULL, 0, NULL}
+};
+
+PyObject *fastmathError;                                                       /* raised on errors */
+
+static PyTypeObject rsaKeyType = {
+       PyObject_HEAD_INIT (NULL) 0,
+       "rsaKey",
+       sizeof (rsaKey),
+       0,
+       (destructor) rsaKey_dealloc,    /* dealloc */
+       0,                              /* print */
+       (getattrfunc) rsaKey_getattr,   /* getattr */
+       0,                              /* setattr */
+       0,                              /* compare */
+       0,                              /* repr */
+       0,                              /* as_number */
+       0,                              /* as_sequence */
+       0,                              /* as_mapping */
+       0,                              /* hash */
+       0,                              /* call */
+};
+
+static PyMethodDef rsaKey__methods__[] = {
+       {"_encrypt", (PyCFunction) rsaKey__encrypt, METH_VARARGS,
+        "Encrypt the given long."},
+       {"_decrypt", (PyCFunction) rsaKey__decrypt, METH_VARARGS,
+        "Decrypt the given long."},
+       {"_sign", (PyCFunction) rsaKey__decrypt, METH_VARARGS,
+        "Sign the given long."},
+       {"_verify", (PyCFunction) rsaKey__verify, METH_VARARGS,
+        "Verify that the signature is valid."},
+       {"_blind", (PyCFunction) rsaKey__blind, METH_VARARGS,
+        "Blind the given long."},
+       {"_unblind", (PyCFunction) rsaKey__unblind, METH_VARARGS,
+        "Unblind the given long."},
+       {"size", (PyCFunction) rsaKey_size, METH_VARARGS,
+        "Return the number of bits that this key can handle."},
+       {"has_private", (PyCFunction) rsaKey_has_private, METH_VARARGS,
+        "Return 1 or 0 if this key does/doesn't have a private key."},
+       {NULL, NULL, 0, NULL}
+};
+
+PyObject *
+dsaKey_new (PyObject * self, PyObject * args)
+{
+       PyLongObject *y = NULL, *g = NULL, *p = NULL, *q = NULL, *x = NULL;
+       dsaKey *key;
+       if (!PyArg_ParseTuple(args, "O!O!O!O!|O!", &PyLong_Type, &y,
+                             &PyLong_Type, &g, &PyLong_Type, &p, 
+                             &PyLong_Type, &q, &PyLong_Type, &x))
+               return NULL;
+
+       key = PyObject_New (dsaKey, &dsaKeyType);
+       mpz_init (key->y);
+       mpz_init (key->g);
+       mpz_init (key->p);
+       mpz_init (key->q);
+       mpz_init (key->x);
+       longObjToMPZ (key->y, y);
+       longObjToMPZ (key->g, g);
+       longObjToMPZ (key->p, p);
+       longObjToMPZ (key->q, q);
+       if (x)
+       {
+               longObjToMPZ (key->x, x);
+       }
+       return (PyObject *) key;
+}
+
+static void
+dsaKey_dealloc (dsaKey * key)
+{
+       mpz_clear (key->y);
+       mpz_clear (key->g);
+       mpz_clear (key->p);
+       mpz_clear (key->q);
+       mpz_clear (key->x);
+       PyObject_Del (key);
+}
+
+static PyObject *
+dsaKey_getattr (dsaKey * key, char *attr)
+{
+       if (strcmp (attr, "y") == 0)
+               return mpzToLongObj (key->y);
+       else if (strcmp (attr, "g") == 0)
+               return mpzToLongObj (key->g);
+       else if (strcmp (attr, "p") == 0)
+               return mpzToLongObj (key->p);
+       else if (strcmp (attr, "q") == 0)
+               return mpzToLongObj (key->q);
+       else if (strcmp (attr, "x") == 0)
+       {
+               if (mpz_size (key->x) == 0)
+               {
+                       PyErr_SetString (PyExc_AttributeError,
+                                        "dsaKey instance has no attribute 'x'");
+                       return NULL;
+               }
+               return mpzToLongObj (key->x);
+       }
+       else
+       {
+               return Py_FindMethod (dsaKey__methods__, (PyObject *) key, attr);
+       }
+}
+
+PyObject *
+dsaKey__sign (dsaKey * key, PyObject * args)
+{
+       PyObject *lm, *lk, *lr, *ls;
+       mpz_t m, k, r, s;
+       int result;
+       if (!PyArg_ParseTuple (args, "O!O!", &PyLong_Type, &lm,
+                              &PyLong_Type, &lk))
+       {
+               return NULL;
+       }
+       mpz_init (m);
+       mpz_init (k);
+       mpz_init (r);
+       mpz_init (s);
+       longObjToMPZ (m, (PyLongObject *) lm);
+       longObjToMPZ (k, (PyLongObject *) lk);
+       result = dsaSign (key, m, k, r, s);
+       if (result == 1)
+       {
+               PyErr_SetString (fastmathError, "K not between 2 and q");
+               return NULL;
+       }
+       lr = mpzToLongObj (r);
+       ls = mpzToLongObj (s);
+       mpz_clear (m);
+       mpz_clear (k);
+       mpz_clear (r);
+       mpz_clear (s);
+       return Py_BuildValue ("(NN)", lr, ls);
+}
+
+PyObject *
+dsaKey__verify (dsaKey * key, PyObject * args)
+{
+       PyObject *lm, *lr, *ls;
+       mpz_t m, r, s;
+       int result;
+       if (!PyArg_ParseTuple (args, "O!O!O!", &PyLong_Type, &lm,
+                              &PyLong_Type, &lr, &PyLong_Type, &ls))
+       {
+               return NULL;
+       }
+       mpz_init (m);
+       mpz_init (r);
+       mpz_init (s);
+       longObjToMPZ (m, (PyLongObject *) lm);
+       longObjToMPZ (r, (PyLongObject *) lr);
+       longObjToMPZ (s, (PyLongObject *) ls);
+       result = dsaVerify (key, m, r, s);
+       mpz_clear (m);
+       mpz_clear (r);
+       mpz_clear (s);
+       if (result) {
+               Py_INCREF(Py_True);
+               return Py_True;
+        } else {
+               Py_INCREF(Py_False);
+               return Py_False;
+       }
+}
+
+PyObject *
+dsaKey_size (dsaKey * key, PyObject * args)
+{
+       if (!PyArg_ParseTuple (args, ""))
+               return NULL;
+       return Py_BuildValue ("i", mpz_sizeinbase (key->p, 2) - 1);
+}
+
+PyObject *
+dsaKey_has_private (dsaKey * key, PyObject * args)
+{
+       if (!PyArg_ParseTuple (args, ""))
+               return NULL;
+       if (mpz_size (key->x) == 0) {
+               Py_INCREF(Py_False);
+               return Py_False;
+        } else {
+               Py_INCREF(Py_True);
+               return Py_True;
+        }
+}
+
+PyObject *
+rsaKey_new (PyObject * self, PyObject * args)
+{
+       PyLongObject *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL, 
+                     *u = NULL;
+       rsaKey *key;
+
+       if (!PyArg_ParseTuple(args, "O!O!|O!O!O!O!", &PyLong_Type, &n,
+                             &PyLong_Type, &e, &PyLong_Type, &d, 
+                             &PyLong_Type, &p, &PyLong_Type, &q,
+                              &PyLong_Type, &u))
+               return NULL;
+
+       key = PyObject_New (rsaKey, &rsaKeyType);
+       mpz_init (key->n);
+       mpz_init (key->e);
+       mpz_init (key->d);
+       mpz_init (key->p);
+       mpz_init (key->q);
+       mpz_init (key->u);
+       longObjToMPZ (key->n, n);
+       longObjToMPZ (key->e, e);
+       if (!d)
+       {
+               return (PyObject *) key;
+       }
+       longObjToMPZ (key->d, d);
+       if (p && q)
+       {
+               longObjToMPZ (key->p, p);
+               longObjToMPZ (key->q, q);
+               if (u) {
+                       longObjToMPZ (key->u, u);
+               } else {
+                       mpz_invert (key->u, key->p, key->q);
+               }
+       }
+       return (PyObject *) key;
+}
+
+static void
+rsaKey_dealloc (rsaKey * key)
+{
+       mpz_clear (key->n);
+       mpz_clear (key->e);
+       mpz_clear (key->d);
+       mpz_clear (key->p);
+       mpz_clear (key->q);
+       mpz_clear (key->u);
+       PyObject_Del (key);
+}
+
+static PyObject *
+rsaKey_getattr (rsaKey * key, char *attr)
+{
+       if (strcmp (attr, "n") == 0)
+               return mpzToLongObj (key->n);
+       else if (strcmp (attr, "e") == 0)
+               return mpzToLongObj (key->e);
+       else if (strcmp (attr, "d") == 0)
+       {
+               if (mpz_size (key->d) == 0)
+               {
+                       PyErr_SetString(PyExc_AttributeError,
+                                       "rsaKey instance has no attribute 'd'");
+                       return NULL;
+               }
+               return mpzToLongObj (key->d);
+       }
+       else if (strcmp (attr, "p") == 0)
+       {
+               if (mpz_size (key->p) == 0)
+               {
+                       PyErr_SetString(PyExc_AttributeError,
+                                       "rsaKey instance has no attribute 'p'");
+                       return NULL;
+               }
+               return mpzToLongObj (key->p);
+       }
+       else if (strcmp (attr, "q") == 0)
+       {
+               if (mpz_size (key->q) == 0)
+               {
+                       PyErr_SetString(PyExc_AttributeError,
+                                       "rsaKey instance has no attribute 'q'");
+                       return NULL;
+               }
+               return mpzToLongObj (key->q);
+       }
+       else if (strcmp (attr, "u") == 0)
+       {
+               if (mpz_size (key->u) == 0)
+               {
+                       PyErr_SetString(PyExc_AttributeError,
+                                       "rsaKey instance has no attribute 'u'");
+                       return NULL;
+               }
+               return mpzToLongObj (key->u);
+       }
+       else
+       {
+               return Py_FindMethod (rsaKey__methods__, 
+                                     (PyObject *) key, attr);
+       }
+}
+
+PyObject *
+rsaKey__encrypt (rsaKey * key, PyObject * args)
+{
+       PyObject *l, *r;
+       mpz_t v;
+       int result;
+       if (!PyArg_ParseTuple (args, "O!", &PyLong_Type, &l))
+       {
+               return NULL;
+       }
+       mpz_init (v);
+       longObjToMPZ (v, (PyLongObject *) l);
+       result = rsaEncrypt (key, v);
+       if (result == 1)
+       {
+               PyErr_SetString (fastmathError, "Plaintext too large");
+               return NULL;
+       }
+       r = (PyObject *) mpzToLongObj (v);
+       mpz_clear (v);
+       return Py_BuildValue ("N", r);
+}
+
+PyObject *
+rsaKey__decrypt (rsaKey * key, PyObject * args)
+{
+       PyObject *l, *r;
+       mpz_t v;
+       int result;
+       if (!PyArg_ParseTuple (args, "O!", &PyLong_Type, &l))
+       {
+               return NULL;
+       }
+       mpz_init (v);
+       longObjToMPZ (v, (PyLongObject *) l);
+       result = rsaDecrypt (key, v);
+       if (result == 1)
+       {
+               PyErr_SetString (fastmathError, 
+                                "Ciphertext too large");
+               return NULL;
+       }
+       else if (result == 2)
+       {
+               PyErr_SetString (fastmathError, 
+                                "Private key not available in this object");
+               return NULL;
+       }
+       r = mpzToLongObj (v);
+       mpz_clear (v);
+       return Py_BuildValue ("N", r);
+}
+
+PyObject *
+rsaKey__verify (rsaKey * key, PyObject * args)
+{
+       PyObject *l, *lsig;
+       mpz_t v, vsig;
+       if (!PyArg_ParseTuple(args, "O!O!", 
+                             &PyLong_Type, &l, &PyLong_Type, &lsig))
+       {
+               return NULL;
+       }
+       mpz_init (v);
+       mpz_init (vsig);
+       longObjToMPZ (v, (PyLongObject *) l);
+       longObjToMPZ (vsig, (PyLongObject *) lsig);
+       rsaEncrypt (key, vsig);
+       if (mpz_cmp (v, vsig) == 0) {
+               Py_INCREF(Py_True);
+               return Py_True;
+       }
+       else {
+               Py_INCREF(Py_False);
+               return Py_False;
+        }
+}
+
+PyObject *
+rsaKey__blind (rsaKey * key, PyObject * args)
+{
+       PyObject *l, *lblind, *r;
+       mpz_t v, vblind;
+       int result;
+       if (!PyArg_ParseTuple (args, "O!O!", &PyLong_Type, &l, 
+                               &PyLong_Type, &lblind))
+               {
+                       return NULL;
+               }
+       mpz_init (v);
+       mpz_init (vblind);
+       longObjToMPZ (v, (PyLongObject *) l);
+       longObjToMPZ (vblind, (PyLongObject *) lblind);
+       result = rsaBlind (key, v, vblind);
+       if (result == 1)
+               {
+                       PyErr_SetString (fastmathError, "Message too large");
+                       return NULL;
+               }
+       else if (result == 2)
+               {
+                       PyErr_SetString (fastmathError, "Blinding factor too large");
+                       return NULL;
+               }
+       r = (PyObject *) mpzToLongObj (v);
+       mpz_clear (v);
+       mpz_clear (vblind);
+       return Py_BuildValue ("N", r);
+}
+
+PyObject *
+rsaKey__unblind (rsaKey * key, PyObject * args)
+{
+       PyObject *l, *lblind, *r;
+       mpz_t v, vblind;
+       int result;
+       if (!PyArg_ParseTuple (args, "O!O!", &PyLong_Type, &l, 
+                               &PyLong_Type, &lblind))
+               {
+                       return NULL;
+               }
+       mpz_init (v);
+       mpz_init (vblind);
+       longObjToMPZ (v, (PyLongObject *) l);
+       longObjToMPZ (vblind, (PyLongObject *) lblind);
+       result = rsaUnBlind (key, v, vblind);
+       if (result == 1)
+               {
+                       PyErr_SetString (fastmathError, "Message too large");
+                       return NULL;
+               }
+       else if (result == 2)
+               {
+                       PyErr_SetString (fastmathError, "Blinding factor too large");
+                       return NULL;
+               }
+       else if (result == 3)
+               {
+                       PyErr_SetString (fastmathError, "Inverse doesn't exist");
+                       return NULL;
+               }
+       r = (PyObject *) mpzToLongObj (v);
+       mpz_clear (v);
+       mpz_clear (vblind);
+       return Py_BuildValue ("N", r);
+}
+  
+PyObject *
+rsaKey_size (rsaKey * key, PyObject * args)
+{
+       if (!PyArg_ParseTuple (args, ""))
+               return NULL;
+       return Py_BuildValue ("i", mpz_sizeinbase (key->n, 2) - 1);
+}
+
+PyObject *
+rsaKey_has_private (rsaKey * key, PyObject * args)
+{
+       if (!PyArg_ParseTuple (args, ""))
+               return NULL;
+       if (mpz_size (key->d) == 0) {
+               Py_INCREF(Py_False);
+               return Py_False;
+        } else {
+               Py_INCREF(Py_True);
+               return Py_True;
+       }
+}
+
+
+PyObject *
+isPrime (PyObject * self, PyObject * args)
+{
+       PyObject *l;
+       mpz_t n;
+       int result;
+
+       if (!PyArg_ParseTuple (args, "O!", &PyLong_Type, &l))
+       {
+               return NULL;
+       }
+       mpz_init (n);
+       longObjToMPZ (n, (PyLongObject *) l);
+
+       result = mpz_probab_prime_p(n, 5);
+
+       mpz_clear (n);
+
+       if (result == 0) {
+               Py_INCREF(Py_False);
+               return Py_False;
+        } else {
+               Py_INCREF(Py_True);
+               return Py_True;
+       }
+}
+
+
+static PyMethodDef _fastmath__methods__[] = {
+       {"dsa_construct", dsaKey_new, METH_VARARGS},
+       {"rsa_construct", rsaKey_new, METH_VARARGS},
+        {"isPrime", isPrime, METH_VARARGS},
+       {NULL, NULL}
+};
+
+void
+init_fastmath (void)
+{
+        PyObject *_fastmath_module;
+        PyObject *_fastmath_dict;
+
+       rsaKeyType.ob_type = &PyType_Type;
+       dsaKeyType.ob_type = &PyType_Type;
+       _fastmath_module = Py_InitModule ("_fastmath", _fastmath__methods__);
+       _fastmath_dict = PyModule_GetDict (_fastmath_module);
+       fastmathError = PyErr_NewException ("_fastmath.error", NULL, NULL);
+       PyDict_SetItemString (_fastmath_dict, "error", fastmathError);
+}