hash 100% coverage
This commit is contained in:
parent
686bc091ba
commit
aa6ecfd79b
|
@ -4,10 +4,11 @@ var BN = require('./bn');
|
||||||
var Point = require('./point');
|
var Point = require('./point');
|
||||||
var Signature = require('./signature');
|
var Signature = require('./signature');
|
||||||
var PublicKey = require('../publickey');
|
var PublicKey = require('../publickey');
|
||||||
var PrivateKey = require('../privatekey');
|
|
||||||
var Random = require('./random');
|
var Random = require('./random');
|
||||||
var Hash = require('./hash');
|
var Hash = require('./hash');
|
||||||
var BufferUtil = require('../util/buffer');
|
var BufferUtil = require('../util/buffer');
|
||||||
|
var _ = require('lodash');
|
||||||
|
var $ = require('../util/preconditions');
|
||||||
|
|
||||||
var ECDSA = function ECDSA(obj) {
|
var ECDSA = function ECDSA(obj) {
|
||||||
if (!(this instanceof ECDSA)) {
|
if (!(this instanceof ECDSA)) {
|
||||||
|
@ -70,8 +71,13 @@ ECDSA.prototype.randomK = function() {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc6979#section-3.2
|
// https://tools.ietf.org/html/rfc6979#section-3.2
|
||||||
ECDSA.prototype.deterministicK = function(badrs) {
|
ECDSA.prototype.deterministicK = function(badrs) {
|
||||||
|
/* jshint maxstatements: 25 */
|
||||||
|
if (_.isUndefined(badrs)) {
|
||||||
|
badrs = 0;
|
||||||
|
}
|
||||||
var v = new Buffer(32);
|
var v = new Buffer(32);
|
||||||
v.fill(0x01);
|
v.fill(0x01);
|
||||||
var k = new Buffer(32);
|
var k = new Buffer(32);
|
||||||
|
@ -87,11 +93,6 @@ ECDSA.prototype.deterministicK = function(badrs) {
|
||||||
var T = BN.fromBuffer(v);
|
var T = BN.fromBuffer(v);
|
||||||
var N = Point.getN();
|
var N = Point.getN();
|
||||||
|
|
||||||
// if r or s were invalid when this function was used in signing,
|
|
||||||
// we do not want to actually compute r, s here for efficiency, so,
|
|
||||||
// we can increment badrs. explained at end of RFC 6979 section 3.2
|
|
||||||
if (typeof badrs === 'undefined')
|
|
||||||
badrs = 0;
|
|
||||||
// also explained in 3.2, we must ensure T is in the proper range (0, N)
|
// also explained in 3.2, we must ensure T is in the proper range (0, N)
|
||||||
for (var i = 0; i < badrs || !(T.lt(N) && T.gt(0)); i++) {
|
for (var i = 0; i < badrs || !(T.lt(N) && T.gt(0)); i++) {
|
||||||
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00])]), k);
|
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00])]), k);
|
||||||
|
@ -107,10 +108,9 @@ ECDSA.prototype.deterministicK = function(badrs) {
|
||||||
// https://bitcointalk.org/index.php?topic=6430.0
|
// https://bitcointalk.org/index.php?topic=6430.0
|
||||||
// http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k
|
// http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k
|
||||||
ECDSA.prototype.toPublicKey = function() {
|
ECDSA.prototype.toPublicKey = function() {
|
||||||
|
/* jshint maxstatements: 25 */
|
||||||
var i = this.sig.i;
|
var i = this.sig.i;
|
||||||
if (!(i === 0 || i === 1 || i === 2 || i === 3)) {
|
$.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be equal to 0, 1, 2, or 3'));
|
||||||
throw new Error('i must be equal to 0, 1, 2, or 3');
|
|
||||||
}
|
|
||||||
|
|
||||||
var e = BN.fromBuffer(this.hashbuf);
|
var e = BN.fromBuffer(this.hashbuf);
|
||||||
var r = this.sig.r;
|
var r = this.sig.r;
|
||||||
|
@ -153,7 +153,8 @@ ECDSA.prototype.toPublicKey = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
ECDSA.prototype.sigError = function() {
|
ECDSA.prototype.sigError = function() {
|
||||||
if (!Buffer.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) {
|
/* jshint maxstatements: 25 */
|
||||||
|
if (!BufferUtil.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) {
|
||||||
return 'hashbuf must be a 32 byte buffer';
|
return 'hashbuf must be a 32 byte buffer';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,35 +173,29 @@ ECDSA.prototype.sigError = function() {
|
||||||
var u2 = sinv.mul(r).mod(n);
|
var u2 = sinv.mul(r).mod(n);
|
||||||
|
|
||||||
var p = Point.getG().mulAdd(u1, this.pubkey.point, u2);
|
var p = Point.getG().mulAdd(u1, this.pubkey.point, u2);
|
||||||
if (p.isInfinity())
|
if (p.isInfinity()) {
|
||||||
return 'p is infinity';
|
return 'p is infinity';
|
||||||
|
}
|
||||||
|
|
||||||
if (!(p.getX().mod(n).cmp(r) === 0))
|
if (p.getX().mod(n).cmp(r) !== 0) {
|
||||||
return 'Invalid signature';
|
return 'Invalid signature';
|
||||||
else
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ECDSA.prototype.sign = function() {
|
ECDSA.toLowS = function(s) {
|
||||||
var hashbuf = this.hashbuf;
|
//enforce low s
|
||||||
var privkey = this.privkey;
|
//see BIP 62, "low S values in signatures"
|
||||||
|
if (s.gt(BN.fromBuffer(new Buffer('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')))) {
|
||||||
var d = privkey.bn;
|
s = Point.getN().sub(s);
|
||||||
|
|
||||||
if (!hashbuf || !privkey || !d) {
|
|
||||||
throw new Error('invalid parameters');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BufferUtil.isBuffer(hashbuf) || hashbuf.length !== 32) {
|
|
||||||
throw new Error('hashbuf must be a 32 byte buffer');
|
|
||||||
}
|
}
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
ECDSA.prototype._findSignature = function(d, e) {
|
||||||
var N = Point.getN();
|
var N = Point.getN();
|
||||||
var G = Point.getG();
|
var G = Point.getG();
|
||||||
var e = BN.fromBuffer(hashbuf, this.endian ? {
|
|
||||||
endian: this.endian
|
|
||||||
} : undefined);
|
|
||||||
|
|
||||||
// try different values of k until r, s are valid
|
// try different values of k until r, s are valid
|
||||||
var badrs = 0;
|
var badrs = 0;
|
||||||
var k, Q, r, s;
|
var k, Q, r, s;
|
||||||
|
@ -215,17 +210,30 @@ ECDSA.prototype.sign = function() {
|
||||||
s = k.invm(N).mul(e.add(d.mul(r))).mod(N);
|
s = k.invm(N).mul(e.add(d.mul(r))).mod(N);
|
||||||
} while (r.cmp(0) <= 0 || s.cmp(0) <= 0);
|
} while (r.cmp(0) <= 0 || s.cmp(0) <= 0);
|
||||||
|
|
||||||
//enforce low s
|
s = ECDSA.toLowS(s);
|
||||||
//see BIP 62, "low S values in signatures"
|
return {
|
||||||
if (s.gt(BN.fromBuffer(new Buffer('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')))) {
|
|
||||||
s = Point.getN().sub(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sig = new Signature({
|
|
||||||
r: r,
|
|
||||||
s: s,
|
s: s,
|
||||||
compressed: this.pubkey.compressed
|
r: r
|
||||||
});
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ECDSA.prototype.sign = function() {
|
||||||
|
var hashbuf = this.hashbuf;
|
||||||
|
var privkey = this.privkey;
|
||||||
|
var d = privkey.bn;
|
||||||
|
|
||||||
|
$.checkState(hashbuf && privkey && d, new Error('invalid parameters'));
|
||||||
|
$.checkState(BufferUtil.isBuffer(hashbuf) && hashbuf.length === 32, new Error('hashbuf must be a 32 byte buffer'));
|
||||||
|
|
||||||
|
var e = BN.fromBuffer(hashbuf, this.endian ? {
|
||||||
|
endian: this.endian
|
||||||
|
} : undefined);
|
||||||
|
|
||||||
|
var obj = this._findSignature(d, e);
|
||||||
|
obj.compressed = this.pubkey.compressed;
|
||||||
|
|
||||||
|
this.sig = new Signature(obj);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,10 +263,11 @@ ECDSA.prototype.toString = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
ECDSA.prototype.verify = function() {
|
ECDSA.prototype.verify = function() {
|
||||||
if (!this.sigError())
|
if (!this.sigError()) {
|
||||||
this.verified = true;
|
this.verified = true;
|
||||||
else
|
} else {
|
||||||
this.verified = false;
|
this.verified = false;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,121 +10,125 @@ describe('Hash', function() {
|
||||||
|
|
||||||
describe('@sha1', function() {
|
describe('@sha1', function() {
|
||||||
|
|
||||||
it('should calculate the hash of this buffer correctly', function() {
|
it('calculates the hash of this buffer correctly', function() {
|
||||||
var hash = Hash.sha1(buf);
|
var hash = Hash.sha1(buf);
|
||||||
hash.toString('hex').should.equal('de69b8a4a5604d0486e6420db81e39eb464a17b2');
|
hash.toString('hex').should.equal('de69b8a4a5604d0486e6420db81e39eb464a17b2');
|
||||||
hash = Hash.sha1(new Buffer(0));
|
hash = Hash.sha1(new Buffer(0));
|
||||||
hash.toString('hex').should.equal('da39a3ee5e6b4b0d3255bfef95601890afd80709');
|
hash.toString('hex').should.equal('da39a3ee5e6b4b0d3255bfef95601890afd80709');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the input is not a buffer', function() {
|
it('throws an error when the input is not a buffer', function() {
|
||||||
(function() {
|
Hash.sha1.bind(Hash, str).should.throw('Invalid Argument');
|
||||||
Hash.sha1(str);
|
|
||||||
}).should.throw('Invalid Argument');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sha256', function() {
|
describe('#sha256', function() {
|
||||||
|
|
||||||
it('should calculate the hash of this buffer correctly', function() {
|
it('calculates the hash of this buffer correctly', function() {
|
||||||
var hash = Hash.sha256(buf);
|
var hash = Hash.sha256(buf);
|
||||||
hash.toString('hex').should.equal('6f2c7b22fd1626998287b3636089087961091de80311b9279c4033ec678a83e8');
|
hash.toString('hex').should.equal('6f2c7b22fd1626998287b3636089087961091de80311b9279c4033ec678a83e8');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the input is not a buffer', function() {
|
it('fails when the input is not a buffer', function() {
|
||||||
(function() {
|
Hash.sha256.bind(Hash, str).should.throw('Invalid Argument');
|
||||||
Hash.sha256(str);
|
|
||||||
}).should.throw('Invalid Argument');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sha256hmac', function() {
|
describe('#sha256hmac', function() {
|
||||||
|
|
||||||
it('should compute this known empty test vector correctly', function() {
|
it('computes this known big key correctly', function() {
|
||||||
var key = new Buffer('');
|
var key = new Buffer('b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad' +
|
||||||
|
'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad' +
|
||||||
|
'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad' +
|
||||||
|
'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad');
|
||||||
var data = new Buffer('');
|
var data = new Buffer('');
|
||||||
Hash.sha256hmac(data, key).toString('hex').should.equal('b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad');
|
Hash.sha256hmac(data, key).toString('hex')
|
||||||
|
.should.equal('fb1f87218671f1c0c4593a88498e02b6dfe8afd814c1729e89a1f1f6600faa23');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should compute this known non-empty test vector correctly', function() {
|
it('computes this known empty test vector correctly', function() {
|
||||||
|
var key = new Buffer('');
|
||||||
|
var data = new Buffer('');
|
||||||
|
Hash.sha256hmac(data, key).toString('hex')
|
||||||
|
.should.equal('b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('computes this known non-empty test vector correctly', function() {
|
||||||
var key = new Buffer('key');
|
var key = new Buffer('key');
|
||||||
var data = new Buffer('The quick brown fox jumps over the lazy dog');
|
var data = new Buffer('The quick brown fox jumps over the lazy dog');
|
||||||
Hash.sha256hmac(data, key).toString('hex').should.equal('f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8');
|
Hash.sha256hmac(data, key).toString('hex')
|
||||||
|
.should.equal('f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sha256sha256', function() {
|
describe('#sha256sha256', function() {
|
||||||
|
|
||||||
it('should calculate the hash of this buffer correctly', function() {
|
it('calculates the hash of this buffer correctly', function() {
|
||||||
var hash = Hash.sha256sha256(buf);
|
var hash = Hash.sha256sha256(buf);
|
||||||
hash.toString('hex').should.equal('be586c8b20dee549bdd66018c7a79e2b67bb88b7c7d428fa4c970976d2bec5ba');
|
hash.toString('hex').should.equal('be586c8b20dee549bdd66018c7a79e2b67bb88b7c7d428fa4c970976d2bec5ba');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the input is not a buffer', function() {
|
it('fails when the input is not a buffer', function() {
|
||||||
(function() {
|
Hash.sha256sha256.bind(Hash, str).should.throw('Invalid Argument');
|
||||||
Hash.sha256sha256(str);
|
|
||||||
}).should.throw('Invalid Argument');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sha256ripemd160', function() {
|
describe('#sha256ripemd160', function() {
|
||||||
|
|
||||||
it('should calculate the hash of this buffer correctly', function() {
|
it('calculates the hash of this buffer correctly', function() {
|
||||||
var hash = Hash.sha256ripemd160(buf);
|
var hash = Hash.sha256ripemd160(buf);
|
||||||
hash.toString('hex').should.equal('7322e2bd8535e476c092934e16a6169ca9b707ec');
|
hash.toString('hex').should.equal('7322e2bd8535e476c092934e16a6169ca9b707ec');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the input is not a buffer', function() {
|
it('fails when the input is not a buffer', function() {
|
||||||
(function() {
|
Hash.sha256ripemd160.bind(Hash, str).should.throw('Invalid Argument');
|
||||||
Hash.sha256ripemd160(str);
|
|
||||||
}).should.throw('Invalid Argument');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#ripemd160', function() {
|
describe('#ripemd160', function() {
|
||||||
|
|
||||||
it('should calculate the hash of this buffer correctly', function() {
|
it('calculates the hash of this buffer correctly', function() {
|
||||||
var hash = Hash.ripemd160(buf);
|
var hash = Hash.ripemd160(buf);
|
||||||
hash.toString('hex').should.equal('fa0f4565ff776fee0034c713cbf48b5ec06b7f5c');
|
hash.toString('hex').should.equal('fa0f4565ff776fee0034c713cbf48b5ec06b7f5c');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the input is not a buffer', function() {
|
it('fails when the input is not a buffer', function() {
|
||||||
(function() {
|
Hash.ripemd160.bind(Hash, str).should.throw('Invalid Argument');
|
||||||
Hash.ripemd160(str);
|
|
||||||
}).should.throw('Invalid Argument');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sha512', function() {
|
describe('#sha512', function() {
|
||||||
|
|
||||||
it('should calculate the hash of this buffer correctly', function() {
|
it('calculates the hash of this buffer correctly', function() {
|
||||||
var hash = Hash.sha512(buf);
|
var hash = Hash.sha512(buf);
|
||||||
hash.toString('hex').should.equal('c0530aa32048f4904ae162bc14b9eb535eab6c465e960130005feddb71613e7d62aea75f7d3333ba06e805fc8e45681454524e3f8050969fe5a5f7f2392e31d0');
|
hash.toString('hex')
|
||||||
|
.should.equal('c0530aa32048f4904ae162bc14b9eb535eab6c465e960130005fedd' +
|
||||||
|
'b71613e7d62aea75f7d3333ba06e805fc8e45681454524e3f8050969fe5a5f7f2392e31d0');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the input is not a buffer', function() {
|
it('fails when the input is not a buffer', function() {
|
||||||
(function() {
|
Hash.sha512.bind(Hash, str).should.throw('Invalid Argument');
|
||||||
Hash.sha512(str);
|
|
||||||
}).should.throw('Invalid Argument');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sha512hmac', function() {
|
describe('#sha512hmac', function() {
|
||||||
|
|
||||||
it('should calculate this known empty test vector correctly', function() {
|
it('calculates this known empty test vector correctly', function() {
|
||||||
var hex = 'b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47';
|
var hex = 'b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4a' +
|
||||||
|
'c6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47';
|
||||||
Hash.sha512hmac(new Buffer([]), new Buffer([])).toString('hex').should.equal(hex);
|
Hash.sha512hmac(new Buffer([]), new Buffer([])).toString('hex').should.equal(hex);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should calculate this known non-empty test vector correctly', function() {
|
it('calculates this known non-empty test vector correctly', function() {
|
||||||
var hex = 'c40bd7c15aa493b309c940e08a73ffbd28b2e4cb729eb94480d727e4df577b13cc403a78e6150d83595f3b17c4cc331f12ca5952691de3735a63c1d4c69a2bac';
|
var hex = 'c40bd7c15aa493b309c940e08a73ffbd28b2e4cb729eb94480d727e4df577' +
|
||||||
|
'b13cc403a78e6150d83595f3b17c4cc331f12ca5952691de3735a63c1d4c69a2bac';
|
||||||
var data = new Buffer('test1');
|
var data = new Buffer('test1');
|
||||||
var key = new Buffer('test2');
|
var key = new Buffer('test2');
|
||||||
Hash.sha512hmac(data, key).toString('hex').should.equal(hex);
|
Hash.sha512hmac(data, key).toString('hex').should.equal(hex);
|
||||||
|
|
Loading…
Reference in New Issue