diff --git a/openid.inc b/openid.inc
index 9223a4d..6412d3b 100644
--- a/openid.inc
+++ b/openid.inc
@@ -284,15 +284,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_comp($long, 0);
   if ($cmp < 0) {
     return FALSE;
   }
@@ -303,9 +303,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_comp($long, 0) > 0) {
+    array_unshift($bytes, _openid_math_mod($long, 256));
+    $long = _openid_math_div($long, pow(2, 8));
   }
 
   if ($bytes && ($bytes[0] > 127)) {
@@ -348,11 +348,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();
@@ -365,9 +365,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_comp($n, $duplicate) < 0);
 
-  return bcmod($n, $stop);
+  return _openid_math_mod($n, $stop);
 }
 
 function _openid_get_bytes($num_bytes) {
@@ -443,3 +443,87 @@ if (!function_exists('bcpowmod')) {
     return $result;
   }
 }
+
+function _openid_get_math_library() {
+  static $library;
+
+  if (empty($library)) {
+    if (function_exists('gmp_add')) {
+      $library = 'gmp';
+    } else if (function_exists('bcadd')) {
+      $library = 'bcmath';
+    } 
+  }
+
+  return $library;
+}
+
+function _openid_math_add($x, $y) {
+  $library = _openid_get_math_library();
+  switch($library) {
+    case 'gmp':
+      return gmp_add($x, $y);
+    case 'bcmath':
+      return bcadd($x, $y);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+function _openid_math_comp($x, $y) {
+  $library = _openid_get_math_library();
+  switch($library) {
+    case 'gmp':
+      return gmp_cmp($x, $y);
+    case 'bcmath':
+      return bccomp($x, $y);
+  }
+}
+
+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);
+  }
+}
+
+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);
+  }
+}
+
+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/openid.install b/openid.install
index 8c4ac89..ee70fce 100644
--- a/openid.install
+++ b/openid.install
@@ -96,6 +96,39 @@ function openid_schema() {
 }
 
 /**
+ * Implements hook_requirements().
+ */
+function openid_requirements($phase) {
+  $requirements = array();
+
+  if ($phase == 'runtime') {
+    // Check for the PHP BC Math library.
+    if (!function_exists('bcadd')) {
+      $requirements['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')),
+      );
+    } elseif (!function_exists('gmp_add')) {
+      $requirements['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['math'] = array(
+        'value' => t('Installed'),
+        'severity' => REQUIREMENT_OK,
+      );
+    }
+    $requirements['math']['title'] = t('OpenID Math library');
+  }
+
+  return $requirements;
+}
+
+/**
  * @defgroup updates-6.x-extra Extra openid updates for 6.x
  * @{
  */
diff --git a/openid.module b/openid.module
index 2db36e1..11219bd 100644
--- a/openid.module
+++ b/openid.module
@@ -179,7 +179,7 @@ function openid_begin($claimed_id, $return_to = '', $form_values = array()) {
   $op_endpoint = $services[0]['uri'];
   // If bcmath is present, then create an association
   $assoc_handle = '';
-  if (function_exists('bcadd')) {
+  if (_openid_get_math_library()) {
     $assoc_handle = openid_association($op_endpoint);
   }
 
@@ -372,8 +372,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);
@@ -392,7 +392,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_query("INSERT INTO {openid_association} (idp_endpoint_uri, session_type, assoc_handle, assoc_type, expires_in, mac_key, created) VALUES('%s', '%s', '%s', '%s', %d, '%s', %d)",
