Модульное возведение в степень — это возведение в степень , выполняемое по модулю . Он полезен в информатике , особенно в области криптографии с открытым ключом , где он используется как при обмене ключами Диффи-Хеллмана, так и при обмене ключами Диффи-Хеллмана и открытых/закрытых ключах RSA .
Модульное возведение в степень — это остаток, когда целое число b (основание) возводится в степень e (показатель степени) и делится на положительное целое число m (модуль); то есть c = b e mod m . Из определения деления следует, что 0 ≤ c < m .
Например, учитывая b = 5 , e = 3 и m = 13 , при делении 5 3 = 125 на 13 остается остаток c = 8 .
Модульное возведение в степень можно выполнить с отрицательным показателем e , найдя модульный мультипликативный обратный d к b по модулю m , используя расширенный алгоритм Евклида . То есть:
Модульное возведение в степень эффективно вычисляет даже для очень больших целых чисел. С другой стороны, вычисление модульного дискретного логарифма , то есть нахождение показателя степени e при заданных b , c и m , считается трудным. Такое одностороннее поведение функции делает модульное возведение в степень кандидатом на использование в криптографических алгоритмах.
Самый прямой метод вычисления модулярного показателя — непосредственно вычислить b e , а затем взять это число по модулю m . Рассмотрим попытку вычислить c , учитывая b = 4 , e = 13 и m = 497 :
Можно было бы использовать калькулятор, чтобы вычислить 4 13 ; получается 67 108 864. Принимая это значение по модулю 497, ответ c определяется как 445.
Обратите внимание, что длина b составляет только одну цифру, а длина e — только две цифры, но длина значения b e составляет 8 цифр.
В сильной криптографии b часто составляет не менее 1024 бит . [1] Рассмотрим b = 5 × 10 76 и e = 17 , оба из которых являются вполне разумными значениями. В этом примере длина b составляет 77 цифр, а длина e — 2 цифры, но длина значения b e составляет 1304 десятичных цифры. Такие вычисления возможны на современных компьютерах, но сама величина таких чисел приводит к значительному замедлению скорости вычислений. Поскольку b и e увеличиваются еще больше для обеспечения большей безопасности, значение b e становится громоздким.
Время, необходимое для возведения в степень, зависит от операционной среды и процессора. Для завершения описанного выше метода требуется O ( e ) умножений.
Уменьшение чисел требует дополнительных операций модульного сокращения, но уменьшенный размер делает каждую операцию быстрее, экономя время (а также память) в целом.
Этот алгоритм использует тождество
Модифицированный алгоритм:
Обратите внимание, что при каждом переходе к шагу 3 уравнение c ≡ b e′ (mod m ) выполняется. Когда шаг 3 был выполнен e раз, c содержит искомый ответ. Таким образом, этот алгоритм в основном подсчитывает e' по единицам, пока e' не достигнет e , выполняя умножение на b и операцию по модулю каждый раз, когда он добавляет единицу (чтобы гарантировать, что результаты остаются небольшими).
Пример b = 4 , e = 13 и m = 497 представлен снова. Алгоритм проходит шаг 3 тринадцать раз:
Таким образом, окончательный ответ для c — 445, как и в первом методе.
Как и первый метод, для завершения этого метода требуется умножение O( e ) . Однако, поскольку числа, используемые в этих расчетах, намного меньше чисел, используемых в расчетах первого алгоритма, время вычислений в этом методе уменьшается как минимум в O( e ) .
В псевдокоде этот метод можно реализовать следующим образом:
функцияmodular_pow (основание, показатель степени, модуль) : если модуль = 1 , то возвращается 0 с := 1 для e_prime = от 0 до экспоненты-1 do c := (c * base) модуль модуля return c
Третий метод радикально сокращает количество операций по модульному возведению в степень, сохраняя при этом тот же объем памяти , что и в предыдущем методе. Это комбинация предыдущего метода и более общего принципа, называемого возведением в степень возведением в степень (также известным как двоичное возведение в степень ).
Во-первых, требуется, чтобы показатель степени e был преобразован в двоичную систему счисления . То есть e можно записать как:
В таких обозначениях длина e равна n битам. a i может принимать значение 0 или 1 для любого i такого, что 0 ≤ i < n . По определению, n − 1 = 1 .
Тогда значение b e можно записать как:
Таким образом, решение c :
Ниже приведен пример псевдокода на основе «Прикладной криптографии» Брюса Шнайера . [2] Входные данные base , показатель степени и модуль соответствуют b , e и m в приведенных выше уравнениях.
функцияmodular_pow (база, показатель, модуль) - если модуль = 1 , то возвращает 0. Assert :: (модуль - 1) * (модуль - 1) не переполняет базу результат := 1 базовый := базовый модуль модуля , пока показатель степени > 0, выполните if (показатель степени 2 == 1), затем результат := (результат * базовый) модуль модуля показатель степени := показатель >> 1base : = (base * base) модуль возвращаемый результат
Обратите внимание, что при первом входе в цикл переменная кода base эквивалентна b . Однако повторное возведение в квадрат в третьей строке кода гарантирует, что по завершении каждого цикла переменная base будет эквивалентна b 2 i mod m , где i — количество повторений цикла. (Это делает i следующим рабочим битом двоичной экспоненты экспоненты , где младшим битом является экспонента 0 ).
Первая строка кода просто выполняет умножение . Если _равно нулю, никакой код не выполняется, поскольку это фактически умножает промежуточную сумму на единицу. Если _вместо этого единица, переменная база (содержащая значение b 2 i mod m исходной базы) просто умножается.
В этом примере основание b возводится в степень e = 13 . Показатель степени равен 1101 в двоичном формате. Имеется четыре двоичных цифры, поэтому цикл выполняется четыре раза со значениями a 0 = 1, a 1 = 0, a 2 = 1 и a 3 = 1 .
Сначала инициализируйте результат значением 1 и сохраните значение b в переменной x :
Мы закончили : теперь R.
Вот приведенный выше расчет, в котором мы вычисляем b = 4 в степени e = 13 , выполняемый по модулю 497.
Инициализировать:
Мы закончили: R теперь равен тому же результату, который был получен в предыдущих алгоритмах.
Время работы этого алгоритма составляет O(log exdependent ) . При работе с большими значениями экспоненты это дает существенный выигрыш в скорости по сравнению с двумя предыдущими алгоритмами, время которых равно O( экспонента ) . Например, если показатель степени был 2 20 = 1048576, этот алгоритм будет иметь 20 шагов вместо 1048576 шагов.
функция modPow(b, e, m), если m == 1 , то возвращает 0 , завершает локальный r = 1 б = б % м пока e > 0 делать, если e % 2 == 1 , то г = (г*б) % м конец б = (b*b) % м e = e >> 1 — используйте 'e = math.floor(e / 2)' в Lua 5.2 или старше конец возврат r конец
Мы также можем использовать биты экспоненты в порядке слева направо. На практике нам обычно нужен результат по модулю некоторого модуля m . В этом случае мы бы уменьшили каждый результат умножения (mod m ) , прежде чем продолжить. Для простоты расчет модуля здесь опущен. В этом примере показано, как выполнять вычисления с использованием двоичного возведения в степень слева направо. Показатель степени равен 1101 в двоичном формате; есть 4 бита, поэтому есть 4 итерации.
Инициализируйте результат как 1: .
В «Искусстве компьютерного программирования» , Vol. 2, Seminumerical Algorithms , стр. 463, Дональд Кнут отмечает, что вопреки некоторым утверждениям, этот метод не всегда дает минимально возможное количество умножений. Наименьший контрпример относится к степени 15, когда двоичный метод требует шести умножений. Вместо этого сформируйте x 3 двумя умножениями, затем x 6 путем возведения в квадрат x 3 , затем x 12 путем возведения в квадрат x 6 и, наконец, x 15 путем умножения x 12 и x 3 , тем самым достигая желаемого результата всего за пять умножений. Однако далее следуют многие страницы, описывающие, как вообще можно создать такие последовательности.
m -й член любой константно-рекурсивной последовательности (например, чисел Фибоначчи или чисел Перрена ), где каждый член является линейной функцией от k предыдущих членов, может быть эффективно вычислен по модулю n путем вычисления A m mod n , где A — соответствующее k × k сопутствующая матрица . Вышеупомянутые методы легко адаптируются к этому приложению. Это можно использовать, например, для проверки простоты больших чисел n .
Рекурсивный алгоритм для ModExp(A, b, c)
= Ab mod c , где A — квадратная матрица .
function Matrix_ModExp(Matrix A, int b, int c) is if b == 0 then return I // Единичная матрица if (b mod 2 == 1) then return (A * Matrix_ModExp(A, b - 1, c) ) мод с Матрица D:= Matrix_ModExp(A, b/2, c) вернуть (D * D) мод c
При обмене ключами Диффи-Хеллмана используется возведение в степень в конечных циклических группах. Вышеупомянутые методы возведения в степень модульной матрицы явно распространяются на этот контекст. Модульное матричное умножение C ≡ AB (mod n ) везде просто заменяется групповым умножением c = ab .
В квантовых вычислениях модульное возведение в степень оказывается узким местом алгоритма Шора , где оно должно быть вычислено с помощью схемы, состоящей из обратимых вентилей , которые в дальнейшем могут быть разбиты на квантовые вентили , подходящие для конкретного физического устройства. Более того, в алгоритме Шора можно знать базу и модуль возведения в степень при каждом вызове, что позволяет проводить различные оптимизации схемы. [3]
Поскольку модульное возведение в степень является важной операцией в информатике и существуют эффективные алгоритмы (см. выше), которые работают намного быстрее, чем просто возведение в степень с последующим взятием остатка, многие языки программирования и библиотеки целых чисел произвольной точности имеют специальную функцию для выполнения модульного возведения в степень. :
pow()
(возведение в степень) [1] принимает необязательный третий аргумент — модульBigInteger
имеет ModPow()
метод для выполнения модульного возведения в степень.java.math.BigInteger
есть modPow()
метод для выполнения модульного возведения в степень.powermod
из Symbolic Math ToolboxMath::BigInt
имеет bmodpow()
метод [2] для выполнения модульного возведения в степень.expmod
.big.Int
содержит Exp()
метод (возведения в степень) [3], третий параметр которого, если он не равен нулю, является модулемbcpowmod()
функция [4] для выполнения модульного возведения в степень.mpz_powm()
функцию [5] для выполнения модульного возведения в степень.@PowerMod()
для FileMaker Pro (с примером 1024-битного шифрования RSA )openssl
есть OpenSSL::BN#mod_exp
метод [6] для выполнения модульного возведения в степень.