Моя задача - быстро вычислить (g^x) mod p
в JavaScript, где ^
- возведение в степень, mod
- операция по модулю. Все входы представляют собой неотрицательные целые числа, x
имеет около 256 бит, а p
- простое число из 2048 бит, а g
может иметь до 2048 бит.
Большая часть программного обеспечения, которое я нашел, которое может сделать это в JavaScript, похоже, использует библиотеку JavaScript BigInt (http://www.leemon.com/crypto/BigInt.html). Выполнение одного экспоненциального размера такого размера с этой библиотекой занимает около 9 секунд в моем медленном браузере (Firefox 3.0 с SpiderMonkey). Я ищу решение, которое по крайней мере в 10 раз быстрее. Очевидная идея использования квадратичного умножения (возведение в степень по квадрату, http://en.wikipedia.org/wiki/Exponentiation_by_squaring) слишком медленна для 2048-битных чисел: она нуждается в до 4096 умножений.
Обновление браузера не является вариантом. Использование другого языка программирования не является вариантом. Отправка номеров в веб-службу не является вариантом.
Есть ли более быстрая альтернатива?
Обновление: сделав некоторые дополнительные приготовления (т.е. предварительно вычислив несколько сотен полномочий), как рекомендовано в статье http://www.ccrwest.org/gordon/fast.pdf, упомянутой в ответе outis ниже, можно сделать до 2048-битного модульного возведения в степень, используя только не более 354 модульных умножений. (Традиционный метод квадратичного умножения намного медленнее: он использует максимум 4096 модульных умножений.) Это ускоряет модульное возведение в 6 раз в Firefox 3.0 и в 4 раза в Google Chrome. Причина, по которой мы не получаем полного ускорения 4096/354, заключается в том, что алгоритм модульной экспоненты BigInt уже быстрее, чем квадратный и многократный, поскольку он использует сокращение Montgomery (<а3 > ).
Обновление: начиная с кода BigInt, кажется целесообразным сделать два уровня ручного оптимизированного (и встроенного) умножения Карацубы (http://en.wikipedia.org/wiki/Karatsuba_algorithm), и только затем вернитесь к умножению базы-32768 O (n ^ 2), реализованному в BigInt. Это ускоряет умножения в 2,25 раза для 2048-битных целых чисел. К сожалению, операция modulo не ускоряется.
Обновление: с использованием модифицированной редукции Барретта, определенной в http://www.lirmm.fr/arith18/papers/hasenplaugh-FastModularReduction.pdf и способности умножения и предвычисления Карацубы (как определено в http://www.ccrwest.org/gordon/fast.pdf), я могу сократить время, необходимое для одного умножения с 73 секунд до 12.3 секунд в Firefox 3.0. Кажется, это лучшее, что я могу сделать, но он все еще слишком медленный.
Обновление: интерпретатор ActionScript 2 (AS2) в Flash Player не стоит использовать, потому что он, кажется, медленнее, чем интерпретатор JavaScript в Firefox 3.0: для Flash Player 9 он, по-видимому, в 4,2 раза медленнее, и для Flash Player 10, похоже, он в 2,35 раза медленнее. Кто-нибудь знает разницу в скорости между ActionScript2 и ActionScript3 (AS3) для chrunching?
Обновление: интерпретатор ActionScript 3 (AS3) в Flash Player 9 не стоит использовать, поскольку он имеет примерно такую же скорость, что и JavaScript int Firefox 3.0.
Обновление: интерпретатор ActionScript 3 (AS3) в Flash Player 10 может быть в 6,5 раз быстрее, чем интерпретатор JavaScript в Firefox 3.0, если вместо Number
используется int
, а Vector.<int>
используется вместо Array
. По крайней мере, это было в 2,41 раза быстрее для 2048-битного большого целочисленного умножения. Поэтому, возможно, стоит сделать модульное возведение в степень в AS3, выполнив его в Flash Player 10, если он доступен. Обратите внимание, что это все еще медленнее, чем V8, интерпретатор JavaScript в Google Chrome. См. http://ptspts.blogspot.com/2009/10/javascript-and-actionscript-performance.html для сравнения скорости различных языков программирования и реализаций JavaScript.
Обновление. Существует очень быстрое Java-решение, которое можно вызывать из браузера JavaScript, если установлен плагин Java. Следующее решение примерно в 310 раз быстрее, чем чистая реализация JavaScript с помощью BigInt.
<body>hi0
<script type="text/javascript">
document.body.innerHTML += '<br>hi1';
if ('object'==typeof java) {
var x = new java.math.BigInteger("123456789123456789", 10);
var p = new java.math.BigInteger("234567891234567891", 10);
var g = new java.math.BigInteger("3", 10);
var v = x.modPow(x, p);
document.body.innerHTML += '<br>' + v.toString();
document.body.innerHTML += '<br>' + v.toString(16);
} else {
document.body.innerHTML += '<br>java plugin not installed';
}
</script></body>
Можно ли перевести этот код на Silverlight (С#)?