views:

1017

answers:

5

My problem is to compute (g^x) mod p quickly in JavaScript, where ^ is exponentiation, mod is the modulo operation. All inputs are nonnegative integers, x has about 256 bits, and p is a prime number of 2048 bits, and g may have up to 2048 bits.

Most of the software I've found that can do this in JavaScript seems to use the JavaScript BigInt library (http://www.leemon.com/crypto/BigInt.html). Doing a single exponentiation of such size with this library takes about 9 seconds on my slow browser (Firefox 3.0 with SpiderMonkey). I'm looking for a solution which is at least 10 times faster. The obvious idea of using square-and-multiply (exponentiation by squaring, http://en.wikipedia.org/wiki/Exponentiation_by_squaring) is too slow for 2048-bit numbers: it needs up to 4096 multiplications.

Upgrading the browser is not an option. Using another programming language is not an option. Sending the numbers to a web service is not an option.

Is there a faster alternative implemented?

Update: By doing some extra preparations (i.e. precomputing a few hundred powers) as recommended by the article http://www.ccrwest.org/gordon/fast.pdf mentioned in outis' answer below, it is possible do to a 2048-bit modular exponentiation using only at most 354 modular multiplications. (The traditional square-and-multiply method is much slower: it uses maximum 4096 modular multiplications.) Doing so speeds up the modular exponentiation by a factor of 6 in Firefox 3.0, and by a factor of 4 in Google Chrome. The reason why we are not getting the full speedup of 4096/354 is that BigInt's modular exponentation algorithm is already faster than square-and-multiply, because it uses Montgomery reduction (http://en.wikipedia.org/wiki/Montgomery_reduction).

Update: Starting from BigInt's code, it seems worthwhile doing two levels of hand-optimized (and inlined) Karatsuba multiplication (http://en.wikipedia.org/wiki/Karatsuba_algorithm), and only then revert to the base-32768 O(n^2) multiplication implemented in BigInt. This speeds up multiplications by a factor of 2.25 for 2048-bit integers. Unfortunately, the modulo operation does not become faster.

Update: Using the modified Barrett reduction defined in http://www.lirmm.fr/arith18/papers/hasenplaugh-FastModularReduction.pdf and Karatsuba multiplication and precomputing powers (as defined in http://www.ccrwest.org/gordon/fast.pdf), I can get down the time needed for a single multiplication from 73 seconds to 12.3 seconds in Firefox 3.0. This seems to be the best I can do, but it is still too slow.

Update: The ActionScript 2 (AS2) interpreter in the Flash Player isn't worth using, because it seems to be slower than the JavaScript interpreter in Firefox 3.0: for Flash Player 9, it seems to be 4.2 times slower, and for Flash Player 10, it seems to be 2.35 times slower. Does anybody know the speed difference between ActionScript2 and ActionScript3 (AS3) for number chrunching?

Update: The ActionScript 3 (AS3) interpreter in Flash Player 9 isn't worth using because it has just about the same speed as the JavaScript int Firefox 3.0.

Update: The ActionScript 3 (AS3) interpreter in Flash Player 10 can be up to 6.5 times faster than the JavaScript interpreter in Firefox 3.0 if int is used instead of Number, and Vector.<int> is used instead of Array. At least it was 2.41 times faster for 2048-bit big integer multiplication. So it might be worth doing the modular exponentiation in AS3, executing it in Flash Player 10 if available. Please note that this is still slower than V8, the JavaScript interpreter of Google Chrome. See http://ptspts.blogspot.com/2009/10/javascript-and-actionscript-performance.html for a speed comparison of various programming language and JavaScript implementations.

Update: There is a very fast Java solution, which can be called from the browser's JavaScript if the Java plugin is installed. The following solution is about 310 times faster than the pure JavaScript implementation using 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>

Can anyone translate this code to Silverlight (C#)?

+1  A: 

Why not do it server side in some kind of web service using a more appropriate language like C? Times will then be time for one round trip (less than 9 seconds), plus the time for the server to calculate the result using some BigInt library in native code. This is likely to be much faster.

1800 INFORMATION
You may not want to send your private key to the server.
Steve Gilham
Who said anything about private keys?
1800 INFORMATION
With C using the GMP library, it is about 1042 times faster. But using a different programming language or sending the numbers to a server is not an option in my problem.
pts
So I suppose poking them into silverlight for the heavy crunching is out of the question too then?
Dan F
I don't want to have Silverlight as a dependency. But using its bigint or Java's bigint if available in the browser can be feasible. But in this question I need a solution which implements fast modular exponentiation in JavaScript.
pts
+2  A: 

I use "%" for modular (mod) and "/" for integer division. Let function f(p,g,x,r) calculate (r*g^x)%p on the condition that r<p and g<p. f() can be implemented as:

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
}

This routine involves a little more calculation, but each integer is less than 4096 bits which is usually much smaller than g^x. I believe this could be more efficient than the direct calculation. Also note that g^(x%i) can be calculated in a faster manner because we have calculated g^(i+1).

EDIT: see this post. Mehrdad gives the right (and better) solution.

Your implementation gives me an infinite recursion for f(100, 3, 8, 1), instead of returning 61. Does your algorithm have a proper name?
pts
Sorry, there is minor error there. I have changed that. This method is just the result of simple math, too simple to get a name.
The method is based on the observation that (k*p+g)^x%p = g^x%p. It repeatedly applies this rule to avoid calculating g^x directly.
f recurses forever when x/i > 2 in the recursive call to f because y*y > p, so the loop in the recursive call will exit with i=1. Try f(100,5,8,1) (only not really, because you'll have to kill your browser). Note also that `i==floor(log(p)/log(g))`. Depending on the implementation of exponentiation and log, using `i=floor(log(p)/log(g)); y=g^i` might be faster than the loop. Once the recursion problem is fixed, f would be logarithmic in x for the best case, but sqrt in x for the worst case. Exponentiation by squaring (which BigInt uses) is logarithmic in x in all cases.
outis
+1  A: 

Would some other client side technology that's callable from JS, such as a Java applet or Flash movie, be acceptable? BigInt's approach is already fairly fast. You can tweak BigInt, or you can try a different algorithm, but you probably won't get an order of magnitude improvement.

outis
I have to confirm that BigInt is quite well optimized. I've tried to implement multiplication using the Karatsuba algorithm, but it become 4 times as slow as BigInt's simple O(n^2) multiplication.
pts
Thank you for mentioning the paper, it looks promising.
pts
Using BigInt.js with the techniques in the article you have linked I could speed up modular multiplication of 2048-bit integers by a factor of 6 on Firefox 3.0 and a factor of 4 on Google Chrome. Unfortunately, this is still too slow for me, so I have to find a different crypto protocol, which needs less calculations.
pts
I'd like to give more upvotes for this answer because I've found the article linked very useful. But I cannot accept it as the answer, because it is still not fast enough.
pts
+1  A: 

Try this Montgomery modular reduction from http://code.google.com/p/bi2php/ on JavaScript.

An6rey
A: 

I'd love to see the source code to your modified BigInt library - is it available anywhere?

viewcopy
The code I have is not ready for sharing. It is definitely not a general-purpose library.
pts