434 lines
10 KiB
JavaScript
434 lines
10 KiB
JavaScript
try {
|
|
var cc = new require('./build/Debug/bignum');
|
|
} catch(e) {
|
|
var cc = new require('./build/Release/bignum');
|
|
}
|
|
var BigNum = cc.BigNum;
|
|
|
|
module.exports = BigNum;
|
|
|
|
BigNum.conditionArgs = function(num, base) {
|
|
if (typeof num !== 'string') num = num.toString(base || 10);
|
|
|
|
if (num.match(/e\+/)) { // positive exponent
|
|
if (!Number(num).toString().match(/e\+/)) {
|
|
return {
|
|
num: Math.floor(Number(num)).toString(),
|
|
base: 10
|
|
};
|
|
}
|
|
else {
|
|
var pow = Math.ceil(Math.log(num) / Math.log(2));
|
|
var n = (num / Math.pow(2, pow)).toString(2)
|
|
.replace(/^0/,'');
|
|
var i = n.length - n.indexOf('.');
|
|
n = n.replace(/\./,'');
|
|
|
|
for (; i <= pow; i++) n += '0';
|
|
return {
|
|
num : n,
|
|
base : 2,
|
|
};
|
|
}
|
|
}
|
|
else if (num.match(/e\-/)) { // negative exponent
|
|
return {
|
|
num : Math.floor(Number(num)).toString(),
|
|
base : base || 10
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
num : num,
|
|
base : base || 10,
|
|
};
|
|
}
|
|
};
|
|
|
|
cc.setJSConditioner(BigNum.conditionArgs);
|
|
|
|
BigNum.prototype.inspect = function () {
|
|
return '<BigNum ' + this.toString(10) + '>';
|
|
};
|
|
|
|
BigNum.prototype.toString = function (base) {
|
|
var value;
|
|
if (base) {
|
|
value = this.tostring(base);
|
|
} else {
|
|
value = this.tostring();
|
|
}
|
|
if (base > 10 && "string" === typeof value) {
|
|
value = value.toLowerCase();
|
|
}
|
|
return value;
|
|
};
|
|
|
|
BigNum.prototype.toNumber = function () {
|
|
return parseInt(this.toString(), 10);
|
|
};
|
|
|
|
[ 'add', 'sub', 'mul', 'div', 'mod' ].forEach(function (op) {
|
|
BigNum.prototype[op] = function (num) {
|
|
if (num instanceof BigNum) {
|
|
return this['b'+op](num);
|
|
}
|
|
else if (typeof num === 'number') {
|
|
if (num >= 0) {
|
|
return this['u'+op](num);
|
|
}
|
|
else if (op === 'add') {
|
|
return this.usub(-num);
|
|
}
|
|
else if (op === 'sub') {
|
|
return this.uadd(-num);
|
|
}
|
|
else {
|
|
var x = BigNum(num);
|
|
return this['b'+op](x);
|
|
}
|
|
}
|
|
else if (typeof num === 'string') {
|
|
var x = BigNum(num);
|
|
return this['b'+op](x);
|
|
}
|
|
else {
|
|
throw new TypeError('Unspecified operation for type '
|
|
+ (typeof num) + ' for ' + op);
|
|
}
|
|
};
|
|
});
|
|
|
|
BigNum.prototype.abs = function () {
|
|
return this.babs();
|
|
};
|
|
|
|
BigNum.prototype.neg = function () {
|
|
return this.bneg();
|
|
};
|
|
|
|
BigNum.prototype.powm = function (num, mod) {
|
|
var m, res;
|
|
|
|
if ((typeof mod) === 'number' || (typeof mod) === 'string') {
|
|
m = BigNum(mod);
|
|
}
|
|
else if (mod instanceof BigNum) {
|
|
m = mod;
|
|
}
|
|
|
|
if ((typeof num) === 'number') {
|
|
return this.upowm(num, m);
|
|
}
|
|
else if ((typeof num) === 'string') {
|
|
var n = BigNum(num);
|
|
return this.bpowm(n, m);
|
|
}
|
|
else if (num instanceof BigNum) {
|
|
return this.bpowm(num, m);
|
|
}
|
|
};
|
|
|
|
BigNum.prototype.mod = function (num, mod) {
|
|
var m, res;
|
|
|
|
if ((typeof mod) === 'number' || (typeof mod) === 'string') {
|
|
m = BigNum(mod);
|
|
}
|
|
else if (mod instanceof BigNum) {
|
|
m = mod;
|
|
}
|
|
|
|
if ((typeof num) === 'number') {
|
|
return this.umod(num, m);
|
|
}
|
|
else if ((typeof num) === 'string') {
|
|
var n = BigNum(num);
|
|
return this.bmod(n, m);
|
|
}
|
|
else if (num instanceof BigNum) {
|
|
return this.bmod(num, m);
|
|
}
|
|
};
|
|
|
|
|
|
BigNum.prototype.pow = function (num) {
|
|
if (typeof num === 'number') {
|
|
if (num >= 0) {
|
|
return this.upow(num);
|
|
}
|
|
else {
|
|
return BigNum.prototype.powm.call(this, num, this);
|
|
}
|
|
}
|
|
else {
|
|
var x = parseInt(num.toString(), 10);
|
|
return BigNum.prototype.pow.call(this, x);
|
|
}
|
|
};
|
|
|
|
BigNum.prototype.shiftLeft = function (num) {
|
|
if (typeof num === 'number') {
|
|
if (num >= 0) {
|
|
return this.umul2exp(num);
|
|
}
|
|
else {
|
|
return this.shiftRight(-num);
|
|
}
|
|
}
|
|
else {
|
|
var x = parseInt(num.toString(), 10);
|
|
return BigNum.prototype.shiftLeft.call(this, x);
|
|
}
|
|
};
|
|
|
|
BigNum.prototype.shiftRight = function (num) {
|
|
if (typeof num === 'number') {
|
|
if (num >= 0) {
|
|
return this.udiv2exp(num);
|
|
}
|
|
else {
|
|
return this.shiftLeft(-num);
|
|
}
|
|
}
|
|
else {
|
|
var x = parseInt(num.toString(), 10);
|
|
return BigNum.prototype.shiftRight.call(this, x);
|
|
}
|
|
};
|
|
|
|
BigNum.prototype.cmp = function (num) {
|
|
if (num instanceof BigNum) {
|
|
return this.bcompare(num);
|
|
}
|
|
else if (typeof num === 'number') {
|
|
if (num < 0) {
|
|
return this.scompare(num);
|
|
}
|
|
else {
|
|
return this.ucompare(num);
|
|
}
|
|
}
|
|
else {
|
|
var x = BigNum(num);
|
|
return this.bcompare(x);
|
|
}
|
|
};
|
|
|
|
BigNum.prototype.gt = function (num) {
|
|
return this.cmp(num) > 0;
|
|
};
|
|
|
|
BigNum.prototype.ge = function (num) {
|
|
return this.cmp(num) >= 0;
|
|
};
|
|
|
|
BigNum.prototype.eq = function (num) {
|
|
return this.cmp(num) === 0;
|
|
};
|
|
|
|
BigNum.prototype.ne = function (num) {
|
|
return this.cmp(num) !== 0;
|
|
};
|
|
|
|
BigNum.prototype.lt = function (num) {
|
|
return this.cmp(num) < 0;
|
|
};
|
|
|
|
BigNum.prototype.le = function (num) {
|
|
return this.cmp(num) <= 0;
|
|
};
|
|
|
|
'and or xor'.split(' ').forEach(function (name) {
|
|
BigNum.prototype[name] = function (num) {
|
|
if (num instanceof BigNum) {
|
|
return this['b' + name](num);
|
|
}
|
|
else {
|
|
var x = BigNum(num);
|
|
return this['b' + name](x);
|
|
}
|
|
};
|
|
});
|
|
|
|
BigNum.prototype.sqrt = function() {
|
|
return this.bsqrt();
|
|
};
|
|
|
|
BigNum.prototype.root = function(num) {
|
|
if (num instanceof BigNum) {
|
|
return this.broot(num);
|
|
}
|
|
else {
|
|
var x = BigNum(num);
|
|
return this.broot(num);
|
|
}
|
|
};
|
|
|
|
BigNum.prototype.rand = function (to) {
|
|
if (to === undefined) {
|
|
if (this.toString() === '1') {
|
|
return BigNum(0);
|
|
}
|
|
else {
|
|
return this.brand0();
|
|
}
|
|
}
|
|
else {
|
|
var x = to instanceof BigNum
|
|
? to.sub(this)
|
|
: BigNum(to).sub(this);
|
|
return x.brand0().add(this);
|
|
}
|
|
};
|
|
|
|
BigNum.prototype.invertm = function (mod) {
|
|
if (mod instanceof BigNum) {
|
|
return this.binvertm(mod);
|
|
}
|
|
else {
|
|
var x = BigNum(mod);
|
|
return this.binvertm(x);
|
|
}
|
|
};
|
|
|
|
BigNum.prime = function (bits, safe) {
|
|
if ("undefined" === typeof safe) {
|
|
safe = true;
|
|
}
|
|
|
|
// Force uint32
|
|
bits >>>= 0;
|
|
|
|
return BigNum.uprime0(bits, !!safe);
|
|
};
|
|
|
|
BigNum.prototype.probPrime = function (reps) {
|
|
var n = this.probprime(reps || 10);
|
|
return { 1 : true, 0 : false }[n];
|
|
};
|
|
|
|
BigNum.prototype.nextPrime = function () {
|
|
var num = this;
|
|
do {
|
|
num = num.add(1);
|
|
} while (!num.probPrime());
|
|
return num;
|
|
};
|
|
|
|
BigNum.fromBuffer = function (buf, opts) {
|
|
if (!opts) opts = {};
|
|
|
|
var endian = { 1 : 'big', '-1' : 'little' }[opts.endian]
|
|
|| opts.endian || 'big'
|
|
;
|
|
|
|
var size = opts.size === 'auto' ? Math.ceil(buf.length) : (opts.size || 1);
|
|
|
|
if (buf.length % size !== 0) {
|
|
throw new RangeError('Buffer length (' + buf.length + ')'
|
|
+ ' must be a multiple of size (' + size + ')'
|
|
);
|
|
}
|
|
|
|
var hex = [];
|
|
for (var i = 0; i < buf.length; i += size) {
|
|
var chunk = [];
|
|
for (var j = 0; j < size; j++) {
|
|
chunk.push(buf[
|
|
i + (endian === 'big' ? j : (size - j - 1))
|
|
]);
|
|
}
|
|
|
|
hex.push(chunk
|
|
.map(function (c) {
|
|
return (c < 16 ? '0' : '') + c.toString(16);
|
|
})
|
|
.join('')
|
|
);
|
|
}
|
|
|
|
return BigNum(hex.join(''), 16);
|
|
};
|
|
|
|
BigNum.prototype.toBuffer = function (opts) {
|
|
if (typeof opts === 'string') {
|
|
if (opts !== 'mpint') return 'Unsupported Buffer representation';
|
|
|
|
var abs = this.abs();
|
|
var buf = abs.toBuffer({ size : 1, endian : 'big' });
|
|
var len = buf.length === 1 && buf[0] === 0 ? 0 : buf.length;
|
|
if (buf[0] & 0x80) len ++;
|
|
|
|
var ret = new Buffer(4 + len);
|
|
if (len > 0) buf.copy(ret, 4 + (buf[0] & 0x80 ? 1 : 0));
|
|
if (buf[0] & 0x80) ret[4] = 0;
|
|
|
|
ret[0] = len & (0xff << 24);
|
|
ret[1] = len & (0xff << 16);
|
|
ret[2] = len & (0xff << 8);
|
|
ret[3] = len & (0xff << 0);
|
|
|
|
// two's compliment for negative integers:
|
|
var isNeg = this.lt(0);
|
|
if (isNeg) {
|
|
for (var i = 4; i < ret.length; i++) {
|
|
ret[i] = 0xff - ret[i];
|
|
}
|
|
}
|
|
ret[4] = (ret[4] & 0x7f) | (isNeg ? 0x80 : 0);
|
|
if (isNeg) ret[ret.length - 1] ++;
|
|
|
|
return ret;
|
|
}
|
|
|
|
if (!opts) opts = {};
|
|
|
|
var endian = { 1 : 'big', '-1' : 'little' }[opts.endian]
|
|
|| opts.endian || 'big'
|
|
;
|
|
|
|
var hex = this.toString(16);
|
|
if (hex.charAt(0) === '-') throw new Error(
|
|
'converting negative numbers to Buffers not supported yet'
|
|
);
|
|
|
|
var size = opts.size === 'auto' ? Math.ceil(hex.length / 2) : (opts.size || 1);
|
|
|
|
var len = Math.ceil(hex.length / (2 * size)) * size;
|
|
var buf = new Buffer(len);
|
|
|
|
// zero-pad the hex string so the chunks are all `size` long
|
|
while (hex.length < 2 * len) hex = '0' + hex;
|
|
|
|
var hx = hex
|
|
.split(new RegExp('(.{' + (2 * size) + '})'))
|
|
.filter(function (s) { return s.length > 0 })
|
|
;
|
|
|
|
hx.forEach(function (chunk, i) {
|
|
for (var j = 0; j < size; j++) {
|
|
var ix = i * size + (endian === 'big' ? j : size - j - 1);
|
|
buf[ix] = parseInt(chunk.slice(j*2,j*2+2), 16);
|
|
}
|
|
});
|
|
|
|
return buf;
|
|
};
|
|
|
|
Object.keys(BigNum.prototype).forEach(function (name) {
|
|
if (name === 'inspect' || name === 'toString') return;
|
|
|
|
BigNum[name] = function (num) {
|
|
var args = [].slice.call(arguments, 1);
|
|
|
|
if (num instanceof BigNum) {
|
|
return num[name].apply(num, args);
|
|
}
|
|
else {
|
|
var bigi = BigNum(num);
|
|
return bigi[name].apply(bigi, args);
|
|
}
|
|
};
|
|
});
|