diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc
index 48af7666918da84d02ba88e42bc91ae64f267a67..e820cd60f077cda0248bc5405c491d7f4a5fbe39 100644
--- a/modules/openid/openid.inc
+++ b/modules/openid/openid.inc
@@ -448,15 +448,15 @@ function _openid_dh_binary_to_long($str) {
 
   $n = 0;
   foreach ($bytes as $byte) {
-    $n = bcmul($n, pow(2, 8));
-    $n = bcadd($n, $byte);
+    $n = _openid_math_mul($n, pow(2, 8));
+    $n = _openid_math_add($n, $byte);
   }
 
   return $n;
 }
 
 function _openid_dh_long_to_binary($long) {
-  $cmp = bccomp($long, 0);
+  $cmp = _openid_math_cmp($long, 0);
   if ($cmp < 0) {
     return FALSE;
   }
@@ -467,9 +467,9 @@ function _openid_dh_long_to_binary($long) {
 
   $bytes = array();
 
-  while (bccomp($long, 0) > 0) {
-    array_unshift($bytes, bcmod($long, 256));
-    $long = bcdiv($long, pow(2, 8));
+  while (_openid_math_cmp($long, 0) > 0) {
+    array_unshift($bytes, _openid_math_mod($long, 256));
+    $long = _openid_math_div($long, pow(2, 8));
   }
 
   if ($bytes && ($bytes[0] > 127)) {
@@ -512,11 +512,11 @@ function _openid_dh_rand($stop) {
       $nbytes = strlen($rbytes);
     }
 
-    $mxrand = bcpow(256, $nbytes);
+    $mxrand = _openid_math_pow(256, $nbytes);
 
     // If we get a number less than this, then it is in the
     // duplicated range.
-    $duplicate = bcmod($mxrand, $stop);
+    $duplicate = _openid_math_mod($mxrand, $stop);
 
     if (count($duplicate_cache) > 10) {
       $duplicate_cache = array();
@@ -529,9 +529,9 @@ function _openid_dh_rand($stop) {
     $bytes = "\x00" . _openid_get_bytes($nbytes);
     $n = _openid_dh_binary_to_long($bytes);
     // Keep looping if this value is in the low duplicated range.
-  } while (bccomp($n, $duplicate) < 0);
+  } while (_openid_math_cmp($n, $duplicate) < 0);
 
-  return bcmod($n, $stop);
+  return _openid_math_mod($n, $stop);
 }
 
 function _openid_get_bytes($num_bytes) {
@@ -683,3 +683,111 @@ function openid_extract_ax_values($values, $uris) {
   return $output;
 }
 
+/**
+ * Determine the available math library GMP vs. BCMath, favouring GMP for performance.
+ */
+function _openid_get_math_library() {
+  $library = &drupal_static(__FUNCTION__);
+
+  if (empty($library)) {
+    if (function_exists('gmp_add')) {
+      $library =  'gmp';
+    }
+    elseif (function_exists('bcadd')) {
+      $library = 'bcmath';
+    }
+  }
+
+  return $library;
+}
+
+/**
+ * Calls the add function from the available math library for OpenID.
+ */
+function _openid_math_add($x, $y) {
+  $library = _openid_get_math_library();
+  switch ($library) {
+    case 'gmp':
+      return gmp_strval(gmp_add($x, $y));
+    case 'bcmath':
+      return bcadd($x, $y);
+  }
+}
+
+/**
+ * Calls the mul function from the available math library for OpenID.
+ */
+function _openid_math_mul($x, $y) {
+  $library = _openid_get_math_library();
+  switch ($library) {
+    case 'gmp':
+      return gmp_mul($x, $y);
+    case 'bcmath':
+      return bcmul($x, $y);
+  }
+}
+
+/**
+ * Calls the div function from the available math library for OpenID.
+ */
+function _openid_math_div($x, $y) {
+  $library = _openid_get_math_library();
+  switch ($library) {
+    case 'gmp':
+      return gmp_div($x, $y);
+    case 'bcmath':
+      return bcdiv($x, $y);
+  }
+}
+
+/**
+ * Calls the cmp function from the available math library for OpenID.
+ */
+function _openid_math_cmp($x, $y) {
+  $library = _openid_get_math_library();
+  switch ($library) {
+    case 'gmp':
+      return gmp_cmp($x, $y);
+    case 'bcmath':
+      return bccomp($x, $y);
+  }
+}
+
+/**
+ * Calls the mod function from the available math library for OpenID.
+ */
+function _openid_math_mod($x, $y) {
+  $library = _openid_get_math_library();
+  switch ($library) {
+    case 'gmp':
+      return gmp_mod($x, $y);
+    case 'bcmath':
+      return bcmod($x, $y);
+  }
+}
+
+/**
+ * Calls the pow function from the available math library for OpenID.
+ */
+function _openid_math_pow($x, $y) {
+  $library = _openid_get_math_library();
+  switch ($library) {
+    case 'gmp':
+      return gmp_pow($x, $y);
+    case 'bcmath':
+      return bcpow($x, $y);
+  }
+}
+
+/**
+ * Calls the mul function from the available math library for OpenID.
+ */
+function _openid_math_powmod($x, $y, $z) {
+  $library = _openid_get_math_library();
+  switch ($library) {
+    case 'gmp':
+      return gmp_powm($x, $y, $z);
+    case 'bcmath':
+      return bcpowmod($x, $y, $z);
+  }
+}
diff --git a/modules/openid/openid.install b/modules/openid/openid.install
index 5a90568de1f400d1d8b4b48b2e47169a224de1c9..2859e26198ba783b3f8d63858782a8722cde5252 100644
--- a/modules/openid/openid.install
+++ b/modules/openid/openid.install
@@ -92,20 +92,27 @@ function openid_requirements($phase) {
 
   if ($phase == 'runtime') {
     // Check for the PHP BC Math library.
-    if (!function_exists('bcadd')) {
-      $requirements['bcmath'] = array(
+    if (!function_exists('bcadd') && !function_exists('gmp_add')) {
+      $requirements['openid_math'] = array(
         'value' => t('Not installed'),
         'severity' => REQUIREMENT_ERROR,
-        'description' => t('OpenID requires the BC Math library for PHP which is missing or outdated. Check the <a href="@url">PHP BC Math Library documentation</a> for information on how to correct this.', array('@url' => 'http://www.php.net/manual/en/book.bc.php')),
+        'description' => t('OpenID suggest the use of either the the <a href="@gmp">GMP Math</a> (recommended for performance) or <a href="@bc">BC Math</a> libraries to enable OpenID associations.', array('@gmp' => 'http://php.net/manual/en/book.gmp.php', '@bc' => 'http://www.php.net/manual/en/book.bc.php')),
+      );
+    }
+    elseif (!function_exists('gmp_add')) {
+      $requirements['openid_math'] = array(
+        'value' => t('Not optimized'),
+        'severity' => REQUIREMENT_WARNING,
+        'description' => t('OpenID suggests the use of the GMP Math library for PHP for optimal performance. Check the <a href="@url">GMP Math Library documentation</a> for installation instructions.', array('@url' => 'http://www.php.net/manual/en/book.gmp.php')),
       );
     }
     else {
-      $requirements['bcmath'] = array(
+      $requirements['openid_math'] = array(
         'value' => t('Installed'),
         'severity' => REQUIREMENT_OK,
       );
     }
-    $requirements['bcmath']['title'] = t('BC Math library');
+    $requirements['openid_math']['title'] = t('OpenID Math library');
   }
 
   return $requirements;
diff --git a/modules/openid/openid.module b/modules/openid/openid.module
index 0ab7c7065a6fc5ef27828f26829de75c582dc65d..c385490b75e7074a097088023f453e0a010b5da5 100644
--- a/modules/openid/openid.module
+++ b/modules/openid/openid.module
@@ -275,9 +275,9 @@ function openid_begin($claimed_id, $return_to = '', $form_values = array()) {
   // user_exteral_login later.
   $_SESSION['openid']['user_login_values'] = $form_values;
 
-  // If bcmath is present, then create an association
+  // If a supported math library is present, then create an association.
   $assoc_handle = '';
-  if (function_exists('bcadd')) {
+  if (_openid_get_math_library()) {
     $assoc_handle = openid_association($service['uri']);
   }
 
@@ -540,8 +540,8 @@ function openid_association($op_endpoint) {
     $mod = OPENID_DH_DEFAULT_MOD;
     $gen = OPENID_DH_DEFAULT_GEN;
     $r = _openid_dh_rand($mod);
-    $private = bcadd($r, 1);
-    $public = bcpowmod($gen, $private, $mod);
+    $private = _openid_math_add($r, 1);
+    $public = _openid_math_powmod($gen, $private, $mod);
 
     // If there is no existing association, then request one
     $assoc_request = openid_association_request($public);
@@ -564,7 +564,7 @@ function openid_association($op_endpoint) {
     if ($assoc_response['session_type'] == 'DH-SHA1') {
       $spub = _openid_dh_base64_to_long($assoc_response['dh_server_public']);
       $enc_mac_key = base64_decode($assoc_response['enc_mac_key']);
-      $shared = bcpowmod($spub, $private, $mod);
+      $shared = _openid_math_powmod($spub, $private, $mod);
       $assoc_response['mac_key'] = base64_encode(_openid_dh_xorsecret($shared, $enc_mac_key));
     }
     db_insert('openid_association')
diff --git a/modules/openid/tests/openid_test.module b/modules/openid/tests/openid_test.module
index 5beb5fa411e486be4324f777ebe32d27a1359936..3251b1d8f9efa8033ec8674e1f08d827519bccb0 100644
--- a/modules/openid/tests/openid_test.module
+++ b/modules/openid/tests/openid_test.module
@@ -228,14 +228,14 @@ function _openid_test_endpoint_associate() {
 
   // Generate private Diffie-Helmann key.
   $r = _openid_dh_rand($mod);
-  $private = bcadd($r, 1);
+  $private = _openid_math_add($r, 1);
 
   // Calculate public Diffie-Helmann key.
-  $public = bcpowmod($gen, $private, $mod);
+  $public = _openid_math_powmod($gen, $private, $mod);
 
   // Calculate shared secret based on Relying Party's public key.
   $cpub = _openid_dh_base64_to_long($_REQUEST['openid_dh_consumer_public']);
-  $shared = bcpowmod($cpub, $private, $mod);
+  $shared = _openid_math_powmod($cpub, $private, $mod);
 
   // Encrypt the MAC key using the shared secret.
   $enc_mac_key = base64_encode(_openid_dh_xorsecret($shared, base64_decode(variable_get('mac_key'))));