Repository: bitcoinjs/bitcoinjs-lib
Pull request #474 (2015-09-21 06:45:57)

HDNode: add sign/verify
This should stop all usage of `hdNode.keyPair` in API usage, meaning we should be able to isolate `HDNode` for `3.0.0`.

Non breaking changes.
Bumps minor.

Note: adds the ability to do `txBuilder.sign(vout, hdNode)`


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a2ce0738..08dded28 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,16 @@
+# 2.1.0
+
+From this release users should use the HDNode directly (compared to accessing `.keyPair`) when performing ECDSA operations such as `sign` or `verify`.
+Ideally you shoud not have to directly access `HDNode` internals for general usage,  as it can often be confusing and error prone.
+
+__added__
+- `ECPair.prototype.getNetwork`
+- `HDNode.prototype.getNetwork`, wraps the underyling keyPair's `getNetwork` method
+- `HDNode.prototype.getPublicKeyBuffer`, wraps the underyling keyPair's `getPublicKeyBuffer` method
+- `HDNode.prototype.sign`, wraps the underlying keyPair's `sign` method
+- `HDNode.prototype.verify`, wraps the underlying keyPair's `verify` method
+
+
 # 2.0.0
 
 In this release we have strived to simplify the API,  [using native types](https://github.com/bitcoinjs/bitcoinjs-lib/issues/407) wherevever possible to encourage cross-compatibility with other open source community modules.
diff --git a/src/ecpair.js b/src/ecpair.js
index 701b6df0..17d19e12 100644
--- a/src/ecpair.js
+++ b/src/ecpair.js
@@ -105,6 +105,10 @@ ECPair.prototype.getAddress = function () {
   return bs58check.encode(payload)
 }
 
+ECPair.prototype.getNetwork = function () {
+  return this.network
+}
+
 ECPair.prototype.getPublicKeyBuffer = function () {
   return this.Q.getEncoded(this.compressed)
 }
diff --git a/src/hdnode.js b/src/hdnode.js
index bf84c458..80ae630c 100644
--- a/src/hdnode.js
+++ b/src/hdnode.js
@@ -136,6 +136,14 @@ 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
@@ -149,6 +157,14 @@ HDNode.prototype.neutered = function () {
   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')
 


Test patch:
diff --git a/test/ecpair.js b/test/ecpair.js
index 2421f5f1..b7edbd04 100644
--- a/test/ecpair.js
+++ b/test/ecpair.js
@@ -167,6 +167,17 @@ describe('ECPair', function () {
     })
   })
 
+  describe('getNetwork', function () {
+    fixtures.valid.forEach(function (f) {
+      it('returns ' + f.network + ' for ' + f.WIF, function () {
+        var network = NETWORKS[f.network]
+        var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
+
+        assert.strictEqual(keyPair.getNetwork(), network)
+      })
+    })
+  })
+
   describe('ecdsa wrappers', function () {
     var keyPair, hash
 
diff --git a/test/hdnode.js b/test/hdnode.js
index c7ab3178..afa98873 100644
--- a/test/hdnode.js
+++ b/test/hdnode.js
@@ -101,6 +101,69 @@ describe('HDNode', function () {
     })
   })
 
+  describe('ECPair wrappers', function () {
+    var keyPair, hd, hash
+
+    beforeEach(function () {
+      keyPair = ECPair.makeRandom()
+      hash = new Buffer(32)
+
+      var chainCode = new Buffer(32)
+      hd = new HDNode(keyPair, chainCode)
+    })
+
+    describe('getAddress', function () {
+      it('wraps keyPair.getAddress', sinon.test(function () {
+        this.mock(keyPair).expects('getAddress')
+          .once().withArgs().returns('foobar')
+
+        assert.strictEqual(hd.getAddress(), 'foobar')
+      }))
+    })
+
+    describe('getNetwork', function () {
+      it('wraps keyPair.getNetwork', sinon.test(function () {
+        this.mock(keyPair).expects('getNetwork')
+          .once().withArgs().returns('network')
+
+        assert.strictEqual(hd.getNetwork(), 'network')
+      }))
+    })
+
+    describe('getPublicKeyBuffer', function () {
+      it('wraps keyPair.getPublicKeyBuffer', sinon.test(function () {
+        this.mock(keyPair).expects('getPublicKeyBuffer')
+          .once().withArgs().returns('pubKeyBuffer')
+
+        assert.strictEqual(hd.getPublicKeyBuffer(), 'pubKeyBuffer')
+      }))
+    })
+
+    describe('sign', function () {
+      it('wraps keyPair.sign', sinon.test(function () {
+        this.mock(keyPair).expects('sign')
+          .once().withArgs(hash).returns('signed')
+
+        assert.strictEqual(hd.sign(hash), 'signed')
+      }))
+    })
+
+    describe('verify', function () {
+      var signature
+
+      beforeEach(function () {
+        signature = hd.sign(hash)
+      })
+
+      it('wraps keyPair.verify', sinon.test(function () {
+        this.mock(keyPair).expects('verify')
+          .once().withArgs(hash, signature).returns('verified')
+
+        assert.strictEqual(hd.verify(hash, signature), 'verified')
+      }))
+    })
+  })
+
   describe('toBase58', function () {
     fixtures.valid.forEach(function (f) {
       it('exports ' + f.master.base58 + ' (public) correctly', function () {
@@ -173,23 +236,6 @@ describe('HDNode', function () {
     })
   })
 
-  describe('getAddress', function () {
-    var hd
-
-    beforeEach(function () {
-      var f = fixtures.valid[0]
-
-      hd = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
-    })
-
-    it('wraps ECPair.getAddress', sinon.test(function () {
-      this.mock(hd.keyPair).expects('getAddress')
-        .once().returns('foobar')
-
-      assert.strictEqual(hd.getAddress(), 'foobar')
-    }))
-  })
-
   describe('neutered', function () {
     var f = fixtures.valid[0]