diff --git a/lib/hdkey.js b/lib/hdkey.js index f48492c..e26c5a5 100644 --- a/lib/hdkey.js +++ b/lib/hdkey.js @@ -1,10 +1,7 @@ var assert = require('assert') var crypto = require('crypto') -var BigInteger = require('bigi') var cs = require('coinstring') -var ecurve = require('ecurve') -var curve = ecurve.getCurveByName('secp256k1') -var Point = ecurve.Point +var secp256k1 = require('secp256k1') var MASTER_SECRET = new Buffer('Bitcoin seed') var HARDENED_OFFSET = 0x80000000 @@ -34,9 +31,10 @@ Object.defineProperty(HDKey.prototype, 'privateKey', { }, set: function (value) { assert.equal(value.length, 32, 'Private key must be 32 bytes.') + assert(secp256k1.privateKeyVerify(value) === true, 'Invalid private key') + this._privateKey = value - this._publicPoint = curve.G.multiply(BigInteger.fromBuffer(this._privateKey)) - this._publicKey = this._publicPoint.getEncoded(true) // force compressed point + this._publicKey = secp256k1.publicKeyCreate(value, true) this._identifier = hash160(this.publicKey) this._fingerprint = this._identifier.slice(0, 4).readUInt32BE(0) } @@ -48,8 +46,9 @@ Object.defineProperty(HDKey.prototype, 'publicKey', { }, set: function (value) { assert(value.length === 33 || value.length === 65, 'Public key must be 33 or 65 bytes.') - this._publicPoint = Point.decodeFrom(curve, value) - this._publicKey = this._publicPoint.getEncoded(true) // force compressed point + assert(secp256k1.publicKeyVerify(value) === true, 'Invalid public key') + + this._publicKey = secp256k1.publicKeyConvert(value, true) // force compressed point this._identifier = hash160(this.publicKey) this._fingerprint = this._identifier.slice(0, 4).readUInt32BE(0) this._privateKey = null @@ -119,33 +118,28 @@ HDKey.prototype.deriveChild = function (index) { var IR = I.slice(32) var hd = new HDKey(this.versions) - var pIL = BigInteger.fromBuffer(IL) // Private parent key -> private child key if (this.privateKey) { // ki = parse256(IL) + kpar (mod n) - var ki = pIL.add(BigInteger.fromBuffer(this.privateKey)).mod(curve.n) - - // In case parse256(IL) >= n or ki == 0, one should proceed with the next value for i - if (pIL.compareTo(curve.n) >= 0 || ki.signum() === 0) { + try { + hd.privateKey = secp256k1.privateKeyTweakAdd(this.privateKey, IL) + // throw if IL >= n || (privateKey + IL) === 0 + } catch (err) { + // In case parse256(IL) >= n or ki == 0, one should proceed with the next value for i return this.derive(index + 1) } - - // if less than 32 bytes, pad with 0's - hd.privateKey = ki.toBuffer(32) - // Public parent key -> public child key } else { // Ki = point(parse256(IL)) + Kpar // = G*IL + Kpar - var Ki = curve.G.multiply(pIL).add(this._publicPoint) - - // In case parse256(IL) >= n or Ki is the point at infinity, one should proceed with the next value for i - if (pIL.compareTo(curve.n) >= 0 || curve.isInfinity(Ki)) { - return this.derive(index + 1) + try { + hd.publicKey = secp256k1.publicKeyTweakAdd(this.publicKey, IL, true) + // throw if IL >= n || (g**IL + publicKey) is infinity + } catch (err) { + // In case parse256(IL) >= n or Ki is the point at infinity, one should proceed with the next value for i + return this.derive(index + 1, isHardened) } - - hd.publicKey = Ki.getEncoded(true) } hd.chainCode = IR diff --git a/package.json b/package.json index 58d11b5..f004d47 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ }, "homepage": "https://github.com/cryptocoinjs/hdkey", "devDependencies": { + "bigi": "^1.1.0", "coveralls": "^2.10.0", + "ecurve": "^1.0.0", "istanbul": "^0.3.17", "mocha": "^2.2.5", "mocha-lcov-reporter": "0.0.1", @@ -30,9 +32,8 @@ "standard": "4.x" }, "dependencies": { - "bigi": "^1.1.0", - "ecurve": "^1.0.0", - "coinstring": "^2.0.0" + "coinstring": "^2.0.0", + "secp256k1": "^3.0.1" }, "scripts": { "browser-test": "mochify --wd -R spec",