JavaScript中最快的模幂运算

时间:2009-09-20 08:48:24

标签: javascript primes modulo discrete-mathematics exponentiation

我的问题是在JavaScript中快速计算(g^x) mod p,其中^是取幂,mod是模运算。所有输入都是非负整数,x大约有256位,p是2048位的素数,g最多可以有2048位。

我发现可以在JavaScript中执行此操作的大多数软件似乎都使用JavaScript BigInt库(http://www.leemon.com/crypto/BigInt.html)。在我的慢速浏览器(使用SpiderMonkey的Firefox 3.0)上使用此库执行此类大小的单次取幂大约需要9秒。我正在寻找一种至少快10倍的解决方案。使用square-and-multiply(通过平方取幂,http://en.wikipedia.org/wiki/Exponentiation_by_squaring)的明显想法对于2048位数来说太慢了:它需要多达4096次乘法。

升级浏览器不是一种选择。使用其他编程语言不是一种选择。将数字发送到Web服务不是一种选择。

是否实施了更快的替代方案?

更新:通过按照下面的答案中提到的文章http://www.ccrwest.org/gordon/fast.pdf的建议做一些额外的准备工作(即预先计算几百个权力),可以使用最多只进行2048位模幂运算354模块化乘法。 (传统的square-and-multiply方法要慢得多:它使用最多4096次模乘。)这样做可以在Firefox 3.0中将模幂运算速度提高6倍,在Google Chrome中提高4倍。我们没有得到4096/354的全速加速的原因是BigInt的模块化指数算法已经比平方和乘法更快,因为它使用蒙哥马利减少(http://en.wikipedia.org/wiki/Montgomery_reduction)。

更新:从BigInt的代码开始,似乎值得做两个级别的手动优化(和内联)Karatsuba乘法(http://en.wikipedia.org/wiki/Karatsuba_algorithm),然后才恢复到基础-32768 O(n ^ 2)乘法在BigInt中实现。对于2048位整数,这会使乘法乘以2.25倍。不幸的是,模运算不会变得更快。

更新:使用http://www.lirmm.fr/arith18/papers/hasenplaugh-FastModularReduction.pdf中定义的修改后的Barrett缩减和Karatsuba乘法和预计算能力(如http://www.ccrwest.org/gordon/fast.pdf中所定义),我可以将单次乘法所需的时间从73秒减少到12.3 Firefox 3.0中的秒数。这似乎是我能做的最好的,但它仍然太慢了。

更新:Flash Player中的ActionScript 2(AS2)解释器不值得使用,因为它似乎比Firefox 3.0中的JavaScript解释器慢:对于Flash Player 9,它似乎慢了4.2倍,并且对于Flash Player 10,它似乎慢了2.35倍。是否有人知道ActionScript2和ActionScript3(AS3)之间的速度差异是否为数字运行?

更新:Flash Player 9中的ActionScript 3(AS3)解释器不值得使用,因为它与JavaScript int Firefox 3.0的速度几乎相同。

更新:如果使用int而不是Number,那么Flash Player 10中的ActionScript 3(AS3)解释器可以比Firefox 3.0中的JavaScript解释器快6.5倍,并且{{1使用}代替Vector.<int>。对于2048位大整数乘法,至少它快2.41倍。因此,在AS3中进行模幂运算可能是值得的,如果可用的话,在Flash Player 10中执行它。请注意,这仍然比谷歌Chrome的JavaScript解释器V8慢。有关各种编程语言和JavaScript实现的速度比较,请参阅http://ptspts.blogspot.com/2009/10/javascript-and-actionscript-performance.html

更新:有一个非常快速的Java解决方案,如果安装了Java插件,可以从浏览器的JavaScript调用。以下解决方案比使用BigInt的纯JavaScript实现快约310倍。

Array

任何人都可以将此代码翻译为Silverlight(C#)吗?

5 个答案:

答案 0 :(得分:4)

可以接受一些可以从JS调用的客户端技术,例如Java applet或Flash电影吗? BigInt的approach已经相当快了。您可以调整BigInt,或者您可以尝试different algorithm,但您可能无法获得一个数量级的改进。

答案 1 :(得分:3)

我使用“%”表示模块(mod),“/”表示整数除法。令函数f(p,g,x,r)在r

bigint_t f(p,g,x,r) {
  bigint_t i, z = g, y;
  for (i = 1; i < x; ++i) {
    y = z; z *= g;
    if (z > p) break;
  }
  if (i >= x - 1) return r*z%p; // g^x*r%p = g^x*r
  else return f(p,y,x/i,g^(x%i)*r%p); // reduce to (r*g^(x%i)%p)*(g^i)^(x/i)%p
}

此例程涉及更多计算,但每个整数小于4096位,通常远小于g ^ x。我相信这可能比直接计算更有效。另请注意,g ^(x%i)可以更快的方式计算,因为我们已经计算了g ^(i + 1)。

编辑:见this post。 Mehrdad提供了正确(和更好)的解决方案。

答案 2 :(得分:2)

为什么不使用像C这样的更合适的语言在某种Web服务中使用服务器端呢?然后,时间将是一次往返(少于9秒)的时间,加上服务器使用本机代码中的一些BigInt库计算结果的时间。这可能会快得多。

答案 3 :(得分:2)

在JavaScript上尝试从http://code.google.com/p/bi2php/进行蒙哥马利模块缩减。

答案 4 :(得分:1)

我很想看到修改过的BigInt库的源代码 - 它可以在任何地方使用吗?