Ошибка в алгоритме проверки подписи в серверных скриптах на PHP

Ошибка в алгоритме проверки подписи в серверных скриптах примера на PHP
https://download.rutoken.ru/Rutoken_Web … TW_PHP.zip

Немного теории:
Пусть P = (x,y), тогда обратной к точек P является точка -P = (x, -y). Сумма P + (-P) = бесконченость.
Сумма точек P = (x1,y1) и Q = (x2,y2), где P != -Q, вычисляется по формулам:
x3 = L^2 - x1 - x2
y3 = L * (x1 - x3) - y1
L = (y2 - y1) / (x2 - x1), если P != Q
L = (3 * x1^2 + a) / (2 * y1), если P == Q

Переходим к коду
файл crypto\classes\Point.php
функция add

Разберём следующий код:
if (gmp_Utils::gmp_mod2(gmp_cmp($p1->x, $p2->x), $p1->curve->getPrime()) == 0) {
    if (gmp_Utils::gmp_mod2(gmp_add($p1->y, $p2->y), $p1->curve->getPrime()) == 0) {
        return self::$infinity;
    } else {
        return self::double($p1);
    }
}

1.
Первая строка
if (gmp_Utils::gmp_mod2(gmp_cmp($p1->x, $p2->x), $p1->curve->getPrime()) == 0) {

1.1
Нам нужно проверить, что x1 == x2
gmp_cmp вернет 0, если x1 == x2. Положительное число, если x1 > x2, и отрицательное, если x1 < x2.
Результат сравнения (знаковое целое) передаётся в функцию gmp_Utils::gmp_mod2, там происходит деление.

Хотя этот код работает, но корректее будет использовать gmp_sub

1.2
Функция gmp_Utils::gmp_mod2 вернет строку с числом и далее она сравнивается с целочисленным нулем.
Да, в PHP делается приведение типов, но корректнее будет использовать gmp_cmp для сравнения.

2.
Следующая строка
if (gmp_Utils::gmp_mod2(gmp_add($p1->y, $p2->y), $p1->curve->getPrime()) == 0) {
Аналогично, для сравнения нужно использовать gmp_cmp

3.
Собственно, главная ошибка.
В коде проверется случай что y1 == -y2.
Но не проверяется случай y1 == y2 (то есть случай, когда P = Q)
Нужно добавить проверку

else if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_sub($p1->y, $p2->y), $p1->curve->getPrime()), '0') === 0)

Таким образом, код должен выглядеть так:
if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_sub($p1->x, $p2->x), $p1->curve->getPrime()), '0') === 0)
{
    if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_add($p1->y, $p2->y), $p1->curve->getPrime()), '0') === 0)
    {
        return self::$infinity;
    }
    else if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_sub($p1->y, $p2->y), $p1->curve->getPrime()), '0') === 0)
    {
        return self::double($p1);
    }
}

Re: Ошибка в алгоритме проверки подписи в серверных скриптах на PHP

Добрый день!
Спасибо Вам огромное за проведённый аудит.
Специально для таких случаев мы выложили исходные коды этого проекта на гитхаб
https://github.com/AktivCo/rutokenweb_php
Если вы сделаете указанные вами изменения на гитхабе мы их примем и сделаем проект лучше.