Repository: bitcoinjs/bitcoinjs-lib
Pull request #539 (2016-02-06 16:22:12)

Adding some checks on deriving indexes
I have added some checks on hardening indexes.

You don't want to accidentally put in twice hardened index, or a negative number to harden (which produces non-hardened index), etc.


Patch:
diff --git a/src/hdnode.js b/src/hdnode.js
index ff97d467..62cac56e 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -206,6 +206,8 @@ HDNode.prototype.toBase58 = function (__isPrivate) {
 
 // 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 = new Buffer(37)
 
@@ -277,6 +279,8 @@ HDNode.prototype.derive = function (index) {
 }
 
 HDNode.prototype.deriveHardened = function (index) {
+  typeforce(types.UInt31, index)
+
   // Only derives hardened private keys by default
   return this.derive(index + HDNode.HIGHEST_BIT)
 }
diff --git a/src/types.js b/src/types.js
index 1a8ca869..7ddf8c85 100644
--- a/src/types.js
+++ b/src/types.js
@@ -12,9 +12,13 @@ function Hash256bit (value) { return nBuffer(value, 32) }
 function Buffer256bit (value) { return nBuffer(value, 32) }
 
 var UINT53_MAX = Math.pow(2, 53) - 1
+var UINT31_MAX = Math.pow(2, 31) - 1
 function UInt2 (value) { return (value & 3) === value }
 function UInt8 (value) { return (value & 0xff) === value }
 function UInt32 (value) { return (value >>> 0) === value }
+function UInt31 (value) {
+  return UInt32(value) && value <= UINT31_MAX
+}
 function UInt53 (value) {
   return typeforce.Number(value) &&
     value >= 0 &&
@@ -51,6 +55,7 @@ var types = {
   Network: Network,
   UInt2: UInt2,
   UInt8: UInt8,
+  UInt31: UInt31,
   UInt32: UInt32,
   UInt53: UInt53
 }


Test patch:
diff --git a/test/hdnode.js b/test/hdnode.js
index e8f3184a..4e9f1cf6 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -327,5 +327,47 @@ describe('HDNode', function () {
         master.deriveHardened(c.m)
       }, /Could not derive hardened child key/)
     })
+
+    it('throws on negative indexes', function () {
+      var f = fixtures.valid[0]
+      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
+
+      assert.throws(function () {
+        master.deriveHardened(-1)
+      }, /Expected UInt31/)
+      assert.throws(function () {
+        master.derive(-1)
+      }, /Expected UInt32/)
+    })
+
+    it('throws on high indexes', function () {
+      var f = fixtures.valid[0]
+      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
+
+      assert.throws(function () {
+        master.deriveHardened(0x80000000)
+      }, /Expected UInt31/)
+      assert.throws(function () {
+        master.derive(0x100000000)
+      }, /Expected UInt32/)
+    })
+
+    it('throws on non-numbers', function () {
+      var f = fixtures.valid[0]
+      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
+
+      assert.throws(function () {
+        master.deriveHardened()
+      }, /Expected UInt31/)
+      assert.throws(function () {
+        master.derive()
+      }, /Expected UInt32/)
+      assert.throws(function () {
+        master.deriveHardened('foo')
+      }, /Expected UInt31/)
+      assert.throws(function () {
+        master.derive('foo')
+      }, /Expected UInt32/)
+    })
   })
 })