source: Dev/branches/rest-dojo-ui/client/dojox/math/BigInteger.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 15.0 KB
Line 
1// AMD-ID "dojox/math/BigInteger"
2define(["dojo", "dojox"], function(dojo, dojox) {
3
4        dojo.getObject("math.BigInteger", true, dojox);
5        dojo.experimental("dojox.math.BigInteger");
6
7// Contributed under CLA by Tom Wu <tjw@cs.Stanford.EDU>
8// See http://www-cs-students.stanford.edu/~tjw/jsbn/ for details.
9
10// Basic JavaScript BN library - subset useful for RSA encryption.
11// The API for dojox.math.BigInteger closely resembles that of the java.math.BigInteger class in Java.
12
13        // Bits per digit
14        var dbits;
15
16        // JavaScript engine analysis
17        var canary = 0xdeadbeefcafe;
18        var j_lm = ((canary&0xffffff)==0xefcafe);
19
20        // (public) Constructor
21        function BigInteger(a,b,c) {
22          if(a != null)
23                if("number" == typeof a) this._fromNumber(a,b,c);
24                else if(!b && "string" != typeof a) this._fromString(a,256);
25                else this._fromString(a,b);
26        }
27
28        // return new, unset BigInteger
29        function nbi() { return new BigInteger(null); }
30
31        // am: Compute w_j += (x*this_i), propagate carries,
32        // c is initial carry, returns final carry.
33        // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
34        // We need to select the fastest one that works in this environment.
35
36        // am1: use a single mult and divide to get the high bits,
37        // max digit bits should be 26 because
38        // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
39        function am1(i,x,w,j,c,n) {
40          while(--n >= 0) {
41                var v = x*this[i++]+w[j]+c;
42                c = Math.floor(v/0x4000000);
43                w[j++] = v&0x3ffffff;
44          }
45          return c;
46        }
47        // am2 avoids a big mult-and-extract completely.
48        // Max digit bits should be <= 30 because we do bitwise ops
49        // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
50        function am2(i,x,w,j,c,n) {
51          var xl = x&0x7fff, xh = x>>15;
52          while(--n >= 0) {
53                var l = this[i]&0x7fff;
54                var h = this[i++]>>15;
55                var m = xh*l+h*xl;
56                l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
57                c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
58                w[j++] = l&0x3fffffff;
59          }
60          return c;
61        }
62        // Alternately, set max digit bits to 28 since some
63        // browsers slow down when dealing with 32-bit numbers.
64        function am3(i,x,w,j,c,n) {
65          var xl = x&0x3fff, xh = x>>14;
66          while(--n >= 0) {
67                var l = this[i]&0x3fff;
68                var h = this[i++]>>14;
69                var m = xh*l+h*xl;
70                l = xl*l+((m&0x3fff)<<14)+w[j]+c;
71                c = (l>>28)+(m>>14)+xh*h;
72                w[j++] = l&0xfffffff;
73          }
74          return c;
75        }
76        if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
77          BigInteger.prototype.am = am2;
78          dbits = 30;
79        }
80        else if(j_lm && (navigator.appName != "Netscape")) {
81          BigInteger.prototype.am = am1;
82          dbits = 26;
83        }
84        else { // Mozilla/Netscape seems to prefer am3
85          BigInteger.prototype.am = am3;
86          dbits = 28;
87        }
88
89        var BI_FP = 52;
90
91        // Digit conversions
92        var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
93        var BI_RC = [];
94        var rr,vv;
95        rr = "0".charCodeAt(0);
96        for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
97        rr = "a".charCodeAt(0);
98        for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
99        rr = "A".charCodeAt(0);
100        for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
101
102        function int2char(n) { return BI_RM.charAt(n); }
103        function intAt(s,i) {
104          var c = BI_RC[s.charCodeAt(i)];
105          return (c==null)?-1:c;
106        }
107
108        // (protected) copy this to r
109        function bnpCopyTo(r) {
110          for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
111          r.t = this.t;
112          r.s = this.s;
113        }
114
115        // (protected) set from integer value x, -DV <= x < DV
116        function bnpFromInt(x) {
117          this.t = 1;
118          this.s = (x<0)?-1:0;
119          if(x > 0) this[0] = x;
120          else if(x < -1) this[0] = x+_DV;
121          else this.t = 0;
122        }
123
124        // return bigint initialized to value
125        function nbv(i) { var r = nbi(); r._fromInt(i); return r; }
126
127        // (protected) set from string and radix
128        function bnpFromString(s,b) {
129          var k;
130          if(b == 16) k = 4;
131          else if(b == 8) k = 3;
132          else if(b == 256) k = 8; // byte array
133          else if(b == 2) k = 1;
134          else if(b == 32) k = 5;
135          else if(b == 4) k = 2;
136          else { this.fromRadix(s,b); return; }
137          this.t = 0;
138          this.s = 0;
139          var i = s.length, mi = false, sh = 0;
140          while(--i >= 0) {
141                var x = (k==8)?s[i]&0xff:intAt(s,i);
142                if(x < 0) {
143                  if(s.charAt(i) == "-") mi = true;
144                  continue;
145                }
146                mi = false;
147                if(sh == 0)
148                  this[this.t++] = x;
149                else if(sh+k > this._DB) {
150                  this[this.t-1] |= (x&((1<<(this._DB-sh))-1))<<sh;
151                  this[this.t++] = (x>>(this._DB-sh));
152                }
153                else
154                  this[this.t-1] |= x<<sh;
155                sh += k;
156                if(sh >= this._DB) sh -= this._DB;
157          }
158          if(k == 8 && (s[0]&0x80) != 0) {
159                this.s = -1;
160                if(sh > 0) this[this.t-1] |= ((1<<(this._DB-sh))-1)<<sh;
161          }
162          this._clamp();
163          if(mi) BigInteger.ZERO._subTo(this,this);
164        }
165
166        // (protected) clamp off excess high words
167        function bnpClamp() {
168          var c = this.s&this._DM;
169          while(this.t > 0 && this[this.t-1] == c) --this.t;
170        }
171
172        // (public) return string representation in given radix
173        function bnToString(b) {
174          if(this.s < 0) return "-"+this.negate().toString(b);
175          var k;
176          if(b == 16) k = 4;
177          else if(b == 8) k = 3;
178          else if(b == 2) k = 1;
179          else if(b == 32) k = 5;
180          else if(b == 4) k = 2;
181          else return this._toRadix(b);
182          var km = (1<<k)-1, d, m = false, r = "", i = this.t;
183          var p = this._DB-(i*this._DB)%k;
184          if(i-- > 0) {
185                if(p < this._DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
186                while(i >= 0) {
187                  if(p < k) {
188                        d = (this[i]&((1<<p)-1))<<(k-p);
189                        d |= this[--i]>>(p+=this._DB-k);
190                  }
191                  else {
192                        d = (this[i]>>(p-=k))&km;
193                        if(p <= 0) { p += this._DB; --i; }
194                  }
195                  if(d > 0) m = true;
196                  if(m) r += int2char(d);
197                }
198          }
199          return m?r:"0";
200        }
201
202        // (public) -this
203        function bnNegate() { var r = nbi(); BigInteger.ZERO._subTo(this,r); return r; }
204
205        // (public) |this|
206        function bnAbs() { return (this.s<0)?this.negate():this; }
207
208        // (public) return + if this > a, - if this < a, 0 if equal
209        function bnCompareTo(a) {
210          var r = this.s-a.s;
211          if(r) return r;
212          var i = this.t;
213          r = i-a.t;
214          if(r) return r;
215          while(--i >= 0) if((r = this[i] - a[i])) return r;
216          return 0;
217        }
218
219        // returns bit length of the integer x
220        function nbits(x) {
221          var r = 1, t;
222          if((t=x>>>16)) { x = t; r += 16; }
223          if((t=x>>8)) { x = t; r += 8; }
224          if((t=x>>4)) { x = t; r += 4; }
225          if((t=x>>2)) { x = t; r += 2; }
226          if((t=x>>1)) { x = t; r += 1; }
227          return r;
228        }
229
230        // (public) return the number of bits in "this"
231        function bnBitLength() {
232          if(this.t <= 0) return 0;
233          return this._DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this._DM));
234        }
235
236        // (protected) r = this << n*DB
237        function bnpDLShiftTo(n,r) {
238          var i;
239          for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
240          for(i = n-1; i >= 0; --i) r[i] = 0;
241          r.t = this.t+n;
242          r.s = this.s;
243        }
244
245        // (protected) r = this >> n*DB
246        function bnpDRShiftTo(n,r) {
247          for(var i = n; i < this.t; ++i) r[i-n] = this[i];
248          r.t = Math.max(this.t-n,0);
249          r.s = this.s;
250        }
251
252        // (protected) r = this << n
253        function bnpLShiftTo(n,r) {
254          var bs = n%this._DB;
255          var cbs = this._DB-bs;
256          var bm = (1<<cbs)-1;
257          var ds = Math.floor(n/this._DB), c = (this.s<<bs)&this._DM, i;
258          for(i = this.t-1; i >= 0; --i) {
259                r[i+ds+1] = (this[i]>>cbs)|c;
260                c = (this[i]&bm)<<bs;
261          }
262          for(i = ds-1; i >= 0; --i) r[i] = 0;
263          r[ds] = c;
264          r.t = this.t+ds+1;
265          r.s = this.s;
266          r._clamp();
267        }
268
269        // (protected) r = this >> n
270        function bnpRShiftTo(n,r) {
271          r.s = this.s;
272          var ds = Math.floor(n/this._DB);
273          if(ds >= this.t) { r.t = 0; return; }
274          var bs = n%this._DB;
275          var cbs = this._DB-bs;
276          var bm = (1<<bs)-1;
277          r[0] = this[ds]>>bs;
278          for(var i = ds+1; i < this.t; ++i) {
279                r[i-ds-1] |= (this[i]&bm)<<cbs;
280                r[i-ds] = this[i]>>bs;
281          }
282          if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
283          r.t = this.t-ds;
284          r._clamp();
285        }
286
287        // (protected) r = this - a
288        function bnpSubTo(a,r) {
289          var i = 0, c = 0, m = Math.min(a.t,this.t);
290          while(i < m) {
291                c += this[i]-a[i];
292                r[i++] = c&this._DM;
293                c >>= this._DB;
294          }
295          if(a.t < this.t) {
296                c -= a.s;
297                while(i < this.t) {
298                  c += this[i];
299                  r[i++] = c&this._DM;
300                  c >>= this._DB;
301                }
302                c += this.s;
303          }
304          else {
305                c += this.s;
306                while(i < a.t) {
307                  c -= a[i];
308                  r[i++] = c&this._DM;
309                  c >>= this._DB;
310                }
311                c -= a.s;
312          }
313          r.s = (c<0)?-1:0;
314          if(c < -1) r[i++] = this._DV+c;
315          else if(c > 0) r[i++] = c;
316          r.t = i;
317          r._clamp();
318        }
319
320        // (protected) r = this * a, r != this,a (HAC 14.12)
321        // "this" should be the larger one if appropriate.
322        function bnpMultiplyTo(a,r) {
323          var x = this.abs(), y = a.abs();
324          var i = x.t;
325          r.t = i+y.t;
326          while(--i >= 0) r[i] = 0;
327          for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
328          r.s = 0;
329          r._clamp();
330          if(this.s != a.s) BigInteger.ZERO._subTo(r,r);
331        }
332
333        // (protected) r = this^2, r != this (HAC 14.16)
334        function bnpSquareTo(r) {
335          var x = this.abs();
336          var i = r.t = 2*x.t;
337          while(--i >= 0) r[i] = 0;
338          for(i = 0; i < x.t-1; ++i) {
339                var c = x.am(i,x[i],r,2*i,0,1);
340                if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x._DV) {
341                  r[i+x.t] -= x._DV;
342                  r[i+x.t+1] = 1;
343                }
344          }
345          if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
346          r.s = 0;
347          r._clamp();
348        }
349
350        // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
351        // r != q, this != m.  q or r may be null.
352        function bnpDivRemTo(m,q,r) {
353          var pm = m.abs();
354          if(pm.t <= 0) return;
355          var pt = this.abs();
356          if(pt.t < pm.t) {
357                if(q != null) q._fromInt(0);
358                if(r != null) this._copyTo(r);
359                return;
360          }
361          if(r == null) r = nbi();
362          var y = nbi(), ts = this.s, ms = m.s;
363          var nsh = this._DB-nbits(pm[pm.t-1]); // normalize modulus
364          if(nsh > 0) { pm._lShiftTo(nsh,y); pt._lShiftTo(nsh,r); }
365          else { pm._copyTo(y); pt._copyTo(r); }
366          var ys = y.t;
367          var y0 = y[ys-1];
368          if(y0 == 0) return;
369          var yt = y0*(1<<this._F1)+((ys>1)?y[ys-2]>>this._F2:0);
370          var d1 = this._FV/yt, d2 = (1<<this._F1)/yt, e = 1<<this._F2;
371          var i = r.t, j = i-ys, t = (q==null)?nbi():q;
372          y._dlShiftTo(j,t);
373          if(r.compareTo(t) >= 0) {
374                r[r.t++] = 1;
375                r._subTo(t,r);
376          }
377          BigInteger.ONE._dlShiftTo(ys,t);
378          t._subTo(y,y);        // "negative" y so we can replace sub with am later
379          while(y.t < ys) y[y.t++] = 0;
380          while(--j >= 0) {
381                // Estimate quotient digit
382                var qd = (r[--i]==y0)?this._DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
383                if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) {  // Try it out
384                  y._dlShiftTo(j,t);
385                  r._subTo(t,r);
386                  while(r[i] < --qd) r._subTo(t,r);
387                }
388          }
389          if(q != null) {
390                r._drShiftTo(ys,q);
391                if(ts != ms) BigInteger.ZERO._subTo(q,q);
392          }
393          r.t = ys;
394          r._clamp();
395          if(nsh > 0) r._rShiftTo(nsh,r);       // Denormalize remainder
396          if(ts < 0) BigInteger.ZERO._subTo(r,r);
397        }
398
399        // (public) this mod a
400        function bnMod(a) {
401          var r = nbi();
402          this.abs()._divRemTo(a,null,r);
403          if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a._subTo(r,r);
404          return r;
405        }
406
407        // Modular reduction using "classic" algorithm
408        function Classic(m) { this.m = m; }
409        function cConvert(x) {
410          if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
411          else return x;
412        }
413        function cRevert(x) { return x; }
414        function cReduce(x) { x._divRemTo(this.m,null,x); }
415        function cMulTo(x,y,r) { x._multiplyTo(y,r); this.reduce(r); }
416        function cSqrTo(x,r) { x._squareTo(r); this.reduce(r); }
417
418        dojo.extend(Classic, {
419                convert:        cConvert,
420                revert:         cRevert,
421                reduce:         cReduce,
422                mulTo:          cMulTo,
423                sqrTo:          cSqrTo
424        });
425
426        // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
427        // justification:
428        //         xy == 1 (mod m)
429        //         xy =  1+km
430        //   xy(2-xy) = (1+km)(1-km)
431        // x[y(2-xy)] = 1-k^2m^2
432        // x[y(2-xy)] == 1 (mod m^2)
433        // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
434        // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
435        // JS multiply "overflows" differently from C/C++, so care is needed here.
436        function bnpInvDigit() {
437          if(this.t < 1) return 0;
438          var x = this[0];
439          if((x&1) == 0) return 0;
440          var y = x&3;          // y == 1/x mod 2^2
441          y = (y*(2-(x&0xf)*y))&0xf;    // y == 1/x mod 2^4
442          y = (y*(2-(x&0xff)*y))&0xff;  // y == 1/x mod 2^8
443          y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff;   // y == 1/x mod 2^16
444          // last step - calculate inverse mod DV directly;
445          // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
446          y = (y*(2-x*y%this._DV))%this._DV;            // y == 1/x mod 2^dbits
447          // we really want the negative inverse, and -DV < y < DV
448          return (y>0)?this._DV-y:-y;
449        }
450
451        // Montgomery reduction
452        function Montgomery(m) {
453          this.m = m;
454          this.mp = m._invDigit();
455          this.mpl = this.mp&0x7fff;
456          this.mph = this.mp>>15;
457          this.um = (1<<(m._DB-15))-1;
458          this.mt2 = 2*m.t;
459        }
460
461        // xR mod m
462        function montConvert(x) {
463          var r = nbi();
464          x.abs()._dlShiftTo(this.m.t,r);
465          r._divRemTo(this.m,null,r);
466          if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m._subTo(r,r);
467          return r;
468        }
469
470        // x/R mod m
471        function montRevert(x) {
472          var r = nbi();
473          x._copyTo(r);
474          this.reduce(r);
475          return r;
476        }
477
478        // x = x/R mod m (HAC 14.32)
479        function montReduce(x) {
480          while(x.t <= this.mt2)        // pad x so am has enough room later
481                x[x.t++] = 0;
482          for(var i = 0; i < this.m.t; ++i) {
483                // faster way of calculating u0 = x[i]*mp mod DV
484                var j = x[i]&0x7fff;
485                var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x._DM;
486                // use am to combine the multiply-shift-add into one call
487                j = i+this.m.t;
488                x[j] += this.m.am(0,u0,x,i,0,this.m.t);
489                // propagate carry
490                while(x[j] >= x._DV) { x[j] -= x._DV; x[++j]++; }
491          }
492          x._clamp();
493          x._drShiftTo(this.m.t,x);
494          if(x.compareTo(this.m) >= 0) x._subTo(this.m,x);
495        }
496
497        // r = "x^2/R mod m"; x != r
498        function montSqrTo(x,r) { x._squareTo(r); this.reduce(r); }
499
500        // r = "xy/R mod m"; x,y != r
501        function montMulTo(x,y,r) { x._multiplyTo(y,r); this.reduce(r); }
502
503        dojo.extend(Montgomery, {
504                convert:        montConvert,
505                revert:         montRevert,
506                reduce:         montReduce,
507                mulTo:          montMulTo,
508                sqrTo:          montSqrTo
509        });
510
511        // (protected) true iff this is even
512        function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
513
514        // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
515        function bnpExp(e,z) {
516          if(e > 0xffffffff || e < 1) return BigInteger.ONE;
517          var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
518          g._copyTo(r);
519          while(--i >= 0) {
520                z.sqrTo(r,r2);
521                if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
522                else { var t = r; r = r2; r2 = t; }
523          }
524          return z.revert(r);
525        }
526
527        // (public) this^e % m, 0 <= e < 2^32
528        function bnModPowInt(e,m) {
529          var z;
530          if(e < 256 || m._isEven()) z = new Classic(m); else z = new Montgomery(m);
531          return this._exp(e,z);
532        }
533
534        dojo.extend(BigInteger, {
535                // protected, not part of the official API
536                _DB:    dbits,
537                _DM:    (1 << dbits) - 1,
538                _DV:    1 << dbits,
539
540                _FV:    Math.pow(2, BI_FP),
541                _F1:    BI_FP - dbits,
542                _F2:    2 * dbits-BI_FP,
543
544                // protected
545                _copyTo:                bnpCopyTo,
546                _fromInt:               bnpFromInt,
547                _fromString:    bnpFromString,
548                _clamp:                 bnpClamp,
549                _dlShiftTo:             bnpDLShiftTo,
550                _drShiftTo:             bnpDRShiftTo,
551                _lShiftTo:              bnpLShiftTo,
552                _rShiftTo:              bnpRShiftTo,
553                _subTo:                 bnpSubTo,
554                _multiplyTo:    bnpMultiplyTo,
555                _squareTo:              bnpSquareTo,
556                _divRemTo:              bnpDivRemTo,
557                _invDigit:              bnpInvDigit,
558                _isEven:                bnpIsEven,
559                _exp:                   bnpExp,
560
561                // public
562                toString:               bnToString,
563                negate:                 bnNegate,
564                abs:                    bnAbs,
565                compareTo:              bnCompareTo,
566                bitLength:              bnBitLength,
567                mod:                    bnMod,
568                modPowInt:              bnModPowInt
569        });
570
571        dojo._mixin(BigInteger, {
572                // "constants"
573                ZERO:   nbv(0),
574                ONE:    nbv(1),
575
576                // internal functions
577                _nbi: nbi,
578                _nbv: nbv,
579                _nbits: nbits,
580
581                // internal classes
582                _Montgomery: Montgomery
583        });
584
585        // export to DojoX
586        dojox.math.BigInteger = BigInteger;
587
588        return dojox.math.BigInteger;
589});
Note: See TracBrowser for help on using the repository browser.