From 884f3fd57d910637c7ae8ea8219d261571458cd9 Mon Sep 17 00:00:00 2001
From: Daniel Cousens <github@dcousens.com>
Date: Tue, 15 May 2018 22:17:46 +1000
Subject: [PATCH] rm HDNode, use bip32 module

---
 README.md                  |   3 -
 package.json               |   3 +
 src/hdnode.js              | 316 -----------------------------
 src/index.js               |   9 +-
 test/fixtures/hdnode.json  | 327 ------------------------------
 test/hdnode.js             | 397 -------------------------------------
 test/integration/bip32.js  |  47 +++--
 test/integration/crypto.js |  28 ++-
 8 files changed, 47 insertions(+), 1083 deletions(-)
 delete mode 100644 src/hdnode.js
 delete mode 100644 test/fixtures/hdnode.json
 delete mode 100644 test/hdnode.js

diff --git a/README.md b/README.md
index dfe8b7f..14faf3d 100644
--- a/README.md
+++ b/README.md
@@ -86,9 +86,6 @@ npm install @types/bitcoinjs-lib
 ```
 
 You can now use `bitcoinjs-lib` as a typescript compliant library.
-``` javascript
-import { HDNode, Transaction } from 'bitcoinjs-lib'
-```
 
 For VSCode (and other editors), users are advised to install the type declarations, as Intellisense uses that information to help you code (autocompletion, static analysis).
 
diff --git a/package.json b/package.json
index 0b73b4e..254289f 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
   "dependencies": {
     "bech32": "^1.1.2",
     "bigi": "^1.4.0",
+    "bip32": "0.0.3",
     "bip66": "^1.1.0",
     "bitcoin-ops": "^1.3.0",
     "bs58check": "^2.0.0",
@@ -42,11 +43,13 @@
     "pushdata-bitcoin": "^1.0.1",
     "randombytes": "^2.0.1",
     "safe-buffer": "^5.1.1",
+    "tiny-secp256k1": "0.0.5",
     "typeforce": "^1.11.3",
     "varuint-bitcoin": "^1.0.4",
     "wif": "^2.0.1"
   },
   "devDependencies": {
+    "bigi": "^1.4.2",
     "bip39": "^2.3.0",
     "bip65": "^1.0.1",
     "bs58": "^4.0.0",
diff --git a/src/hdnode.js b/src/hdnode.js
deleted file mode 100644
index a96b20c..0000000
--- a/src/hdnode.js
+++ /dev/null
@@ -1,316 +0,0 @@
-var Buffer = require('safe-buffer').Buffer
-var base58check = require('bs58check')
-var bcrypto = require('./crypto')
-var createHmac = require('create-hmac')
-var typeforce = require('typeforce')
-var types = require('./types')
-var NETWORKS = require('./networks')
-
-var BigInteger = require('bigi')
-var ECPair = require('./ecpair')
-
-var ecurve = require('ecurve')
-var curve = ecurve.getCurveByName('secp256k1')
-
-function HDNode (keyPair, chainCode) {
-  typeforce(types.tuple('ECPair', types.Buffer256bit), arguments)
-
-  if (!keyPair.compressed) throw new TypeError('BIP32 only allows compressed keyPairs')
-
-  this.keyPair = keyPair
-  this.chainCode = chainCode
-  this.depth = 0
-  this.index = 0
-  this.parentFingerprint = 0x00000000
-}
-
-HDNode.HIGHEST_BIT = 0x80000000
-HDNode.LENGTH = 78
-HDNode.MASTER_SECRET = Buffer.from('Bitcoin seed', 'utf8')
-
-HDNode.fromSeedBuffer = function (seed, network) {
-  typeforce(types.tuple(types.Buffer, types.maybe(types.Network)), arguments)
-
-  if (seed.length < 16) throw new TypeError('Seed should be at least 128 bits')
-  if (seed.length > 64) throw new TypeError('Seed should be at most 512 bits')
-
-  var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest()
-  var IL = I.slice(0, 32)
-  var IR = I.slice(32)
-
-  // In case IL is 0 or >= n, the master key is invalid
-  // This is handled by the ECPair constructor
-  var pIL = BigInteger.fromBuffer(IL)
-  var keyPair = new ECPair(pIL, null, {
-    network: network
-  })
-
-  return new HDNode(keyPair, IR)
-}
-
-HDNode.fromSeedHex = function (hex, network) {
-  return HDNode.fromSeedBuffer(Buffer.from(hex, 'hex'), network)
-}
-
-HDNode.fromBase58 = function (string, networks) {
-  var buffer = base58check.decode(string)
-  if (buffer.length !== 78) throw new Error('Invalid buffer length')
-
-  // 4 bytes: version bytes
-  var version = buffer.readUInt32BE(0)
-  var network
-
-  // list of networks?
-  if (Array.isArray(networks)) {
-    network = networks.filter(function (x) {
-      return version === x.bip32.private ||
-             version === x.bip32.public
-    }).pop()
-
-    if (!network) throw new Error('Unknown network version')
-
-  // otherwise, assume a network object (or default to bitcoin)
-  } else {
-    network = networks || NETWORKS.bitcoin
-  }
-
-  if (version !== network.bip32.private &&
-    version !== network.bip32.public) throw new Error('Invalid network version')
-
-  // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ...
-  var depth = buffer[4]
-
-  // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
-  var parentFingerprint = buffer.readUInt32BE(5)
-  if (depth === 0) {
-    if (parentFingerprint !== 0x00000000) throw new Error('Invalid parent fingerprint')
-  }
-
-  // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
-  // This is encoded in MSB order. (0x00000000 if master key)
-  var index = buffer.readUInt32BE(9)
-  if (depth === 0 && index !== 0) throw new Error('Invalid index')
-
-  // 32 bytes: the chain code
-  var chainCode = buffer.slice(13, 45)
-  var keyPair
-
-  // 33 bytes: private key data (0x00 + k)
-  if (version === network.bip32.private) {
-    if (buffer.readUInt8(45) !== 0x00) throw new Error('Invalid private key')
-
-    var d = BigInteger.fromBuffer(buffer.slice(46, 78))
-    keyPair = new ECPair(d, null, { network: network })
-
-  // 33 bytes: public key data (0x02 + X or 0x03 + X)
-  } else {
-    var Q = ecurve.Point.decodeFrom(curve, buffer.slice(45, 78))
-    // Q.compressed is assumed, if somehow this assumption is broken, `new HDNode` will throw
-
-    // Verify that the X coordinate in the public point corresponds to a point on the curve.
-    // If not, the extended public key is invalid.
-    curve.validate(Q)
-
-    keyPair = new ECPair(null, Q, { network: network })
-  }
-
-  var hd = new HDNode(keyPair, chainCode)
-  hd.depth = depth
-  hd.index = index
-  hd.parentFingerprint = parentFingerprint
-
-  return hd
-}
-
-HDNode.prototype.getAddress = function () {
-  return this.keyPair.getAddress()
-}
-
-HDNode.prototype.getIdentifier = function () {
-  return bcrypto.hash160(this.keyPair.getPublicKeyBuffer())
-}
-
-HDNode.prototype.getFingerprint = function () {
-  return this.getIdentifier().slice(0, 4)
-}
-
-HDNode.prototype.getNetwork = function () {
-  return this.keyPair.getNetwork()
-}
-
-HDNode.prototype.getPublicKeyBuffer = function () {
-  return this.keyPair.getPublicKeyBuffer()
-}
-
-HDNode.prototype.neutered = function () {
-  var neuteredKeyPair = new ECPair(null, this.keyPair.Q, {
-    network: this.keyPair.network
-  })
-
-  var neutered = new HDNode(neuteredKeyPair, this.chainCode)
-  neutered.depth = this.depth
-  neutered.index = this.index
-  neutered.parentFingerprint = this.parentFingerprint
-
-  return neutered
-}
-
-HDNode.prototype.sign = function (hash) {
-  return this.keyPair.sign(hash)
-}
-
-HDNode.prototype.verify = function (hash, signature) {
-  return this.keyPair.verify(hash, signature)
-}
-
-HDNode.prototype.toBase58 = function (__isPrivate) {
-  if (__isPrivate !== undefined) throw new TypeError('Unsupported argument in 2.0.0')
-
-  // Version
-  var network = this.keyPair.network
-  var version = (!this.isNeutered()) ? network.bip32.private : network.bip32.public
-  var buffer = Buffer.allocUnsafe(78)
-
-  // 4 bytes: version bytes
-  buffer.writeUInt32BE(version, 0)
-
-  // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ....
-  buffer.writeUInt8(this.depth, 4)
-
-  // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
-  buffer.writeUInt32BE(this.parentFingerprint, 5)
-
-  // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
-  // This is encoded in big endian. (0x00000000 if master key)
-  buffer.writeUInt32BE(this.index, 9)
-
-  // 32 bytes: the chain code
-  this.chainCode.copy(buffer, 13)
-
-  // 33 bytes: the public key or private key data
-  if (!this.isNeutered()) {
-    // 0x00 + k for private keys
-    buffer.writeUInt8(0, 45)
-    this.keyPair.d.toBuffer(32).copy(buffer, 46)
-
-  // 33 bytes: the public key
-  } else {
-    // X9.62 encoding for public keys
-    this.keyPair.getPublicKeyBuffer().copy(buffer, 45)
-  }
-
-  return base58check.encode(buffer)
-}
-
-// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions
-HDNode.prototype.derive = function (index) {
-  typeforce(types.UInt32, index)
-
-  var isHardened = index >= HDNode.HIGHEST_BIT
-  var data = Buffer.allocUnsafe(37)
-
-  // Hardened child
-  if (isHardened) {
-    if (this.isNeutered()) throw new TypeError('Could not derive hardened child key')
-
-    // data = 0x00 || ser256(kpar) || ser32(index)
-    data[0] = 0x00
-    this.keyPair.d.toBuffer(32).copy(data, 1)
-    data.writeUInt32BE(index, 33)
-
-  // Normal child
-  } else {
-    // data = serP(point(kpar)) || ser32(index)
-    //      = serP(Kpar) || ser32(index)
-    this.keyPair.getPublicKeyBuffer().copy(data, 0)
-    data.writeUInt32BE(index, 33)
-  }
-
-  var I = createHmac('sha512', this.chainCode).update(data).digest()
-  var IL = I.slice(0, 32)
-  var IR = I.slice(32)
-
-  var pIL = BigInteger.fromBuffer(IL)
-
-  // In case parse256(IL) >= n, proceed with the next value for i
-  if (pIL.compareTo(curve.n) >= 0) {
-    return this.derive(index + 1)
-  }
-
-  // Private parent key -> private child key
-  var derivedKeyPair
-  if (!this.isNeutered()) {
-    // ki = parse256(IL) + kpar (mod n)
-    var ki = pIL.add(this.keyPair.d).mod(curve.n)
-
-    // In case ki == 0, proceed with the next value for i
-    if (ki.signum() === 0) {
-      return this.derive(index + 1)
-    }
-
-    derivedKeyPair = new ECPair(ki, null, {
-      network: this.keyPair.network
-    })
-
-  // Public parent key -> public child key
-  } else {
-    // Ki = point(parse256(IL)) + Kpar
-    //    = G*IL + Kpar
-    var Ki = curve.G.multiply(pIL).add(this.keyPair.Q)
-
-    // In case Ki is the point at infinity, proceed with the next value for i
-    if (curve.isInfinity(Ki)) {
-      return this.derive(index + 1)
-    }
-
-    derivedKeyPair = new ECPair(null, Ki, {
-      network: this.keyPair.network
-    })
-  }
-
-  var hd = new HDNode(derivedKeyPair, IR)
-  hd.depth = this.depth + 1
-  hd.index = index
-  hd.parentFingerprint = this.getFingerprint().readUInt32BE(0)
-
-  return hd
-}
-
-HDNode.prototype.deriveHardened = function (index) {
-  typeforce(types.UInt31, index)
-
-  // Only derives hardened private keys by default
-  return this.derive(index + HDNode.HIGHEST_BIT)
-}
-
-// Private === not neutered
-// Public === neutered
-HDNode.prototype.isNeutered = function () {
-  return !(this.keyPair.d)
-}
-
-HDNode.prototype.derivePath = function (path) {
-  typeforce(types.BIP32Path, path)
-
-  var splitPath = path.split('/')
-  if (splitPath[0] === 'm') {
-    if (this.parentFingerprint) {
-      throw new Error('Not a master node')
-    }
-
-    splitPath = splitPath.slice(1)
-  }
-
-  return splitPath.reduce(function (prevHd, indexStr) {
-    var index
-    if (indexStr.slice(-1) === "'") {
-      index = parseInt(indexStr.slice(0, -1), 10)
-      return prevHd.deriveHardened(index)
-    } else {
-      index = parseInt(indexStr, 10)
-      return prevHd.derive(index)
-    }
-  }, this)
-}
-
-module.exports = HDNode
diff --git a/src/index.js b/src/index.js
index e0c58cb..e1876f0 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,18 +1,17 @@
-var script = require('./script')
-
-var templates = require('./templates')
-for (var key in templates) {
+let script = require('./script')
+let templates = require('./templates')
+for (let key in templates) {
   script[key] = templates[key]
 }
 
 module.exports = {
   Block: require('./block'),
   ECPair: require('./ecpair'),
-  HDNode: require('./hdnode'),
   Transaction: require('./transaction'),
   TransactionBuilder: require('./transaction_builder'),
 
   address: require('./address'),
+  bip32: require('bip32'),
   crypto: require('./crypto'),
   networks: require('./networks'),
   opcodes: require('bitcoin-ops'),
diff --git a/test/fixtures/hdnode.json b/test/fixtures/hdnode.json
deleted file mode 100644
index 56e97d6..0000000
--- a/test/fixtures/hdnode.json
+++ /dev/null
@@ -1,327 +0,0 @@
-{
-  "valid": [
-    {
-      "network": "bitcoin",
-      "master": {
-        "seed": "000102030405060708090a0b0c0d0e0f",
-        "wif": "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW",
-        "pubKey": "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
-        "chainCode": "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508",
-        "base58": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
-        "base58Priv": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
-        "identifier": "3442193e1bb70916e914552172cd4e2dbc9df811",
-        "fingerprint": "3442193e",
-        "address": "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"
-      },
-      "children": [
-        {
-          "path": "m/0'",
-          "m": 0,
-          "hardened": true,
-          "wif": "L5BmPijJjrKbiUfG4zbiFKNqkvuJ8usooJmzuD7Z8dkRoTThYnAT",
-          "pubKey": "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
-          "chainCode": "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141",
-          "base58": "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
-          "base58Priv": "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
-          "identifier": "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7",
-          "fingerprint": "5c1bd648",
-          "address": "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh",
-          "index": 2147483648,
-          "depth": 1
-        },
-        {
-          "path": "m/0'/1",
-          "m": 1,
-          "wif": "KyFAjQ5rgrKvhXvNMtFB5PCSKUYD1yyPEe3xr3T34TZSUHycXtMM",
-          "pubKey": "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c",
-          "chainCode": "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19",
-          "base58": "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
-          "base58Priv": "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
-          "identifier": "bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe",
-          "fingerprint": "bef5a2f9",
-          "address": "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj",
-          "index": 1,
-          "depth": 2
-        },
-        {
-          "path": "m/0'/1/2'",
-          "m": 2,
-          "hardened": true,
-          "wif": "L43t3od1Gh7Lj55Bzjj1xDAgJDcL7YFo2nEcNaMGiyRZS1CidBVU",
-          "pubKey": "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2",
-          "chainCode": "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f",
-          "base58": "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
-          "base58Priv": "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
-          "identifier": "ee7ab90cde56a8c0e2bb086ac49748b8db9dce72",
-          "fingerprint": "ee7ab90c",
-          "address": "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x",
-          "index": 2147483650,
-          "depth": 3
-        },
-        {
-          "path": "m/0'/1/2'/2",
-          "m": 2,
-          "wif": "KwjQsVuMjbCP2Zmr3VaFaStav7NvevwjvvkqrWd5Qmh1XVnCteBR",
-          "pubKey": "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29",
-          "chainCode": "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd",
-          "base58": "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
-          "base58Priv": "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
-          "identifier": "d880d7d893848509a62d8fb74e32148dac68412f",
-          "fingerprint": "d880d7d8",
-          "address": "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt",
-          "index": 2,
-          "depth": 4
-        },
-        {
-          "path": "m/0'/1/2'/2/1000000000",
-          "m": 1000000000,
-          "wif": "Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs",
-          "pubKey": "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011",
-          "chainCode": "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e",
-          "base58": "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
-          "base58Priv": "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
-          "identifier": "d69aa102255fed74378278c7812701ea641fdf32",
-          "fingerprint": "d69aa102",
-          "address": "1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam",
-          "index": 1000000000,
-          "depth": 5
-        }
-      ]
-    },
-    {
-      "network": "bitcoin",
-      "master": {
-        "seed": "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542",
-        "wif": "KyjXhyHF9wTphBkfpxjL8hkDXDUSbE3tKANT94kXSyh6vn6nKaoy",
-        "pubKey": "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7",
-        "chainCode": "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689",
-        "base58": "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
-        "base58Priv": "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
-        "identifier": "bd16bee53961a47d6ad888e29545434a89bdfe95",
-        "fingerprint": "bd16bee5",
-        "address": "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"
-      },
-      "children": [
-        {
-          "path": "m/0",
-          "m": 0,
-          "wif": "L2ysLrR6KMSAtx7uPqmYpoTeiRzydXBattRXjXz5GDFPrdfPzKbj",
-          "pubKey": "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea",
-          "chainCode": "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c",
-          "base58": "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
-          "base58Priv": "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
-          "identifier": "5a61ff8eb7aaca3010db97ebda76121610b78096",
-          "fingerprint": "5a61ff8e",
-          "address": "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ",
-          "index": 0,
-          "depth": 1
-        },
-        {
-          "path": "m/0/2147483647'",
-          "m": 2147483647,
-          "hardened": true,
-          "wif": "L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr",
-          "pubKey": "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b",
-          "chainCode": "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9",
-          "base58": "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
-          "base58Priv": "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
-          "identifier": "d8ab493736da02f11ed682f88339e720fb0379d1",
-          "fingerprint": "d8ab4937",
-          "address": "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk",
-          "index": 4294967295,
-          "depth": 2
-        },
-        {
-          "path": "m/0/2147483647'/1",
-          "m": 1,
-          "wif": "KzyzXnznxSv249b4KuNkBwowaN3akiNeEHy5FWoPCJpStZbEKXN2",
-          "pubKey": "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9",
-          "chainCode": "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb",
-          "base58": "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
-          "base58Priv": "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
-          "identifier": "78412e3a2296a40de124307b6485bd19833e2e34",
-          "fingerprint": "78412e3a",
-          "address": "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW",
-          "index": 1,
-          "depth": 3
-        },
-        {
-          "path": "m/0/2147483647'/1/2147483646'",
-          "m": 2147483646,
-          "hardened": true,
-          "wif": "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF",
-          "pubKey": "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0",
-          "chainCode": "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29",
-          "base58": "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
-          "base58Priv": "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
-          "identifier": "31a507b815593dfc51ffc7245ae7e5aee304246e",
-          "fingerprint": "31a507b8",
-          "address": "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R",
-          "index": 4294967294,
-          "depth": 4
-        },
-        {
-          "path": "m/0/2147483647'/1/2147483646'/2",
-          "m": 2,
-          "wif": "L3WAYNAZPxx1fr7KCz7GN9nD5qMBnNiqEJNJMU1z9MMaannAt4aK",
-          "pubKey": "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c",
-          "chainCode": "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271",
-          "base58": "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
-          "base58Priv": "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
-          "identifier": "26132fdbe7bf89cbc64cf8dafa3f9f88b8666220",
-          "fingerprint": "26132fdb",
-          "address": "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt",
-          "index": 2,
-          "depth": 5
-        }
-      ]
-    },
-    {
-      "comment": "Private key has leading zeros, see PR #673",
-      "network": "bitcoin",
-      "master": {
-        "seed": "d13de7bd1e54422d1a3b3b699a27fb460de2849e7e66a005c647e8e4a54075cb",
-        "wif": "KwDiCU5bs8xQwsRgxjhkcJcVuR7NE4Mei8X9uSAVviVTE7JmMoS6",
-        "pubKey": "0298ccc720d5dea817c7077605263bae52bca083cf8888fee77ff4c1b4797ee180",
-        "chainCode": "c23ab32b36ddff49fae350a1bed8ec6b4d9fc252238dd789b7273ba4416054eb",
-        "base58": "xpub661MyMwAqRbcGUbHLLJ5n2DzFAt8mmaDxbmbdimh68m8EiXGEQPiJya4BJat5yMzy4e68VSUoLGCu5uvzf8dUoGvwuJsLE6F1cibmWsxFNn",
-        "base58Priv": "xprv9s21ZrQH143K3zWpEJm5QtHFh93eNJrNbNqzqLN5XoE9MvC7gs5TmBFaL2PpaXpDc8FBYVe5EChc73ApjSQ5fWsXS7auHy1MmG6hdpywE1q",
-        "identifier": "1a87677be6f73cc9655e8b4c5d2fd0aeeb1b23c7",
-        "fingerprint": "1a87677b",
-        "address": "KyDarNhq8WK8rSU36UY7bDv9MAwdpKFZYKPN89Geh2dUwHjTqVh5"
-      },
-      "children": [
-        {
-          "path": "m/44'/0'/0'/0/0'",
-          "wif": "L3z3MSqZtDQ1FPHKi7oWf1nc9rMEGFtZUDCoFa7n4F695g5qZiSu",
-          "pubKey": "027c3591221e28939e45f8ea297d62c3640ebb09d7058b01d09c963d984a40ad49",
-          "chainCode": "ca27553aa89617e982e621637d6478f564b32738f8bbe2e48d0a58a8e0f6da40",
-          "base58": "xpub6GcBnm7FfDg5ERWACCvtuotN6Tdoc37r3SZ1asBHvCWzPkqWn3MVKPWKzy6GsfmdMUGanR3D12dH1cp5tJauuubwc4FAJDn67SH2uUjwAT1",
-          "base58Priv": "xprvA3cqPFaMpr7n1wRh6BPtYfwdYRoKCaPzgDdQnUmgMrz1WxWNEW3EmbBr9ieh9BJAsRGKFPLvotb4p4Aq79jddUVKPVJt7exVzLHcv777JVf",
-          "identifier": "e371d69b5dae6eacee832a130ee9f55545275a09",
-          "fingerprint": "e371d69b",
-          "address": "1MjcmArHeqorgm9uJi4kPNQ6CbsrmCtASH",
-          "index": 2147483648,
-          "depth": 5
-        }
-      ]
-    },
-    {
-      "network": "litecoin",
-      "master": {
-        "seed": "000102030405060708090a0b0c0d0e0f",
-        "wif": "TAroS5Knm8GZcnpPycBgzjwwDLWMyQjDrcuGPPoArgrbW7Ln22qp",
-        "pubKey": "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
-        "chainCode": "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508",
-        "base58": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491",
-        "base58Priv": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k",
-        "identifier": "3442193e1bb70916e914552172cd4e2dbc9df811",
-        "fingerprint": "3442193e",
-        "address": "LPzGaoLUtXFkmNo3u1chDxGxDnSaBQTTxm"
-      },
-      "children": [
-        {
-          "path": "m/0'",
-          "m": 0,
-          "hardened": true,
-          "wif": "TB22qU2V9EJCVKJ8cdYaTfvDhnYcCzthcWgFm1k6hbvbKM1NLxoL",
-          "pubKey": "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
-          "chainCode": "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141",
-          "base58": "Ltub2UhtRiSfp82berwLEKkB34QBEt2TUdCDCu4WNzGumvAMwYsxfWjULKsXhADxqy3cuDu3TnqoKJr1xmB8Wb2qzthWAtbb4CutpXPuSU1YMgG",
-          "base58Priv": "Ltpv73XYpw28ZyVe2zEVyiFnxUZxoKLGQNdZ8NxUi1WcqjNmMBgtLbh3KimGSnPHCoLv1RmvxHs4dnKmo1oXQ8dXuDu8uroxrbVxZPA1gXboYvx",
-          "identifier": "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7",
-          "fingerprint": "5c1bd648",
-          "address": "LTcyn1jun6g9hvxtsT7cqMRSyix7AULC76",
-          "index": 2147483648,
-          "depth": 1
-        }
-      ]
-    }
-  ],
-  "invalid": {
-    "fromBase58": [
-      {
-        "exception": "Invalid checksum",
-        "string": "xprvQQQQQQQQQQQQQQQQCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"
-      },
-      {
-        "exception": "Invalid buffer length",
-        "network": "bitcoin",
-        "string": "HAsbc6CgKmTYEQg2CTz7m5STEPAB"
-      },
-      {
-        "exception": "Invalid parent fingerprint",
-        "network": "bitcoin",
-        "string": "xprv9tnJFvAXAXPfPnMTKfwpwnkty7MzJwELVgp4NTBquaKXy4RndyfJJCJJf7zNaVpBpzrwVRutZNLRCVLEcZHcvuCNG3zGbGBcZn57FbNnmSP"
-      },
-      {
-        "exception": "Invalid private key",
-        "network": "bitcoin",
-        "string": "xprv9s21ZrQH143K3yLysFvsu3n1dMwhNusmNHr7xArzAeCc7MQYqDBBStmqnZq6WLi668siBBNs3SjiyaexduHu9sXT9ixTsqptL67ADqcaBdm"
-      },
-      {
-        "exception": "Invalid index",
-        "network": "bitcoin",
-        "string": "xprv9s21ZrQYdgnodnKW4Drm1Qg7poU6Gf2WUDsjPxvYiK7iLBMrsjbnF1wsZZQgmXNeMSG3s7jmHk1b3JrzhG5w8mwXGxqFxfrweico7k8DtxR"
-      },
-      {
-        "exception": "Unknown network version",
-        "string": "1111111111111adADjFaSNPxwXqLjHLj4mBfYxuewDPbw9hEj1uaXCzMxRPXDFF3cUoezTFYom4sEmEVSQmENPPR315cFk9YUFVek73wE9"
-      },
-      {
-        "exception": "Invalid network version",
-        "network": "bitcoin",
-        "string": "Ltpv73XYpw28ZyVe2zEVyiFnxUZxoKLGQNdZ8NxUi1WcqjNmMBgtLbh3KimGSnPHCoLv1RmvxHs4dnKmo1oXQ8dXuDu8uroxrbVxZPA1gXboYvx"
-      },
-      {
-        "exception": "Invalid buffer length",
-        "string": "9XpNiB4DberdMn4jZiMhNGtuZUd7xUrCEGw4MG967zsVNvUKBEC9XLrmVmFasanWGp15zXfTNw4vW4KdvUAynEwyKjdho9QdLMPA2H5uyt"
-      },
-      {
-        "exception": "Invalid buffer length",
-        "string": "7JJikZQ2NUXjSAnAF2SjFYE3KXbnnVxzRBNddFE1DjbDEHVGEJzYC7zqSgPoauBJS3cWmZwsER94oYSFrW9vZ4Ch5FtGeifdzmtS3FGYDB1vxFZsYKgMc"
-      },
-      {
-        "exception": "Invalid parent fingerprint",
-        "string": "xpub67tVq9SuNQCfm2PXBqjGRAtNZ935kx2uHJaURePth4JBpMfEy6jum7Euj7FTpbs7fnjhfZcNEktCucWHcJf74dbKLKNSTZCQozdDVwvkJhs"
-      },
-      {
-        "exception": "Invalid index",
-        "string": "xpub661MyMwTWkfYZq6BEh3ywGVXFvNj5hhzmWMhFBHSqmub31B1LZ9wbJ3DEYXZ8bHXGqnHKfepTud5a2XxGdnnePzZa2m2DyzTnFGBUXtaf9M"
-      },
-      {
-        "exception": "Unknown network version",
-        "string": "8FH81Rao5EgGmdScoN66TJAHsQP7phEMeyMTku9NBJd7hXgaj3HTvSNjqJjoqBpxdbuushwPEM5otvxXt2p9dcw33AqNKzZEPMqGHmz7Dpayi6Vb"
-      },
-      {
-        "exception": "Point is not on the curve",
-        "string": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gYymDsxxRe3WWeZQ7TadaLSdKUffezzczTCpB8j3JP96UwE2n6w1"
-      }
-    ],
-    "deriveHardened": [
-      2147483648,
-      null,
-      "foo",
-      -1
-    ],
-    "derive": [
-      4294967296,
-      null,
-      "foo",
-      -1
-    ],
-    "derivePath": [
-      2,
-      [
-        2,
-        3,
-        4
-      ],
-      "/",
-      "m/m/123",
-      "a/0/1/2",
-      "m/0/  1  /2",
-      "m/0/1.5/2"
-    ]
-  }
-}
diff --git a/test/hdnode.js b/test/hdnode.js
deleted file mode 100644
index 42a2d14..0000000
--- a/test/hdnode.js
+++ /dev/null
@@ -1,397 +0,0 @@
-/* global describe, it, beforeEach */
-/* eslint-disable no-new */
-
-var assert = require('assert')
-var ecdsa = require('../src/ecdsa')
-var hoodwink = require('hoodwink')
-
-var BigInteger = require('bigi')
-var ECPair = require('../src/ecpair')
-var HDNode = require('../src/hdnode')
-
-var fixtures = require('./fixtures/hdnode.json')
-var curve = ecdsa.__curve
-
-var NETWORKS = require('../src/networks')
-var NETWORKS_LIST = [] // Object.values(NETWORKS)
-for (var networkName in NETWORKS) {
-  NETWORKS_LIST.push(NETWORKS[networkName])
-}
-
-var validAll = []
-fixtures.valid.forEach(function (f) {
-  function addNetwork (n) {
-    n.network = f.network
-    return n
-  }
-
-  validAll = validAll.concat(addNetwork(f.master), f.children.map(addNetwork))
-})
-
-describe('HDNode', function () {
-  describe('Constructor', function () {
-    var keyPair, chainCode
-
-    beforeEach(function () {
-      var d = BigInteger.ONE
-
-      keyPair = new ECPair(d, null)
-      chainCode = Buffer.alloc(32, 1)
-    })
-
-    it('stores the keyPair/chainCode directly', function () {
-      var hd = new HDNode(keyPair, chainCode)
-
-      assert.strictEqual(hd.keyPair, keyPair)
-      assert.strictEqual(hd.chainCode, chainCode)
-    })
-
-    it('has a default depth/index of 0', function () {
-      var hd = new HDNode(keyPair, chainCode)
-
-      assert.strictEqual(hd.depth, 0)
-      assert.strictEqual(hd.index, 0)
-    })
-
-    it('throws on uncompressed keyPair', function () {
-      keyPair.compressed = false
-
-      assert.throws(function () {
-        new HDNode(keyPair, chainCode)
-      }, /BIP32 only allows compressed keyPairs/)
-    })
-
-    it('throws when an invalid length chain code is given', function () {
-      assert.throws(function () {
-        new HDNode(keyPair, Buffer.alloc(20))
-      }, /Expected property "1" of type Buffer\(Length: 32\), got Buffer\(Length: 20\)/)
-    })
-  })
-
-  describe('fromSeed*', function () {
-    fixtures.valid.forEach(function (f) {
-      it('calculates privKey and chainCode for ' + f.master.fingerprint, function () {
-        var network = NETWORKS[f.network]
-        var hd = HDNode.fromSeedHex(f.master.seed, network)
-
-        assert.strictEqual(hd.keyPair.toWIF(), f.master.wif)
-        assert.strictEqual(hd.chainCode.toString('hex'), f.master.chainCode)
-      })
-    })
-
-    it('throws if IL is not within interval [1, n - 1] | IL === 0', hoodwink(function () {
-      this.mock(BigInteger, 'fromBuffer', function () {
-        return BigInteger.ZERO
-      }, 1)
-
-      assert.throws(function () {
-        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
-      }, /Private key must be greater than 0/)
-    }))
-
-    it('throws if IL is not within interval [1, n - 1] | IL === n', hoodwink(function () {
-      this.mock(BigInteger, 'fromBuffer', function () {
-        return curve.n
-      }, 1)
-
-      assert.throws(function () {
-        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
-      }, /Private key must be less than the curve order/)
-    }))
-
-    it('throws on low entropy seed', function () {
-      assert.throws(function () {
-        HDNode.fromSeedHex('ffffffffff')
-      }, /Seed should be at least 128 bits/)
-    })
-
-    it('throws on too high entropy seed', function () {
-      assert.throws(function () {
-        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
-      }, /Seed should be at most 512 bits/)
-    })
-  })
-
-  describe('ECPair wrappers', function () {
-    var keyPair, hd, hash
-
-    beforeEach(function () {
-      keyPair = ECPair.makeRandom()
-      hash = Buffer.alloc(32)
-
-      var chainCode = Buffer.alloc(32)
-      hd = new HDNode(keyPair, chainCode)
-    })
-
-    describe('getAddress', function () {
-      it('wraps keyPair.getAddress', hoodwink(function () {
-        this.mock(hd.keyPair, 'getAddress', function () {
-          return 'foo'
-        }, 1)
-
-        assert.strictEqual(hd.getAddress(), 'foo')
-      }))
-    })
-
-    describe('getNetwork', function () {
-      it('wraps keyPair.getNetwork', hoodwink(function () {
-        this.mock(hd.keyPair, 'getNetwork', function () {
-          return 'foo'
-        }, 1)
-
-        assert.strictEqual(hd.getNetwork(), 'foo')
-      }))
-    })
-
-    describe('getPublicKeyBuffer', function () {
-      it('wraps keyPair.getPublicKeyBuffer', hoodwink(function () {
-        this.mock(hd.keyPair, 'getPublicKeyBuffer', function () {
-          return 'foo'
-        }, 1)
-
-        assert.strictEqual(hd.getPublicKeyBuffer(), 'foo')
-      }))
-    })
-
-    describe('sign', function () {
-      it('wraps keyPair.sign', hoodwink(function () {
-        this.mock(hd.keyPair, 'sign', function (h) {
-          assert.strictEqual(hash, h)
-          return 'foo'
-        }, 1)
-
-        assert.strictEqual(hd.sign(hash), 'foo')
-      }))
-    })
-
-    describe('verify', function () {
-      var signature
-
-      beforeEach(function () {
-        signature = hd.sign(hash)
-      })
-
-      it('wraps keyPair.verify', hoodwink(function () {
-        this.mock(hd.keyPair, 'verify', function (h, s) {
-          assert.strictEqual(hash, h)
-          assert.strictEqual(signature, s)
-          return 'foo'
-        }, 1)
-
-        assert.strictEqual(hd.verify(hash, signature), 'foo')
-      }))
-    })
-  })
-
-  describe('fromBase58 / toBase58', function () {
-    validAll.forEach(function (f) {
-      it('exports ' + f.base58 + ' (public) correctly', function () {
-        var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
-
-        assert.strictEqual(hd.toBase58(), f.base58)
-        assert.throws(function () { hd.keyPair.toWIF() }, /Missing private key/)
-      })
-    })
-
-    validAll.forEach(function (f) {
-      it('exports ' + f.base58Priv + ' (private) correctly', function () {
-        var hd = HDNode.fromBase58(f.base58Priv, NETWORKS_LIST)
-
-        assert.strictEqual(hd.toBase58(), f.base58Priv)
-        assert.strictEqual(hd.keyPair.toWIF(), f.wif)
-      })
-    })
-
-    fixtures.invalid.fromBase58.forEach(function (f) {
-      it('throws on ' + f.string, function () {
-        assert.throws(function () {
-          var networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
-
-          HDNode.fromBase58(f.string, networks)
-        }, new RegExp(f.exception))
-      })
-    })
-  })
-
-  describe('getIdentifier', function () {
-    validAll.forEach(function (f) {
-      it('returns the identifier for ' + f.fingerprint, function () {
-        var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
-
-        assert.strictEqual(hd.getIdentifier().toString('hex'), f.identifier)
-      })
-    })
-  })
-
-  describe('getFingerprint', function () {
-    validAll.forEach(function (f) {
-      it('returns the fingerprint for ' + f.fingerprint, function () {
-        var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
-
-        assert.strictEqual(hd.getFingerprint().toString('hex'), f.fingerprint)
-      })
-    })
-  })
-
-  describe('neutered / isNeutered', function () {
-    validAll.forEach(function (f) {
-      it('drops the private key for ' + f.fingerprint, function () {
-        var hd = HDNode.fromBase58(f.base58Priv, NETWORKS_LIST)
-        var hdn = hd.neutered()
-
-        assert.notEqual(hdn.keyPair, hd.keyPair)
-        assert.throws(function () { hdn.keyPair.toWIF() }, /Missing private key/)
-        assert.strictEqual(hdn.toBase58(), f.base58)
-        assert.strictEqual(hdn.chainCode, hd.chainCode)
-        assert.strictEqual(hdn.depth, f.depth >>> 0)
-        assert.strictEqual(hdn.index, f.index >>> 0)
-        assert.strictEqual(hdn.isNeutered(), true)
-
-        // does not modify the original
-        assert.strictEqual(hd.toBase58(), f.base58Priv)
-        assert.strictEqual(hd.isNeutered(), false)
-      })
-    })
-  })
-
-  describe('derive', function () {
-    function verifyVector (hd, v) {
-      if (hd.isNeutered()) {
-        assert.strictEqual(hd.toBase58(), v.base58)
-      } else {
-        assert.strictEqual(hd.neutered().toBase58(), v.base58)
-        assert.strictEqual(hd.toBase58(), v.base58Priv)
-      }
-
-      assert.strictEqual(hd.getFingerprint().toString('hex'), v.fingerprint)
-      assert.strictEqual(hd.getIdentifier().toString('hex'), v.identifier)
-      assert.strictEqual(hd.getAddress(), v.address)
-      assert.strictEqual(hd.keyPair.toWIF(), v.wif)
-      assert.strictEqual(hd.keyPair.getPublicKeyBuffer().toString('hex'), v.pubKey)
-      assert.strictEqual(hd.chainCode.toString('hex'), v.chainCode)
-      assert.strictEqual(hd.depth, v.depth >>> 0)
-      assert.strictEqual(hd.index, v.index >>> 0)
-    }
-
-    fixtures.valid.forEach(function (f) {
-      var network = NETWORKS[f.network]
-      var hd = HDNode.fromSeedHex(f.master.seed, network)
-      var master = hd
-
-      // testing deriving path from master
-      f.children.forEach(function (c) {
-        it(c.path + ' from ' + f.master.fingerprint + ' by path', function () {
-          var child = master.derivePath(c.path)
-          var childNoM = master.derivePath(c.path.slice(2)) // no m/ on path
-
-          verifyVector(child, c)
-          verifyVector(childNoM, c)
-        })
-      })
-
-      // testing deriving path from children
-      f.children.forEach(function (c, i) {
-        var cn = master.derivePath(c.path)
-
-        f.children.slice(i + 1).forEach(function (cc) {
-          it(cc.path + ' from ' + c.fingerprint + ' by path', function () {
-            var ipath = cc.path.slice(2).split('/').slice(i + 1).join('/')
-            var child = cn.derivePath(ipath)
-            verifyVector(child, cc)
-
-            assert.throws(function () {
-              cn.derivePath('m/' + ipath)
-            }, /Not a master node/)
-          })
-        })
-      })
-
-      // FIXME: test data is only testing Private -> private for now
-      f.children.forEach(function (c) {
-        if (c.m === undefined) return
-
-        it(c.path + ' from ' + f.master.fingerprint, function () {
-          if (c.hardened) {
-            hd = hd.deriveHardened(c.m)
-          } else {
-            hd = hd.derive(c.m)
-          }
-
-          verifyVector(hd, c)
-        })
-      })
-    })
-
-    it('works for Private -> public (neutered)', function () {
-      var f = fixtures.valid[1]
-      var c = f.children[0]
-
-      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
-      var child = master.derive(c.m).neutered()
-
-      assert.strictEqual(child.toBase58(), c.base58)
-    })
-
-    it('works for Private -> public (neutered, hardened)', function () {
-      var f = fixtures.valid[0]
-      var c = f.children[0]
-
-      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
-      var child = master.deriveHardened(c.m).neutered()
-
-      assert.strictEqual(c.base58, child.toBase58())
-    })
-
-    it('works for Public -> public', function () {
-      var f = fixtures.valid[1]
-      var c = f.children[0]
-
-      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
-      var child = master.derive(c.m)
-
-      assert.strictEqual(c.base58, child.toBase58())
-    })
-
-    it('throws on Public -> public (hardened)', function () {
-      var f = fixtures.valid[0]
-      var c = f.children[0]
-
-      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
-
-      assert.throws(function () {
-        master.deriveHardened(c.m)
-      }, /Could not derive hardened child key/)
-    })
-
-    it('throws on wrong types', function () {
-      var f = fixtures.valid[0]
-      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
-
-      fixtures.invalid.derive.forEach(function (fx) {
-        assert.throws(function () {
-          master.derive(fx)
-        }, /Expected UInt32/)
-      })
-
-      fixtures.invalid.deriveHardened.forEach(function (fx) {
-        assert.throws(function () {
-          master.deriveHardened(fx)
-        }, /Expected UInt31/)
-      })
-
-      fixtures.invalid.derivePath.forEach(function (fx) {
-        assert.throws(function () {
-          master.derivePath(fx)
-        }, /Expected BIP32 derivation path/)
-      })
-    })
-
-    it('works when private key has leading zeros', function () {
-      var key = 'xprv9s21ZrQH143K3ckY9DgU79uMTJkQRLdbCCVDh81SnxTgPzLLGax6uHeBULTtaEtcAvKjXfT7ZWtHzKjTpujMkUd9dDb8msDeAfnJxrgAYhr'
-      var hdkey = HDNode.fromBase58(key)
-      assert.strictEqual(hdkey.keyPair.d.toBuffer(32).toString('hex'), '00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd')
-      var child = hdkey.derivePath('m/44\'/0\'/0\'/0/0\'')
-      assert.strictEqual(child.keyPair.d.toBuffer().toString('hex'), '3348069561d2a0fb925e74bf198762acc47dce7db27372257d2d959a9e6f8aeb')
-    })
-  })
-})
diff --git a/test/integration/bip32.js b/test/integration/bip32.js
index 1908166..b7f0bb2 100644
--- a/test/integration/bip32.js
+++ b/test/integration/bip32.js
@@ -1,32 +1,39 @@
 /* global describe, it */
 
 var assert = require('assert')
+let bip32 = require('bip32')
 var bip39 = require('bip39')
 var bitcoin = require('../../')
 
+var baddress = bitcoin.address
+var bcrypto = bitcoin.crypto
+function getAddress (node) {
+  return baddress.toBase58Check(bcrypto.hash160(node.publicKey), bitcoin.networks.bitcoin.pubKeyHash)
+}
+
 describe('bitcoinjs-lib (BIP32)', function () {
   it('can import a BIP32 testnet xpriv and export to WIF', function () {
     var xpriv = 'tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK'
-    var node = bitcoin.HDNode.fromBase58(xpriv, bitcoin.networks.testnet)
+    var node = bip32.fromBase58(xpriv, bitcoin.networks.testnet)
 
-    assert.equal(node.keyPair.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7')
+    assert.equal(node.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7')
   })
 
   it('can export a BIP32 xpriv, then import it', function () {
     var mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
     var seed = bip39.mnemonicToSeed(mnemonic)
-    var node = bitcoin.HDNode.fromSeedBuffer(seed)
+    var node = bip32.fromSeed(seed)
     var string = node.toBase58()
-    var restored = bitcoin.HDNode.fromBase58(string)
+    var restored = bip32.fromBase58(string)
 
-    assert.equal(node.getAddress(), restored.getAddress()) // same public key
-    assert.equal(node.keyPair.toWIF(), restored.keyPair.toWIF()) // same private key
+    assert.equal(getAddress(node), getAddress(restored)) // same public key
+    assert.equal(node.toWIF(), restored.toWIF()) // same private key
   })
 
   it('can export a BIP32 xpub', function () {
     var mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
     var seed = bip39.mnemonicToSeed(mnemonic)
-    var node = bitcoin.HDNode.fromSeedBuffer(seed)
+    var node = bip32.fromSeed(seed)
     var string = node.neutered().toBase58()
 
     assert.equal(string, 'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n')
@@ -34,7 +41,7 @@ describe('bitcoinjs-lib (BIP32)', function () {
 
   it('can create a BIP32, bitcoin, account 0, external address', function () {
     var path = "m/0'/0/0"
-    var root = bitcoin.HDNode.fromSeedHex('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd')
+    var root = bip32.fromSeed(Buffer.from('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', 'hex'))
 
     var child1 = root.derivePath(path)
 
@@ -43,12 +50,12 @@ describe('bitcoinjs-lib (BIP32)', function () {
       .derive(0)
       .derive(0)
 
-    assert.equal(child1.getAddress(), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
-    assert.equal(child1b.getAddress(), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
+    assert.equal(getAddress(child1), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
+    assert.equal(getAddress(child1b), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
   })
 
   it('can create a BIP44, bitcoin, account 0, external address', function () {
-    var root = bitcoin.HDNode.fromSeedHex('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd')
+    var root = bip32.fromSeed(Buffer.from('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', 'hex'))
 
     var child1 = root.derivePath("m/44'/0'/0'/0/0")
 
@@ -59,19 +66,19 @@ describe('bitcoinjs-lib (BIP32)', function () {
       .derive(0)
       .derive(0)
 
-    assert.equal(child1.getAddress(), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
-    assert.equal(child1b.getAddress(), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
+    assert.equal(getAddress(child1), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
+    assert.equal(getAddress(child1b), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
   })
 
   it('can create a BIP49, bitcoin testnet, account 0, external address', function () {
     var mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
     var seed = bip39.mnemonicToSeed(mnemonic)
-    var root = bitcoin.HDNode.fromSeedBuffer(seed)
+    var root = bip32.fromSeed(seed)
 
     var path = "m/49'/1'/0'/0/0"
     var child = root.derivePath(path)
 
-    var keyhash = bitcoin.crypto.hash160(child.getPublicKeyBuffer())
+    var keyhash = bitcoin.crypto.hash160(child.publicKey)
     var scriptSig = bitcoin.script.witnessPubKeyHash.output.encode(keyhash)
     var addressBytes = bitcoin.crypto.hash160(scriptSig)
     var outputScript = bitcoin.script.scriptHash.output.encode(addressBytes)
@@ -86,14 +93,14 @@ describe('bitcoinjs-lib (BIP32)', function () {
     assert(bip39.validateMnemonic(mnemonic))
 
     var seed = bip39.mnemonicToSeed(mnemonic)
-    var root = bitcoin.HDNode.fromSeedBuffer(seed)
+    var root = bip32.fromSeed(seed)
 
     // receive addresses
-    assert.strictEqual(root.derivePath("m/0'/0/0").getAddress(), '1AVQHbGuES57wD68AJi7Gcobc3RZrfYWTC')
-    assert.strictEqual(root.derivePath("m/0'/0/1").getAddress(), '1Ad6nsmqDzbQo5a822C9bkvAfrYv9mc1JL')
+    assert.strictEqual(getAddress(root.derivePath("m/0'/0/0")), '1AVQHbGuES57wD68AJi7Gcobc3RZrfYWTC')
+    assert.strictEqual(getAddress(root.derivePath("m/0'/0/1")), '1Ad6nsmqDzbQo5a822C9bkvAfrYv9mc1JL')
 
     // change addresses
-    assert.strictEqual(root.derivePath("m/0'/1/0").getAddress(), '1349KVc5NgedaK7DvuD4xDFxL86QN1Hvdn')
-    assert.strictEqual(root.derivePath("m/0'/1/1").getAddress(), '1EAvj4edpsWcSer3duybAd4KiR4bCJW5J6')
+    assert.strictEqual(getAddress(root.derivePath("m/0'/1/0")), '1349KVc5NgedaK7DvuD4xDFxL86QN1Hvdn')
+    assert.strictEqual(getAddress(root.derivePath("m/0'/1/1")), '1EAvj4edpsWcSer3duybAd4KiR4bCJW5J6')
   })
 })
diff --git a/test/integration/crypto.js b/test/integration/crypto.js
index 183c50e..4b53769 100644
--- a/test/integration/crypto.js
+++ b/test/integration/crypto.js
@@ -3,7 +3,9 @@
 var assert = require('assert')
 var bigi = require('bigi')
 var bitcoin = require('../../')
+var bip32 = require('bip32')
 var crypto = require('crypto')
+var tinysecp = require('tiny-secp256k1')
 
 var ecurve = require('ecurve')
 var secp256k1 = ecurve.getCurveByName('secp256k1')
@@ -68,35 +70,31 @@ describe('bitcoinjs-lib (crypto)', function () {
 
   it('can recover a BIP32 parent private key from the parent public key, and a derived, non-hardened child private key', function () {
     function recoverParent (master, child) {
-      assert(!master.keyPair.d, 'You already have the parent private key')
-      assert(child.keyPair.d, 'Missing child private key')
+      assert(master.isNeutered(), 'You already have the parent private key')
+      assert(!child.isNeutered(), 'Missing child private key')
 
-      var curve = secp256k1
-      var QP = master.keyPair.Q
-      var serQP = master.keyPair.getPublicKeyBuffer()
-
-      var d1 = child.keyPair.d
+      var serQP = master.publicKey
+      var d1 = child.privateKey
       var d2
       var data = Buffer.alloc(37)
       serQP.copy(data, 0)
 
       // search index space until we find it
-      for (var i = 0; i < bitcoin.HDNode.HIGHEST_BIT; ++i) {
+      for (var i = 0; i < 0x80000000; ++i) {
         data.writeUInt32BE(i, 33)
 
         // calculate I
         var I = crypto.createHmac('sha512', master.chainCode).update(data).digest()
         var IL = I.slice(0, 32)
-        var pIL = bigi.fromBuffer(IL)
 
-        // See hdnode.js:273 to understand
-        d2 = d1.subtract(pIL).mod(curve.n)
+        // See bip32.js:273 to understand
+        d2 = tinysecp.privateSub(d1, IL)
 
-        var Qp = new bitcoin.ECPair(d2).Q
-        if (Qp.equals(QP)) break
+        var Qp = bip32.fromPrivateKey(d2, Buffer.alloc(32, 0)).publicKey
+        if (Qp.equals(serQP)) break
       }
 
-      var node = new bitcoin.HDNode(new bitcoin.ECPair(d2), master.chainCode, master.network)
+      var node = bip32.fromPrivateKey(d2, master.chainCode, master.network)
       node.depth = master.depth
       node.index = master.index
       node.masterFingerprint = master.masterFingerprint
@@ -104,7 +102,7 @@ describe('bitcoinjs-lib (crypto)', function () {
     }
 
     var seed = crypto.randomBytes(32)
-    var master = bitcoin.HDNode.fromSeedBuffer(seed)
+    var master = bip32.fromSeed(seed)
     var child = master.derive(6) // m/6
 
     // now for the recovery