Автор неизвестен. Перевод Кантор И. e-mail: algolist@mail.ru web: iliakan@gmail.com
Стадия 1
Определение
Пусть B - положительное целое число. Некоторое положительное целое N называется B-гладким, если все простые делители N меньше, либо равны B. N будет называться гладким степени B, если все степени простых чисел, делящие N меньше, либо равны B.
Эти слова о гладкости весьма естественны в методах факторизации и, как мы увидим, будут весьма необходимы в самых современных из них.
Пусть p - заранее не известный простой делитель N, которое мы хотим разложить. Пусть a > 1 - целое число (которое мы полагаем взаимно простым с N, проверяя это вычислением НОД. Если НОД ( a , N ) > 1, то N уже разложено). По теореме Ферма ap-1 сравнимо с 1 (mod p). Теперь предположим, что p-1 - гладкое степени B, где B не слишком велико. Тогда по определению p-1 делит НОК чисел от 1 до B. Следовательно, aНОК(1..B)*k сравнимо с 1 (mod p), следовательно aНОК(1..B) сравнимо с 1 (mod p). А значит
НОД ( aНОК(1..B)-1 , N ) > 1.
Если мы проверяем это для увеличивающихся значений B, то весьма маловероятно, что НОД будет равен N. Также можно использовать некоторые трюки, например не вычислять НОД каждый раз заново, а хранить результаты по модулю N и вычислять НОД только время от времени. Это приводит нас к алгоритму Полларда:
Первая стадия алгоритма p-1
Пусть N - составное число, и В - заранее выбранная верхняя грань. Этот алгоритм будет пытаться найти нетривиальный делитель N, но это получится только если существует простой делитель N, такой что p-1 - гладкое степени B. Мы предполагаем, что уже есть таблица p[1], ..., p[k] всех простых до B.
[Инициализация]
Пусть x := 2, y := x, P := 1, c := 0, i := 0, j := i.
[Следующее простое]
Пусть i := i + 1. Если i > k, вычислим g = НОД ( P , N ). Если g = 1, выведем сообщение, что разложение не удалось и выйдем, иначе i := j, x := y и идти на шаг 5. Иначе ( т.е если i <= k ), q := p[i], q1 := q, L := [ B / q ].
[Вычисляем степень]
Пока q1 <= L, пусть q1 := q * q1. Затем, пусть x := xq1 mod N, P := P * (x-1) mod N, c := c + 1, и , если c < 20, идти на шаг 2.
[Вычисляем НОД]
Пусть g := НОД ( P , N ). Если g = 1, пусть c := 0, j := i, y := x и идти на шаг 2. Иначе пусть i := j, x := y.
[Обратный ход]
Пусть i := i + 1, q := p[i] и q1 := q.
[Конец?]
Пусть x := xq mod N, g := НОД ( x - 1 , N ). Если g = 1, пусть q1 := q * q1 и если q <= B, идти на шаг 6, иначе - на шаг 5. Иначе (т.е если g >= 1), если g < N, вывести g и выйти.
Если g = N (редкий случай), вывести, что разложение не удалось и выйти.
Заметим, что этот алгоритм может прекратить работу по двум различным причинам. Первая, самая часто встречающаяся, проявит себя в шаге 2. Это то, что N не имеет простых делителей p таких, что p-1 - гладкое степени B. При этом данный факт можно будет считать доказанным.
Вторая причина ( в шаге 6 ) чрезвычайно редка. Это будет означать, что все простые делители N найдены одновременно. Если это так, то, очевидно, существует p - делитель N, которое является гладким степени B. Значит, стоит попробовать запустить алгоритм с другим начальным значением x, например, x := 3 вместо x :=2.
Даже в такой простой форме поведение p-1 алгоритма довольно впечатляюще. Разумеется, он не претендует на получение полного разложения ( например, когда N = ( 2 * p + 1 ) * ( 2 * q + 1 ), где p, q, 2 * p + 1 и 2 * q + 1 простые, причем p и q примерно одного размера, время работы алгоритма будет O( N1/2+e ), если мы хотим разложить N полностью, не лучше простого деления ). С другой стороны, его можно удачно использовать для нахождения даже очень больших делителей N, так как на время работы влияет не размер делителя p, а гладкость p-1.
Размер B зависит, в основном, от времени, которое мы можем потратить. Кроме того, на него влияет существование второй стадии алгоритма. Обычные значения B - где-то от 105 до 106.
p-1 метод, стадия 2.
А теперь - существенное улучшения P-1 алгоритма. Требование существования простого делителя N, такого что p - 1 - гладкое степени B, - слишком строгое. Более рационально положить условие полной разложимости p - 1 при простом делении до B. То есть сделаем возможным существование одного простого делителя, большего B. Но это значит, что p - 1 = f * q, где f - B-гладкое, а q - простое число, возможно, гораздо большее B ( но не B2 ). Для наших целей мы несколько усилим условие и предположим, что у N есть простой делитель р, такой что p - 1 \ f * q, где f - гладкое степени B1 , и q - такое простое, что B1 < q <= B2, где B1 - cтарое B и B2 - гораздо большая константа.
Покажем, как мы будем искать такое p. Очевидно, p - 1 - гладкое степени B2, таким образом мы могли бы использовать стадию 1 с B1 замененным на В2, однако, это нереально, так как B2 - гораздо большая константа, чем В1.
Тем же путем получаем
НОД ( аq*НОК(1..В) - 1 , N ) > 1
и поступаем так: в конце первой стадии у нас будет вычислено b := aНОК(1..В) mod N. Мы храним таблицу разностей простых от B1 до B2. Теперь эти разности малы и у нас их немного. Таким образом мы можем легко вычислить bd для всех возможных разностий d и получить все bd, умножая начальную степень b на эти заранее вычисленные bd. Следовательно, для каждого простого, мы заменяем возведение в степень простым умножением, которое гораздо быстрее, и поэтому мы можем пойти много дальше. Это приводит нас к следующему алгоритму.
Алгоритм p-1 со второй стадией.
Пусть N - составное число и В1 и В2 - заранее выбранные границы. Этот аглоритм будет искать нетривиальные делители N и может сделать это только в том случае, если существует простой делитель p такой, что p - 1 равно некоторому числу гладкости В1, умноженному на простое, меньшее либо равное В2. Мы предполагаем, что уже есть таблица p[1], ... , p[k1] всех простых до В1 и таблица d[1], ... , d[k2] разностей между простыми от В1 до В2, где d[k] = p[k1 + 1] - p[k1], и т.д...
[Первая стадия]
Используя В = В1, попытаться разложить N через алгоритм А2. Если удалось - выйти. В противоположном случае у нас будет число х и тогда пусть b := x, c := 0, P := 1, i := 0, j := i, y := x.
[Предварительные вычисления]
Для всех разностей d[i] (которые малы по размеру и по численности) вычислить и сохранить bd[i]. Пусть x := xp[k1].
[Вперед!]
Пусть i := i + 1, x : = x * bd[i] ( используя значения, вычесленные в шаге 2 ), P := P * ( x - 1 ), c := c + 1. Если i >= k2, идти на шаг 6. Иначе, если c < 20, идти на шаг 3.
[Вычисляем НОД]
Пусть g := НОД ( P , N ). Если g = 1, пусть c := 0, j := i, y := x и идти на шаг 3.
[Обратный ход]
Пусть i := j, x := y. Повторять x := x * bd[i], i := i + 1, g := НОД ( x - 1 , N ) до того, g не примет значение g > 1 ( это должно произойти ). Если g < N вывести g и выйти. Иначе (т.е если g = N, редчайший случай), вывести, что разложение не удалось ( или попробовать опять, используя x := 3 вместо x := 2 в 1 шаге алгоритма А2), и выйти.
[Не удалось?]
Пусть g := НОД ( P , N ). Если g = 1, вывести, что разложение не удалось, и выйти. Иначе идти на шаг 5.
Эта форма р-1 алгоритма гораздо более эффективна, чем одна первая стадия. Обычные значения для использования - это B1 = 2 * 106, B2 = 108.
Оптимально использовать этот алгоритм после простого деления, но перед применением более серьезных методов.