Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed both power functions in the BN library. #203

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 61 additions & 53 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 @@ -267,19 +267,19 @@ sjcl.bn.prototype = {
if (typeof(l) === "number") {
l = [l];
} else if (l.limbs !== undefined) {
l = l.normalize().limbs;
l = l.normalize().trim().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);
}
if (l[i] & (1<<j)) { out = out.mul(pow); }
if (i == (l.length - 1) && l[i]>>(j + 1) == 0) { break; }

pow = pow.square();
}
}

return out;
},

Expand All @@ -289,15 +289,24 @@ sjcl.bn.prototype = {
},

/** this ^ x mod N */
powermod: function(x, N) {
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.mulmod(a, N); }
k.halveM();
if (k.equals(0)) { break; }
a = a.mulmod(a, N);
}
return result.normalize().reduce();
powermod: function(l, N) {
if (typeof(l) === "number") {
l = [l];
} else if (l.limbs !== undefined) {
l = l.normalize().trim().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.mulmod(pow, N); }
if (i == (l.length - 1) && l[i]>>(j + 1) == 0) { break; }

pow = pow.mulmod(pow, N);
}
}

return out;
},

trim: function() {
Expand All @@ -308,7 +317,7 @@ sjcl.bn.prototype = {
l.push(p);
return this;
},

/** Reduce mod a modulus. Stubbed for subclassing. */
reduce: function() {
return this;
Expand All @@ -318,7 +327,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 +353,7 @@ sjcl.bn.prototype = {
limbs[i] += carry;
return this;
},

/** Serialize to a bit array */
toBits: function(len) {
this.fullReduce();
Expand All @@ -357,7 +366,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 +385,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 +405,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 +425,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 +453,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 +465,7 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {

return this;
};

/** @memberof sjcl.bn
* @this { sjcl.bn }
*/
Expand All @@ -480,15 +489,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 +506,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 +574,3 @@ sjcl.bn.random = function(modulus, paranoia) {
}
}
};

Loading