Skip to content

Commit c937011

Browse files
committed
ext/gmp: Add gmp_powm_sec()
1 parent 7abd493 commit c937011

9 files changed

Lines changed: 109 additions & 2 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ PHP NEWS
1717
declares a default value for the attribute). (iliaal)
1818

1919
- GMP:
20+
. Added gmp_powm_sec(). (Weilin Du)
2021
. Added gmp_prevprime(). (Weilin Du, David Carlier)
2122
. Fixed GMP power and shift operators to reject GMP right operands outside
2223
the unsigned long range instead of silently truncating them. (Weilin Du)

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ PHP 8.6 UPGRADE NOTES
272272
. finfo_file() now works with remote streams.
273273

274274
- GMP:
275+
. Added gmp_powm_sec() for side-channel quiet modular exponentiation.
276+
Requires GNU MP 5.0.0 or later.
275277
. Added gmp_prevprime() to get the largest prime smaller than the given
276278
number. A ValueError is thrown if no such prime exists. This function is
277279
available only when PHP is built against GNU MP 6.3.0 or later; it is not
@@ -428,6 +430,7 @@ PHP 8.6 UPGRADE NOTES
428430
========================================
429431

430432
- GMP:
433+
. gmp_powm_sec()
431434
. gmp_prevprime()
432435

433436
- Intl:

ext/gmp/config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ if test "$PHP_GMP" != "no"; then
2222
LIBS="$LIBS $GMP_LIBS"
2323
gmp_check=no
2424
AC_CHECK_HEADER([gmp.h], [AC_CHECK_FUNC([__gmpz_rootrem], [gmp_check=yes])])
25-
AC_CHECK_FUNCS([__gmpz_prevprime])
25+
AC_CHECK_FUNCS([__gmpz_powm_sec __gmpz_prevprime])
2626
CFLAGS=$CFLAGS_SAVED
2727
LIBS=$LIBS_SAVED
2828

ext/gmp/config.w32

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ARG_WITH("gmp", "Include GNU MP support.", "no");
55
if (PHP_GMP != "no") {
66
if (CHECK_LIB("mpir_a.lib", "gmp", PHP_GMP) &&
77
CHECK_HEADER("gmp.h", "CFLAGS_GMP", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) {
8+
if (GREP_HEADER("gmp.h", "mpz_powm_sec", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) {
9+
AC_DEFINE('HAVE___GMPZ_POWM_SEC', 1, "Define to 1 if GMP has the 'mpz_powm_sec' function.");
10+
}
811
if (GREP_HEADER("gmp.h", "mpz_prevprime", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) {
912
AC_DEFINE('HAVE___GMPZ_PREVPRIME', 1, "Define to 1 if GMP has the 'mpz_prevprime' function.");
1013
}

ext/gmp/gmp.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,39 @@ ZEND_FUNCTION(gmp_powm)
12171217
}
12181218
/* }}} */
12191219

1220+
#ifdef HAVE___GMPZ_POWM_SEC
1221+
/* {{{ Raise base to power exp and take result modulo mod using a side-channel quiet algorithm */
1222+
ZEND_FUNCTION(gmp_powm_sec)
1223+
{
1224+
mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result;
1225+
1226+
ZEND_PARSE_PARAMETERS_START(3, 3)
1227+
GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_base)
1228+
GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_exp)
1229+
GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_mod)
1230+
ZEND_PARSE_PARAMETERS_END();
1231+
1232+
if (mpz_sgn(gmpnum_exp) <= 0) {
1233+
zend_argument_value_error(2, "must be greater than 0");
1234+
RETURN_THROWS();
1235+
}
1236+
1237+
if (UNEXPECTED(!mpz_odd_p(gmpnum_mod))) {
1238+
/* Zero is an even modulus, but report it like gmp_powm() does. */
1239+
if (UNEXPECTED(!mpz_cmp_ui(gmpnum_mod, 0))) {
1240+
zend_argument_error(zend_ce_division_by_zero_error, 3, "Modulo by zero");
1241+
} else {
1242+
zend_argument_value_error(3, "must be odd");
1243+
}
1244+
RETURN_THROWS();
1245+
}
1246+
1247+
INIT_GMP_RETVAL(gmpnum_result);
1248+
mpz_powm_sec(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod);
1249+
}
1250+
/* }}} */
1251+
#endif
1252+
12201253
/* {{{ Takes integer part of square root of a */
12211254
ZEND_FUNCTION(gmp_sqrt)
12221255
{

ext/gmp/gmp.stub.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ function gmp_pow(GMP|int|string $num, int $exponent): GMP {}
125125

126126
function gmp_powm(GMP|int|string $num, GMP|int|string $exponent, GMP|int|string $modulus): GMP {}
127127

128+
#ifdef HAVE___GMPZ_POWM_SEC
129+
function gmp_powm_sec(GMP|int|string $num, GMP|int|string $exponent, GMP|int|string $modulus): GMP {}
130+
#endif
131+
128132
function gmp_perfect_square(GMP|int|string $num): bool {}
129133

130134
function gmp_perfect_power(GMP|int|string $num): bool {}

ext/gmp/gmp_arginfo.h

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/gmp/tests/bug80560.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ $functions2 = [
6363
$functions3 = [
6464
'gmp_powm',
6565
];
66+
if (function_exists('gmp_powm_sec')) {
67+
$functions3[] = 'gmp_powm_sec';
68+
}
6669

6770
echo 'Explicit base with gmp_init:', \PHP_EOL;
6871
echo 'Hexadecimal', \PHP_EOL;

ext/gmp/tests/gmp_powm_sec.phpt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
gmp_powm_sec()
3+
--EXTENSIONS--
4+
gmp
5+
--SKIPIF--
6+
<?php
7+
if (!function_exists('gmp_powm_sec')) {
8+
die('skip gmp_powm_sec() is not available');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
var_dump(gmp_strval(gmp_powm_sec(4, 13, 497)));
15+
var_dump(gmp_strval(gmp_powm_sec(gmp_init(7), gmp_init(3), gmp_init(13))));
16+
17+
foreach ([0, -1] as $exp) {
18+
try {
19+
var_dump(gmp_powm_sec(4, $exp, 497));
20+
} catch (\ValueError $e) {
21+
echo $e::class, ": ", $e->getMessage(), \PHP_EOL;
22+
}
23+
}
24+
25+
try {
26+
var_dump(gmp_powm_sec(4, 13, 0));
27+
} catch (\DivisionByZeroError $e) {
28+
echo $e::class, ": ", $e->getMessage(), \PHP_EOL;
29+
}
30+
31+
try {
32+
var_dump(gmp_powm_sec(4, 13, 496));
33+
} catch (\ValueError $e) {
34+
echo $e::class, ": ", $e->getMessage(), \PHP_EOL;
35+
}
36+
37+
echo "Done\n";
38+
?>
39+
--EXPECT--
40+
string(3) "445"
41+
string(1) "5"
42+
ValueError: gmp_powm_sec(): Argument #2 ($exponent) must be greater than 0
43+
ValueError: gmp_powm_sec(): Argument #2 ($exponent) must be greater than 0
44+
DivisionByZeroError: gmp_powm_sec(): Argument #3 ($modulus) Modulo by zero
45+
ValueError: gmp_powm_sec(): Argument #3 ($modulus) must be odd
46+
Done

0 commit comments

Comments
 (0)