Непривычное быстрое возведение в степень
Обычно, все возводят число в степень бинарно, попробуем сделать это изощреннее.
Бинарное возведение в степень, которому все учат
У нас есть число, допустим 7. Нам его нужно возвести в степень 19, по модулю 1024, к примеру. Как оно обстоит:
- У нас изначально есть переменная, хранящая такое же значение, как и база для возведения в степень, и отдельная переменная, изначально равная 1.
- Идем по битам сначала степени.
- Если в бите стоит 1, то мы умножаем финальное число на переменную. Если 0, то пропускаем.
- После условия мы умножаем базовое число само на себя, убираем последний бит у степени (мы его использовали только что) и начинаем новую итерацию.
Выглядит оно следующим образом
def binpow(base, power, mod) : res = 1 base = base % mod while power ! = 0 : if power & 1: res = res * base % mod base = base * base % mod power >> = 1 return res;
В чем удобство данного алгоритма? Он достаточно быстрый. Для возведения в степень 19 - 10011, мы проделаем всего 5 итераций циrла, O(LogN).
Максимально простое представление:
7 ^ 19 mod 1024 = 7^1 * 7^2 *7^16 - в сумме степени дают 19, и это как раз что нам надо.
В чем же проблема данного алгоритма? Если мы будем смотреть по тактам, то легко можем понять что происходит внутри. Из-за наличия условия, где происходят самые большие вычисления, алгоритм не является безопасным на аппаратном уровне: либо два умножения (одно из которых гораздо сложнее другого) и сдвиг, либо одно простое и сдвиг.
И тут появляется Монтгомери и предлагает свою лесенку
Лестница Монтгомери
В чем основная идея лестницы? В том, что умножения происходят также и если условие не выполняется. Что это дает? Постоянно происходят разные вычисления, сложно понять что происходит извне (да, в последние годы были исследования уязвимостей и там находили проблемы, но нам важна идея сейчас и понимание), а также эта лесенка применяется в разных кривых как быстрый способ вычисления.
def mont_ladder(base, power, mod): power_bin = format(power, 'b') first = 1 second = base % mod for i in power_bin: if i == "0": second = (first * second) % mod first = pow(first, 2, mod) else: first = (first * second) % mod second = pow(second, 2, mod) return first }
Думаю проще будет показать на примере вычислений:
Получили x = 983, это и есть ответ.
7^19 = 11 398 895 185 373 143 % 1024 = 983.
При всем при этом, лесенка монтгомери не всегда выдает ответ на x, порой она дает правильные значения на втором из оперируемых переменных при возведении в степень
Это все хорошо, но зачем оно нам?
Понадобится позже для понимания того, как происходят вычисления в эллиптических кривых, важность понимания постоянных вычислений (не пропуская вычисления если условие не совпадает, что важно для криптографии) и важность