/** * Constructs a new bignum from another bignum, a number or a hex string. */ sjcl.bn = function(it) { this.initWith(it); }; sjcl.bn.prototype = { radix: 24, maxMul: 8, _class: sjcl.bn, copy: function() { return new this._class(this); }, /** * Initializes this with it, either as a bn, a number, or a hex string. */ initWith: function(it) { var i=0, k, n, l; switch(typeof it) { case "object": this.limbs = it.limbs.slice(0); break; case "number": this.limbs = [it]; this.normalize(); break; case "string": it = it.replace(/^0x/, ''); this.limbs = []; // hack k = this.radix / 4; for (i=0; i < it.length; i+=k) { this.limbs.push(parseInt(it.substring(Math.max(it.length - i - k, 0), it.length - i),16)); } break; default: this.limbs = [0]; } return this; }, /** * Returns true if "this" and "that" are equal. Calls fullReduce(). * Equality test is in constant time. */ equals: function(that) { if (typeof that === "number") { that = new this._class(that); } var difference = 0, i; this.fullReduce(); that.fullReduce(); for (i = 0; i < this.limbs.length || i < that.limbs.length; i++) { difference |= this.getLimb(i) ^ that.getLimb(i); } return (difference === 0); }, /** * Get the i'th limb of this, zero if i is too large. */ getLimb: function(i) { return (i >= this.limbs.length) ? 0 : this.limbs[i]; }, /** * Constant time comparison function. * Returns 1 if this >= that, or zero otherwise. */ greaterEquals: function(that) { if (typeof that === "number") { that = new this._class(that); } var less = 0, greater = 0, i, a, b; i = Math.max(this.limbs.length, that.limbs.length) - 1; for (; i>= 0; i--) { a = this.getLimb(i); b = that.getLimb(i); greater |= (b - a) & ~less; less |= (a - b) & ~greater; } return (greater | ~less) >>> 31; }, /** * Convert to a hex string. */ toString: function() { this.fullReduce(); var out="", i, s, l = this.limbs; for (i=0; i < this.limbs.length; i++) { s = l[i].toString(16); while (i < this.limbs.length - 1 && s.length < 6) { s = "0" + s; } out = s + out; } return "0x"+out; }, /** this += that. Does not normalize. */ addM: function(that) { if (typeof(that) !== "object") { that = new this._class(that); } var i, l=this.limbs, ll=that.limbs; for (i=l.length; i> r; } if (carry) { l.push(carry); } return this; }, /** this /= 2, rounded down. Requires normalized; ends up normalized. */ halveM: function() { var i, carry=0, tmp, r=this.radix, l=this.limbs; for (i=l.length-1; i>=0; i--) { tmp = l[i]; l[i] = (tmp+carry)>>1; carry = (tmp&1) << r; } if (!l[l.length-1]) { l.pop(); } return this; }, /** this -= that. Does not normalize. */ subM: function(that) { if (typeof(that) !== "object") { that = new this._class(that); } var i, l=this.limbs, ll=that.limbs; for (i=l.length; i 0; ci--) { that.halveM(); if (out.greaterEquals(that)) { out.subM(that).normalize(); } } return out.trim(); }, /** return inverse mod prime p. p must be odd. Binary extended Euclidean algorithm mod p. */ inverseMod: function(p) { var a = new sjcl.bn(1), b = new sjcl.bn(0), x = new sjcl.bn(this), y = new sjcl.bn(p), tmp, i, nz=1; if (!(p.limbs[0] & 1)) { throw (new sjcl.exception.invalid("inverseMod: p must be odd")); } // invariant: y is odd do { if (x.limbs[0] & 1) { if (!x.greaterEquals(y)) { // x < y; swap everything tmp = x; x = y; y = tmp; tmp = a; a = b; b = tmp; } x.subM(y); x.normalize(); if (!a.greaterEquals(b)) { a.addM(p); } a.subM(b); } // cut everything in half x.halveM(); if (a.limbs[0] & 1) { a.addM(p); } a.normalize(); a.halveM(); // check for termination: x ?= 0 for (i=nz=0; i= 0; i--) { out = w.concat(out, [w.partial(this.radix, this.getLimb(i))]); } return out; }, /** Return the length in bits, rounded up to the nearest byte. */ bitLength: function() { this.fullReduce(); var out = this.radix * (this.limbs.length - 1), b = this.limbs[this.limbs.length - 1]; for (; b; b >>= 1) { out ++; } return out+7 & -8; } }; sjcl.bn.fromBits = function(bits) { var Class = this, out = new Class(), words=[], w=sjcl.bitArray, t = this.prototype, l = Math.min(this.bitLength || 0x100000000, w.bitLength(bits)), e = l % t.radix || t.radix; words[0] = w.extract(bits, 0, e); for (; e < l; e += t.radix) { words.unshift(w.extract(bits, e, t.radix)); } out.limbs = words; return out; }; sjcl.bn.prototype.ipv = 1 / (sjcl.bn.prototype.placeVal = Math.pow(2,sjcl.bn.prototype.radix)); sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1; /** * Creates a new subclass of bn, based on reduction modulo a pseudo-Mersenne prime, * i.e. a prime of the form 2^e + sum(a * 2^b),where the sum is negative and sparse. */ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) { function p(it) { this.initWith(it); /*if (this.limbs[this.modOffset]) { this.reduce(); }*/ } var ppr = p.prototype = new sjcl.bn(), i, tmp, mo; mo = ppr.modOffset = Math.ceil(tmp = exponent / ppr.radix); ppr.exponent = exponent; ppr.offset = []; ppr.factor = []; ppr.minOffset = mo; ppr.fullMask = 0; ppr.fullOffset = []; ppr.fullFactor = []; ppr.modulus = p.modulus = new sjcl.bn(Math.pow(2,exponent)); ppr.fullMask = 0|-Math.pow(2, exponent % ppr.radix); for (i=0; i mo) { l = limbs.pop(); ll = limbs.length; for (k=0; k