Paul Sheer optimised the OpenSSL to/from libGMP conversions for the case
authorGeoff Thorpe <geoff@openssl.org>
Sun, 27 Apr 2008 18:41:23 +0000 (18:41 +0000)
committerGeoff Thorpe <geoff@openssl.org>
Sun, 27 Apr 2008 18:41:23 +0000 (18:41 +0000)
where they both use the same limb size. I've tweaked his patch slightly, so
blame me if it breaks.

Submitted by: Paul Sheer
Reviewed by: Geoff Thorpe

CHANGES
engines/e_gmp.c

diff --git a/CHANGES b/CHANGES
index 1aa60fa..66adadf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 
  Changes between 0.9.8g and 0.9.8h  [xx XXX xxxx]
 
+  *) Update the GMP engine glue to do direct copies between BIGNUM and
+     mpz_t when openssl and GMP use the same limb size. Otherwise the
+     existing "conversion via a text string export" trick is still used.
+     [Paul Sheer <paulsheer@gmail.com>, Geoff Thorpe]
+
   *) Zlib compression BIO. This is a filter BIO which compressed and
      uncompresses any data passed through it.
      [Steve Henson]
index 3b1f4b9..97bc214 100644 (file)
@@ -85,6 +85,8 @@
 #include <openssl/crypto.h>
 #include <openssl/buffer.h>
 #include <openssl/engine.h>
+#include <openssl/rsa.h>
+#include <openssl/bn.h>
 
 #ifndef OPENSSL_NO_HW
 #ifndef OPENSSL_NO_GMP
@@ -251,27 +253,61 @@ static int e_gmp_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
        return to_return;
        }
 
-/* HACK - use text I/O functions in openssl and GMP to handle conversions. This
- * is vile. */
+
+/* Most often limb sizes will be the same. If not, we use hex conversion
+ * which is neat, but extremely inefficient. */
 static int bn2gmp(const BIGNUM *bn, mpz_t g)
        {
-       int toret;
-       char *tmpchar = BN_bn2hex(bn);
-       if(!tmpchar) return 0;
-       toret = (mpz_set_str(g, tmpchar, 16) == 0 ? 1 : 0);
-       OPENSSL_free(tmpchar);
-       return toret;
+       bn_check_top(bn);
+       if(((sizeof(bn->d[0]) * 8) == GMP_NUMB_BITS) &&
+                       (BN_BITS2 == GMP_NUMB_BITS)) 
+               {
+               /* The common case */
+               if(!_mpz_realloc (g, bn->top))
+                       return 0;
+               memcpy(&g->_mp_d[0], &bn->d[0], bn->top * sizeof(bn->d[0]));
+               g->_mp_size = bn->top;
+               if(bn->neg)
+                       g->_mp_size = -g->_mp_size;
+               return 1;
+               }
+       else
+               {
+               int toret;
+               char *tmpchar = BN_bn2hex(bn);
+               if(!tmpchar) return 0;
+               toret = (mpz_set_str(g, tmpchar, 16) == 0 ? 1 : 0);
+               OPENSSL_free(tmpchar);
+               return toret;
+               }
        }
 
 static int gmp2bn(mpz_t g, BIGNUM *bn)
        {
-       int toret;
-       char *tmpchar = OPENSSL_malloc(mpz_sizeinbase(g, 16) + 10);
-       if(!tmpchar) return 0;
-       mpz_get_str(tmpchar, 16, g);
-       toret = BN_hex2bn(&bn, tmpchar);
-       OPENSSL_free(tmpchar);
-       return toret;
+       if(((sizeof(bn->d[0]) * 8) == GMP_NUMB_BITS) &&
+                       (BN_BITS2 == GMP_NUMB_BITS))
+               {
+               /* The common case */
+               int s = (g->_mp_size >= 0) ? g->_mp_size : -g->_mp_size;
+               BN_zero(bn);
+               if(bn_expand2 (bn, s) == NULL)
+                       return 0;
+               bn->top = s;
+               memcpy(&bn->d[0], &g->_mp_d[0], s * sizeof(bn->d[0]));
+               bn_correct_top(bn);
+               bn->neg = g->_mp_size >= 0 ? 0 : 1;
+               return 1;
+               }
+       else
+               {
+               int toret;
+               char *tmpchar = OPENSSL_malloc(mpz_sizeinbase(g, 16) + 10);
+               if(!tmpchar) return 0;
+               mpz_get_str(tmpchar, 16, g);
+               toret = BN_hex2bn(&bn, tmpchar);
+               OPENSSL_free(tmpchar);
+               return toret;
+               }
        }
 
 #ifndef OPENSSL_NO_RSA