Added Jacobi functionality, more bn features - plus tests.

This commit is contained in:
Stefan Thomas
2013-09-19 22:24:36 -07:00
parent 26220239fa
commit 0986b37267
5 changed files with 212 additions and 3 deletions

View File

@@ -45,8 +45,8 @@ sjcl.bn.prototype.div = function (that) {
};
sjcl.bn.prototype.sign = function () {
return this.greaterEquals(sjcl.bn.ZERO) ? 1 : -1;
};
return this.greaterEquals(sjcl.bn.ZERO) ? 1 : -1;
};
/** -this */
sjcl.bn.prototype.neg = function () {
@@ -59,3 +59,79 @@ sjcl.bn.prototype.abs = function () {
return this.neg();
} else return this;
};
/** this >> that */
sjcl.bn.prototype.shiftRight = function (that) {
if ("number" !== typeof that) {
throw new Error("shiftRight expects a number");
}
that = +that;
if (that < 0) {
return this.shiftLeft(that);
}
var a = new sjcl.bn(this);
while (that--) {
a.halveM();
}
return a;
};
/** this >> that */
sjcl.bn.prototype.shiftLeft = function (that) {
if ("number" !== typeof that) {
throw new Error("shiftLeft expects a number");
}
that = +that;
if (that < 0) {
return this.shiftRight(that);
}
var a = new sjcl.bn(this);
while (that--) {
a.doubleM();
}
return a;
};
/** (int)this */
// NOTE Truncates to 32-bit integer
sjcl.bn.prototype.toNumber = function () {
return this.limbs[0] | 0;
};
/** find n-th bit, 0 = LSB */
sjcl.bn.prototype.testBit = function (bitIndex) {
var limbIndex = Math.floor(bitIndex / this.radix);
var bitIndexInLimb = bitIndex % this.radix;
if (limbIndex >= this.limbs.length) return 0;
return (this.limbs[limbIndex] >>> bitIndexInLimb) & 1;
};
/** set n-th bit, 0 = LSB */
sjcl.bn.prototype.setBitM = function (bitIndex) {
var limbIndex = Math.floor(bitIndex / this.radix);
var bitIndexInLimb = bitIndex % this.radix;
while (limbIndex >= this.limbs.length) this.limbs.push(0);
this.limbs[limbIndex] |= 1 << bitIndexInLimb;
this.cnormalize();
return this;
};
sjcl.bn.prototype.modInt = function (n) {
return this.toNumber() % n;
};

View File

@@ -0,0 +1,45 @@
sjcl.bn.prototype.jacobi = function (that) {
var a = this;
that = new sjcl.bn(that);
if (that.sign() === -1) return;
// 1. If a = 0 then return(0).
if (a.equals(0)) { return 0; }
// 2. If a = 1 then return(1).
if (a.equals(1)) { return 1; }
var s = 0;
// 3. Write a = 2^e * a1, where a1 is odd.
var e = 0;
while (!a.testBit(e)) e++;
var a1 = a.shiftRight(e);
// 4. If e is even then set s ← 1.
if ((e & 1) === 0) {
s = 1;
} else {
var residue = that.modInt(8);
if (residue === 1 || residue === 7) {
// Otherwise set s ← 1 if n ≡ 1 or 7 (mod 8)
s = 1;
} else if (residue === 3 || residue === 5) {
// Or set s ← 1 if n ≡ 3 or 5 (mod 8).
s = -1;
}
}
// 5. If n ≡ 3 (mod 4) and a1 ≡ 3 (mod 4) then set s ← s.
if (that.modInt(4) === 3 && a1.modInt(4) === 3) {
s = -s;
}
if (a1.equals(1)) {
return s;
} else {
return s * that.mod(a1).jacobi(a1);
}
};