Speed
Where math operations are concerned phpseclib will use whatever extensions are availale to speed up operations. The impact of these extensions on various versions of PHP is shown below.
Note that the following benchmarks were performed with phpseclib v1. phpseclib v3's performance should be comparable. The reason phpseclib v1 was employed is to show how PHP has sped up over the years.
The benchmarks were performed on GitHub Actions using Docker containers from phpseclib/docker-php.
Benchmarks
| PHP32 | PHP64 | BCMath | PHP32 | PHP64 | BCMath | GMP | |
| w/o OpenSSL | w/ OpenSSL | ||||||
| PHP 4.4 | 7.033 | 4.606 | 2.310 | 0.710 | 0.587 | 0.062 | 0.002 |
| PHP 5.0 | 7.396 | 4.825 | 2.265 | 0.749 | 0.617 | 0.061 | 0.002 |
| PHP 5.1 | 3.278 | 2.024 | 2.257 | 0.403 | 0.352 | 0.060 | 0.002 |
| PHP 5.2 | 3.666 | 2.092 | 2.244 | 0.368 | 0.316 | 0.058 | 0.002 |
| PHP 5.3 | 3.288 | 1.939 | 2.276 | 0.356 | 0.297 | 0.058 | 0.002 |
| PHP 5.4 | 2.067 | 1.242 | 2.288 | 0.254 | 0.209 | 0.059 | 0.002 |
| PHP 5.5 | 2.060 | 1.200 | 2.314 | 0.249 | 0.205 | 0.058 | 0.002 |
| PHP 5.6 | 1.989 | 1.192 | 2.311 | 0.243 | 0.206 | 0.057 | 0.002 |
| PHP 7.0 | 0.908 | 0.548 | 2.282 | 0.089 | 0.073 | 0.055 | 0.001 |
| PHP 7.1 | 0.773 | 0.500 | 2.305 | 0.082 | 0.072 | 0.056 | 0.001 |
| PHP 7.2 | 0.701 | 0.460 | 2.314 | 0.064 | 0.055 | 0.055 | 0.001 |
| PHP 7.3 | 0.683 | 0.445 | 2.305 | 0.063 | 0.054 | 0.053 | 0.001 |
| PHP 7.4 | 0.614 | 0.403 | 2.349 | 0.059 | 0.050 | 0.055 | 0.002 |
| PHP 8.0 | 0.642 | 0.415 | 2.251 | 0.060 | 0.052 | 0.053 | 0.001 |
| PHP 8.1 | 0.642 | 0.416 | 2.234 | 0.060 | 0.051 | 0.053 | 0.003 |
| PHP 8.2 | 0.619 | 0.407 | 2.235 | 0.060 | 0.051 | 0.054 | 0.002 |
| PHP 8.3 | 0.646 | 0.417 | 2.205 | 0.061 | 0.052 | 0.052 | 0.002 |
| PHP 8.4 | 0.634 | 0.417 | 0.056 | 0.061 | 0.053 | 0.010 | 0.002 |
Benchmarks with JIT
PHP 8 introduced a new Just-In-Time (JIT) compilation engine. The specific JIT settings that were used can be seen in the Docker containers opcache.ini.
| PHP32 | PHP64 | BCMath | PHP32 | PHP64 | BCMath | GMP | |
| w/o OpenSSL | w/ OpenSSL | ||||||
| PHP 8.0 | 0.204 | 0.103 | 2.255 | 0.032 | 0.029 | 0.053 | 0.002 |
| PHP 8.1 | 0.190 | 0.087 | 2.234 | 0.033 | 0.029 | 0.055 | 0.002 |
| PHP 8.2 | 0.188 | 0.089 | 2.238 | 0.033 | 0.042 | 0.054 | 0.002 |
| PHP 8.3 | 0.189 | 0.087 | 2.207 | 0.033 | 0.029 | 0.052 | 0.002 |
| PHP 8.4 | 0.179 | 0.087 | 0.058 | 0.036 | 0.032 | 0.012 | 0.002 |
GMP Engine
GMP, to quote wikipedia, "aims to be faster than any other bignum library", using "highly optimized assembly language code".
BCMath
BCMath was significantly sped up in PHP 8.4. BCMath Performance Improvement Explanation (in Japanese) explains how this was done.
PHP32 / PHP64
These days, most systems are 64-bit, however, a notable exception are Raspberry Pi's.
On 32-bit systems phpseclib uses base-2**26 to reduce the number of digits of each number. When two 26-bit numbers are multiplied together the result is a 64-bit floating point (of which only 48 bits are used), which is then converted back to two 32-bit signed integers (of which only 26 bits are used).
On 64-bit systems phpseclib uses base-2**31 to reduce the number of digits of each number. When two 31-bit numbers are multiplied together the result is a 64-bit signed integer (of which only 62 bits are used), which is then converted back to two 32-bit signed integers (of which only 31 bits are used).
OpenSSL Enhancements
Only used for powMod(). Converts the exponent and the modulo to an appropriately formatted RSA public key and performs unpadded RSA encryption with that.
Security Tradeoffs
phpseclib prioritizes portability and practical performance over universal constant-time guarantees. The real-world severity of timing attacks depends heavily on threat model. If secret operations are not performed on attacker-controlled input (eg. when an administrator uploads a private key for outbound SSH use) there is no meaningful timing oracle. Conversely, if untrusted users can repeatedly submit ciphertext that is decrypted with a long-lived server key, constant-time behavior becomes materially important. Security decisions should be driven by deployment context, not theoretical worst cases in isolation.
Because phpseclib is designed to run anywhere PHP runs, including environments without OpenSSL, it must sometimes rely on pure-PHP arithmetic or extensions like GMP, neither of which guarantees constant-time behavior. A fully constant-time BigInteger implementation in PHP would require fixed-width arithmetic, elimination of data-dependent branches, and uniform memory access patterns, resulting in severe performance penalties. For very large keys (eg. a 16K RSA key), such an approach would likely be impractically slow. Similarly, constant-time AES without hardware acceleration is dramatically slower than table-based implementations, and PHP cannot access AES-NI instructions directly.
Where constant-time protections are inexpensive and practical - such as fixed-time string comparison, blinding during modular exponentiation, or careful padding checks - phpseclib applies them. However, imposing a 5x slowdown across all cryptographic operations in pursuit of absolute constant-time purity would render the library unusable in many of the constrained environments it targets. In practice, a widely deployable library with context-aware risk trade-offs is often more valuable than one that is theoretically ideal but operationally impractical.
See Public Keys - Overview § Best Practices for a more in depth discussion.