make bignum interface backwards compatible

- fix cmp, mul, div, add, mod, sub functions to take numbers and strings
- fix Point class to use common folder correctly
This commit is contained in:
Ryan X. Charles 2014-07-10 18:14:13 -07:00
parent e4cb7d2014
commit af1d754bd8
9 changed files with 1498 additions and 95 deletions

File diff suppressed because one or more lines are too long

View File

@ -3,13 +3,7 @@
var bignum = require('bignum'); var bignum = require('bignum');
var CPPKey = require('bindings')('KeyModule').Key; var CPPKey = require('bindings')('KeyModule').Key;
var assert = require('assert'); var assert = require('assert');
var Point = require('./common/Point');
//a point on the secp256k1 curve
//x and y are bignums
var Point = function(x, y) {
this.x = x;
this.y = y;
};
Point.add = function(p1, p2) { Point.add = function(p1, p2) {
var u1 = p1.toUncompressedPubKey(); var u1 = p1.toUncompressedPubKey();
@ -24,29 +18,4 @@ Point.multiply = function(p1, x) {
return Point.fromUncompressedPubKey(pubKey); return Point.fromUncompressedPubKey(pubKey);
}; };
//convert the public key of a Key into a Point
Point.fromUncompressedPubKey = function(pubkey) {
var point = new Point();
point.x = bignum.fromBuffer(pubkey.slice(1, 33), {
size: 32
});
point.y = bignum.fromBuffer(pubkey.slice(33, 65), {
size: 32
});
return point;
};
//convert the Point into the Key containing a compressed public key
Point.prototype.toUncompressedPubKey = function() {
var xbuf = this.x.toBuffer({
size: 32
});
var ybuf = this.y.toBuffer({
size: 32
});
var prefix = new Buffer([0x04]);
var pubkey = Buffer.concat([prefix, xbuf, ybuf]);
return pubkey;
};
module.exports = (Point); module.exports = (Point);

View File

@ -1,8 +1,6 @@
var bnjs = require('bn.js'); var _bnjs = require('bn.js');
var _bnjs = bnjs; var bnjs = function bnjs_extended(n) {
bnjs = function bnjs_extended(n) {
if (!(this instanceof bnjs_extended)) { if (!(this instanceof bnjs_extended)) {
return new bnjs(n); return new bnjs(n);
} }
@ -75,15 +73,79 @@ bnjs.prototype.toBuffer = function(opts) {
return buf; return buf;
}; };
bnjs.prototype._add = _bnjs.prototype.add;
bnjs.prototype.add = function(b) {
if (typeof b === 'number')
b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this._add(b);
};
bnjs.prototype._sub = _bnjs.prototype.sub;
bnjs.prototype.sub = function(b) {
if (typeof b === 'number')
b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this._sub(b);
};
bnjs.prototype._mul = _bnjs.prototype.mul;
bnjs.prototype.mul = function(b) {
if (typeof b === 'number')
b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this._mul(b);
};
bnjs.prototype._mod = _bnjs.prototype.mod;
bnjs.prototype.mod = function(b) {
if (typeof b === 'number')
b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this._mod(b);
};
bnjs.prototype._div = _bnjs.prototype.div;
bnjs.prototype.div = function(b) {
if (typeof b === 'number')
b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this._div(b);
};
bnjs.prototype._cmp = _bnjs.prototype.cmp;
bnjs.prototype.cmp = function(b) {
if (typeof b === 'number')
b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this._cmp(b);
};
bnjs.prototype.gt = function(b) { bnjs.prototype.gt = function(b) {
if (typeof b === 'number') if (typeof b === 'number')
b = new bnjs(b); b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this.cmp(b) > 0; return this.cmp(b) > 0;
}; };
bnjs.prototype.lt = function(b) { bnjs.prototype.lt = function(b) {
if (typeof b === 'number') if (typeof b === 'number')
b = new bnjs(b); b = b.toString();
if (typeof b === 'number' || typeof b === 'string')
b = new _bnjs(b);
return this.cmp(b) < 0; return this.cmp(b) < 0;
}; };

View File

@ -4,13 +4,7 @@ var Key = require('./Key');
var bignum = require('bignum'); var bignum = require('bignum');
var assert = require('assert'); var assert = require('assert');
var elliptic = require('elliptic'); var elliptic = require('elliptic');
var Point = require('../common/Point');
//a point on the secp256k1 curve
//x and y are bignums
var Point = function(x, y) {
this.x = x;
this.y = y;
};
Point.add = function(p1, p2) { Point.add = function(p1, p2) {
var ec = elliptic.curves.secp256k1; var ec = elliptic.curves.secp256k1;
@ -30,41 +24,4 @@ Point.multiply = function(p1, xbuf) {
return p; return p;
}; };
//convert the public key of a Key into a Point
Point.fromUncompressedPubKey = function(pubkey) {
var point = new Point();
point.x = bignum.fromBuffer((new Buffer(pubkey)).slice(1, 33), {
size: 32
});
point.y = bignum.fromBuffer((new Buffer(pubkey)).slice(33, 65), {
size: 32
});
return point;
};
//convert the Point into the Key containing a compressed public key
Point.prototype.toUncompressedPubKey = function() {
var xbuf = this.x.toBuffer({
size: 32
});
var ybuf = this.y.toBuffer({
size: 32
});
var prefix = new Buffer([0x04]);
var pub = Buffer.concat([prefix, xbuf, ybuf]);
return pub;
};
Point.prototype.toCompressedPubKey = function() {
var xbuf = this.x.toBuffer({size: 32});
var ybuf = this.y.toBuffer({size: 32});
if (ybuf[ybuf.length-1] % 2) { //odd
var pub = Buffer.concat([new Buffer([3]), xbuf]);
}
else { //even
var pub = Buffer.concat([new Buffer([2]), xbuf]);
}
return pub;
};
module.exports = (Point); module.exports = (Point);

46
lib/common/Point.js Normal file
View File

@ -0,0 +1,46 @@
var bignum = require('bignum');
//x and y are both bignums
var Point = function(x, y) {
this.x = x;
this.y = y;
};
//convert the public key of a Key into a Point
Point.fromUncompressedPubKey = function(pubkey) {
var point = new Point();
point.x = bignum.fromBuffer(pubkey.slice(1, 33), {
size: 32
});
point.y = bignum.fromBuffer(pubkey.slice(33, 65), {
size: 32
});
return point;
};
//convert the Point into the Key containing a compressed public key
Point.prototype.toUncompressedPubKey = function() {
var xbuf = this.x.toBuffer({
size: 32
});
var ybuf = this.y.toBuffer({
size: 32
});
var prefix = new Buffer([0x04]);
var pubkey = Buffer.concat([prefix, xbuf, ybuf]);
return pubkey;
};
Point.prototype.toCompressedPubKey = function() {
var xbuf = this.x.toBuffer({size: 32});
var ybuf = this.y.toBuffer({size: 32});
if (ybuf[ybuf.length-1] % 2) { //odd
var pub = Buffer.concat([new Buffer([3]), xbuf]);
}
else { //even
var pub = Buffer.concat([new Buffer([2]), xbuf]);
}
return pub;
};
module.exports = Point;

View File

@ -19,6 +19,11 @@ if (typeof process == 'undefined' || typeof process.versions == 'undefined') {
should.exist(bn); should.exist(bn);
bn.toString().should.equal('50'); bn.toString().should.equal('50');
}); });
it('should parse this number', function() {
var bn = new Bignum(999970000);
bn.toString().should.equal('999970000');
});
describe('#add', function() { describe('#add', function() {

View File

@ -191,7 +191,7 @@ describe('TransactionBuilder', function() {
tx.ins.length.should.equal(2); tx.ins.length.should.equal(2);
tx.outs.length.should.equal(2); tx.outs.length.should.equal(2);
util.valueToBigInt(tx.outs[0].v).cmp(new bignum(8000000)).should.equal(0); util.valueToBigInt(tx.outs[0].v).cmp(8000000).should.equal(0);
// remainder is 0.0299 here because unspent select utxos in order // remainder is 0.0299 here because unspent select utxos in order
//util.valueToBigInt(tx.outs[1].v).cmp(new bignum(2990000)).should.equal(0); //util.valueToBigInt(tx.outs[1].v).cmp(new bignum(2990000)).should.equal(0);
@ -440,7 +440,7 @@ describe('TransactionBuilder', function() {
parseInt(b.remainderSat.toString()).should.equal(parseInt(9.9997 * util.COIN)); parseInt(b.remainderSat.toString()).should.equal(parseInt(9.9997 * util.COIN));
util.valueToBigInt(tx.outs[N].v).cmp(new bignum(999970000)).should.equal(0); util.valueToBigInt(tx.outs[N].v).cmp(999970000).should.equal(0);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
}); });
@ -477,7 +477,7 @@ describe('TransactionBuilder', function() {
// 101 * 0.01 = 1.01BTC; + 0.0004 fee = 1.0104btc // 101 * 0.01 = 1.01BTC; + 0.0004 fee = 1.0104btc
// remainder = 11.0101-1.0104 = 9.9997 // remainder = 11.0101-1.0104 = 9.9997
parseInt(b.remainderSat.toString()).should.equal(parseInt(0.0097 * util.COIN)); parseInt(b.remainderSat.toString()).should.equal(parseInt(0.0097 * util.COIN));
util.valueToBigInt(tx.outs[N].v).cmp(new bignum(970000)).should.equal(0); util.valueToBigInt(tx.outs[N].v).cmp(970000).should.equal(0);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
}); });
@ -859,10 +859,10 @@ describe('TransactionBuilder', function() {
tx.ins.length.should.equal(2); tx.ins.length.should.equal(2);
tx.outs.length.should.equal(2); tx.outs.length.should.equal(2);
util.valueToBigInt(tx.outs[0].v).cmp(new bignum(8000000)).should.equal(0); util.valueToBigInt(tx.outs[0].v).cmp(8000000).should.equal(0);
// remainder is 0.0299 here because unspent select utxos in order // remainder is 0.0299 here because unspent select utxos in order
util.valueToBigInt(tx.outs[1].v).cmp(new bignum(2990000)).should.equal(0); util.valueToBigInt(tx.outs[1].v).cmp(2990000).should.equal(0);
}); });
it('#toObj #fromObj roundtrip, step signatures p2sh/p2pubkeyhash', function() { it('#toObj #fromObj roundtrip, step signatures p2sh/p2pubkeyhash', function() {

View File

@ -84,13 +84,13 @@ describe('Miscelaneous stuff', function() {
should.exist(bitcore.Bignum); should.exist(bitcore.Bignum);
}); });
it('should create a bignum from string', function() { it('should create a bignum from string', function() {
var n = new bignum('9832087987979879879879879879879879879879879879'); var n = bignum('9832087987979879879879879879879879879879879879');
should.exist(n); should.exist(n);
}); });
it('should perform basic math operations for bignum', function() { it('should perform basic math operations for bignum', function() {
var b = new bignum('782910138827292261791972728324982') var b = bignum('782910138827292261791972728324982')
.sub(new bignum('182373273283402171237474774728373')) .sub('182373273283402171237474774728373')
.div(new bignum(13)); .div(13);
b.toNumber().should.equal(46195143503376160811884457968969); b.toNumber().should.equal(46195143503376160811884457968969);
}); });

View File

@ -224,7 +224,7 @@ exports.intToBufferSM = function(v) {
v = new bignum(v); v = new bignum(v);
} }
var b, c; var b, c;
var cmp = v.cmp(new bignum(0)); var cmp = v.cmp(0);
if (cmp > 0) { if (cmp > 0) {
b = v.toBuffer(); b = v.toBuffer();
c = padSign(b); c = padSign(b);
@ -292,7 +292,7 @@ function padFrac(frac) {
} }
function parseFullValue(res) { function parseFullValue(res) {
return new bignum(res[1]).mul(new bignum('100000000')).add(new bignum(padFrac(res[2]))); return new bignum(res[1]).mul('100000000').add(new bignum(padFrac(res[2])));
} }
function parseFracValue(res) { function parseFracValue(res) {
@ -300,7 +300,7 @@ function parseFracValue(res) {
} }
function parseWholeValue(res) { function parseWholeValue(res) {
return new bignum(res[1]).mul(new bignum('100000000')); return new bignum(res[1]).mul('100000000');
} }
exports.parseValue = function parseValue(valueStr) { exports.parseValue = function parseValue(valueStr) {
@ -368,7 +368,7 @@ var decodeDiffBits = exports.decodeDiffBits = function(diffBits, asBigInt) {
var mov = 8 * ((diffBits >>> 24) - 3); var mov = 8 * ((diffBits >>> 24) - 3);
while (mov-- > 0) while (mov-- > 0)
target = target.mul(new bignum(2)); target = target.mul(2);
if (asBigInt) { if (asBigInt) {
return target; return target;