Skip to content

Commit

Permalink
sjcl.bn.power would freeze when not in a field
Browse files Browse the repository at this point in the history
  • Loading branch information
Bren2010 committed Nov 25, 2014
1 parent 1d1bc48 commit b35ee6b
Showing 1 changed file with 46 additions and 56 deletions.
102 changes: 46 additions & 56 deletions core/bn.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ sjcl.bn.prototype = {
radix: 24,
maxMul: 8,
_class: sjcl.bn,

copy: function() {
return new this._class(this);
},
Expand All @@ -24,12 +24,12 @@ sjcl.bn.prototype = {
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 = [];
Expand Down Expand Up @@ -60,14 +60,14 @@ sjcl.bn.prototype = {
}
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.
Expand All @@ -84,7 +84,7 @@ sjcl.bn.prototype = {
}
return (greater | ~less) >>> 31;
},

/**
* Convert to a hex string.
*/
Expand All @@ -100,7 +100,7 @@ sjcl.bn.prototype = {
}
return "0x"+out;
},

/** this += that. Does not normalize. */
addM: function(that) {
if (typeof(that) !== "object") { that = new this._class(that); }
Expand All @@ -113,7 +113,7 @@ sjcl.bn.prototype = {
}
return this;
},

/** this *= 2. Requires normalized; ends up normalized. */
doubleM: function() {
var i, carry=0, tmp, r=this.radix, m=this.radixMask, l=this.limbs;
Expand All @@ -128,7 +128,7 @@ sjcl.bn.prototype = {
}
return this;
},

/** this /= 2, rounded down. Requires normalized; ends up normalized. */
halveM: function() {
var i, carry=0, tmp, r=this.radix, l=this.limbs;
Expand All @@ -155,21 +155,21 @@ sjcl.bn.prototype = {
}
return this;
},

mod: function(that) {
var neg = !this.greaterEquals(new sjcl.bn(0));

that = new sjcl.bn(that).normalize(); // copy before we begin
var out = new sjcl.bn(this).normalize(), ci=0;

if (neg) out = (new sjcl.bn(0)).subM(out).normalize();

for (; out.greaterEquals(that); ci++) {
that.doubleM();
}

if (neg) out = that.sub(out).normalize();

for (; ci > 0; ci--) {
that.halveM();
if (out.greaterEquals(that)) {
Expand All @@ -178,15 +178,15 @@ sjcl.bn.prototype = {
}
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) {
Expand All @@ -197,34 +197,34 @@ sjcl.bn.prototype = {
}
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<x.limbs.length; i++) {
nz |= x.limbs[i];
}
} while(nz);

if (!y.equals(1)) {
throw (new sjcl.exception.invalid("inverseMod: p and x must be relatively prime"));
}

return b;
},

/** this + that. Does not normalize. */
add: function(that) {
return this.copy().addM(that);
Expand All @@ -234,7 +234,7 @@ sjcl.bn.prototype = {
sub: function(that) {
return this.copy().subM(that);
},

/** this * that. Normalizes and reduces. */
mul: function(that) {
if (typeof(that) === "number") { that = new this._class(that); }
Expand All @@ -248,7 +248,7 @@ sjcl.bn.prototype = {
for (j=0; j<bl; j++) {
c[i+j] += ai * b[j];
}

if (!--ii) {
ii = this.maxMul;
out.cnormalize();
Expand All @@ -263,24 +263,15 @@ sjcl.bn.prototype = {
},

/** this ^ n. Uses square-and-multiply. Normalizes and reduces. */
power: function(l) {
if (typeof(l) === "number") {
l = [l];
} else if (l.limbs !== undefined) {
l = l.normalize().limbs;
}
var i, j, out = new this._class(1), pow = this;

for (i=0; i<l.length; i++) {
for (j=0; j<this.radix; j++) {
if (l[i] & (1<<j)) {
out = out.mul(pow);
}
pow = pow.square();
power: function(x) {
var result = new sjcl.bn(1), a = new sjcl.bn(this), k = new sjcl.bn(x);
while (true) {
if (k.limbs[0] & 1) { result = result.mul(a); }
k.halveM();
if (k.equals(0)) { break; }
a = a.mul(a);
}
}

return out;
return result.normalize().reduce();
},

/** this * that mod N */
Expand Down Expand Up @@ -308,7 +299,7 @@ sjcl.bn.prototype = {
l.push(p);
return this;
},

/** Reduce mod a modulus. Stubbed for subclassing. */
reduce: function() {
return this;
Expand All @@ -318,7 +309,7 @@ sjcl.bn.prototype = {
fullReduce: function() {
return this.normalize();
},

/** Propagate carries. */
normalize: function() {
var carry=0, i, pv = this.placeVal, ipv = this.ipv, l, m, limbs = this.limbs, ll = limbs.length, mask = this.radixMask;
Expand All @@ -344,7 +335,7 @@ sjcl.bn.prototype = {
limbs[i] += carry;
return this;
},

/** Serialize to a bit array */
toBits: function(len) {
this.fullReduce();
Expand All @@ -357,7 +348,7 @@ sjcl.bn.prototype = {
}
return out;
},

/** Return the length in bits, rounded up to the nearest byte. */
bitLength: function() {
this.fullReduce();
Expand All @@ -376,7 +367,7 @@ sjcl.bn.prototype = {
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));
Expand All @@ -396,7 +387,7 @@ sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1;
* 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) {
/** @constructor
/** @constructor
* @private
*/
function p(it) {
Expand All @@ -416,7 +407,7 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
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<coeff.length; i++) {
Expand Down Expand Up @@ -444,7 +435,7 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
for (k=0; k<ol; k++) {
limbs[ll+off[k]] -= fac[k] * l;
}

i--;
if (!i) {
limbs.push(0);
Expand All @@ -456,7 +447,7 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {

return this;
};

/** @memberof sjcl.bn
* @this { sjcl.bn }
*/
Expand All @@ -480,15 +471,15 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
ppr.fullReduce = function() {
var greater, i;
// massively above the modulus, may be negative

this._strongReduce();
// less than twice the modulus, may be negative

this.addM(this.modulus);
this.addM(this.modulus);
this.normalize();
// probably 2-3x the modulus

this._strongReduce();
// less than the power of 2. still may be more than
// the modulus
Expand All @@ -497,7 +488,7 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
for (i=this.limbs.length; i<this.modOffset; i++) {
this.limbs[i] = 0;
}

// constant-time subtract modulus
greater = this.greaterEquals(this.modulus);
for (i=0; i<this.limbs.length; i++) {
Expand Down Expand Up @@ -565,4 +556,3 @@ sjcl.bn.random = function(modulus, paranoia) {
}
}
};

0 comments on commit b35ee6b

Please sign in to comment.