Repository: bitcoinjs/bitcoinjs-lib
Pull request #459 (2015-09-08 06:35:21)

Remove explicit DER/Compact decoding
None of `ECSignature`, except `parseScriptSignature`, is relevant to bitcoin or this libraries intended use.

**Ideally** https://github.com/bitcoinjs/bitcoinjs-lib/issues/394 might allow us to expose these functions for general purpose in the underlying ECC library.
Since we don't expose raw `ecdsa`, that would be the best place for it.

It is basically a pointless abstraction for this library.

IMHO.

Chained on https://github.com/bitcoinjs/bitcoinjs-lib/pull/456


dcousens: Rebased and addressed https://github.com/bitcoinjs/bitcoinjs-lib/pull/459#commitcomment-14945676
jprichardson: Funny, I just updated https://github.com/cryptocoinjs/ecdsa to track bitcoinjs-lib/ecdsa. I suppose these methods can rest in there for the time being.
dcousens: Rebased,  obviously still `3.0.0` though
jprichardson: Given that signatures need to be serialized, parsed, and validated, I'm not so sure I'd be quick to call the abstraction useless - yes, maybe this implementation, but an implementation, probably not. This seems like would be very low-priority. I'd be in favor of ditching it for 3.0 - but I think 3.0 should just focus on the move to secp2561k and other pending breaking changes.
dcousens: > This seems like would be very low-priority. 

Indeed my thoughts.   However,  this could make the movement to `secp256k1` easier due to less specialised / non-generic interfaces?

dcousens: This is ultimately part of https://github.com/bitcoinjs/bitcoinjs-lib/issues/407.
With https://github.com/bitcoinjs/bitcoinjs-lib/pull/456 merged,  and `bip66` being a separate module... there is literally no reason to have `toDER` and `toCompact`.

This finalises that move.
This is hopefully the last PR before `3.0.0`.

Ping @jprichardson @rubensayshi @afk11 
dcousens: Known breaks for code in the wild (based on a GitHub search):

https://github.com/sabakaio/mnemoauth-client/blob/a46202351a976e4346277ddf9827661a29ca30be/index.js#L19

```
var signature = authKey.sign(messageHash).toDER();
```

would need to become
```
var signature = authKey.sign(messageHash)
var encoded = bip66.encode(signature.r, signature.s)
```

Manual unpacking... yay? :confused: 

https://github.com/darkwallet/darkwallet/blob/4c51dacacb8541305f1442ef7fa1628eb7c19a79/src/js/dwutil/multisig.js#L202

--- Very weird usage there.

https://github.com/BitGo/BitGoJS/blob/5a06433c4c424e5f7bebe1ef2895b857622751b6/src/bitcoin.js#L114

Their using `secp256k1` for performance,  and then double serialising? Interesting... would be a `bip66.decode(...)`
dcousens: If no consensus is reached within 24 hours,  I'm going to bump this to `4.0.0` and start the `3.0.0` release process.
rubensayshi: :rocket: 

the BitGo case would actually just become `return secp256k1.signatureExport(sig)` right, they overload the `ECPair.sign` and then go from Buffer -> Signature, but now they can just return that buffer.

the others are odd use cases for which the `bip66` package is perfect.
dcousens: @rubensayshi for PR to be complete in that respect,  just realised it needs to serialize `r` in `ecdsa.sign` and deserialize in `ecdsa.verify`

Maybe we should just return a `bip66` signature there instead?
Save everyone of that hassle?
dcousens: Bumped to `4.0.0`... 
dcousens: Rebased

Patch:
diff --git a/package.json b/package.json
index f785872c..0b73b4ec 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,7 @@
     "merkle-lib": "^2.0.10",
     "pushdata-bitcoin": "^1.0.1",
     "randombytes": "^2.0.1",
-    "safe-buffer": "^5.0.1",
+    "safe-buffer": "^5.1.1",
     "typeforce": "^1.11.3",
     "varuint-bitcoin": "^1.0.4",
     "wif": "^2.0.1"
diff --git a/src/ecdsa.js b/src/ecdsa.js
index 8841f6e1..403ffd51 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -4,7 +4,6 @@ var typeforce = require('typeforce')
 var types = require('./types')
 
 var BigInteger = require('bigi')
-var ECSignature = require('./ecsignature')
 
 var ZERO = Buffer.alloc(1, 0)
 var ONE = Buffer.alloc(1, 1)
@@ -102,7 +101,10 @@ function sign (hash, d) {
     s = n.subtract(s)
   }
 
-  return new ECSignature(r, s)
+  return {
+    r: r,
+    s: s
+  }
 }
 
 function verify (hash, signature, Q) {
diff --git a/src/ecsignature.js b/src/ecsignature.js
deleted file mode 100644
index ebdcc364..00000000
--- a/src/ecsignature.js
+++ /dev/null
@@ -1,97 +0,0 @@
-var bip66 = require('bip66')
-var typeforce = require('typeforce')
-var types = require('./types')
-
-var BigInteger = require('bigi')
-
-function ECSignature (r, s) {
-  typeforce(types.tuple(types.BigInt, types.BigInt), arguments)
-
-  this.r = r
-  this.s = s
-}
-
-ECSignature.parseCompact = function (buffer) {
-  typeforce(types.BufferN(65), buffer)
-
-  var flagByte = buffer.readUInt8(0) - 27
-  if (flagByte !== (flagByte & 7)) throw new Error('Invalid signature parameter')
-
-  var compressed = !!(flagByte & 4)
-  var recoveryParam = flagByte & 3
-  var signature = ECSignature.fromRSBuffer(buffer.slice(1))
-
-  return {
-    compressed: compressed,
-    i: recoveryParam,
-    signature: signature
-  }
-}
-
-ECSignature.fromRSBuffer = function (buffer) {
-  typeforce(types.BufferN(64), buffer)
-
-  var r = BigInteger.fromBuffer(buffer.slice(0, 32))
-  var s = BigInteger.fromBuffer(buffer.slice(32, 64))
-  return new ECSignature(r, s)
-}
-
-ECSignature.fromDER = function (buffer) {
-  var decode = bip66.decode(buffer)
-  var r = BigInteger.fromDERInteger(decode.r)
-  var s = BigInteger.fromDERInteger(decode.s)
-
-  return new ECSignature(r, s)
-}
-
-// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
-ECSignature.parseScriptSignature = function (buffer) {
-  var hashType = buffer.readUInt8(buffer.length - 1)
-  var hashTypeMod = hashType & ~0x80
-
-  if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04) throw new Error('Invalid hashType ' + hashType)
-
-  return {
-    signature: ECSignature.fromDER(buffer.slice(0, -1)),
-    hashType: hashType
-  }
-}
-
-ECSignature.prototype.toCompact = function (i, compressed) {
-  if (compressed) {
-    i += 4
-  }
-
-  i += 27
-
-  var buffer = Buffer.alloc(65)
-  buffer.writeUInt8(i, 0)
-  this.toRSBuffer(buffer, 1)
-  return buffer
-}
-
-ECSignature.prototype.toDER = function () {
-  var r = Buffer.from(this.r.toDERInteger())
-  var s = Buffer.from(this.s.toDERInteger())
-
-  return bip66.encode(r, s)
-}
-
-ECSignature.prototype.toRSBuffer = function (buffer, offset) {
-  buffer = buffer || Buffer.alloc(64)
-  this.r.toBuffer(32).copy(buffer, offset)
-  this.s.toBuffer(32).copy(buffer, offset + 32)
-  return buffer
-}
-
-ECSignature.prototype.toScriptSignature = function (hashType) {
-  var hashTypeMod = hashType & ~0x80
-  if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
-
-  var hashTypeBuffer = Buffer.alloc(1)
-  hashTypeBuffer.writeUInt8(hashType, 0)
-
-  return Buffer.concat([this.toDER(), hashTypeBuffer])
-}
-
-module.exports = ECSignature
diff --git a/src/index.js b/src/index.js
index a809b3c7..e0c58cb0 100644
--- a/src/index.js
+++ b/src/index.js
@@ -8,7 +8,6 @@ for (var key in templates) {
 module.exports = {
   Block: require('./block'),
   ECPair: require('./ecpair'),
-  ECSignature: require('./ecsignature'),
   HDNode: require('./hdnode'),
   Transaction: require('./transaction'),
   TransactionBuilder: require('./transaction_builder'),
diff --git a/src/script.js b/src/script.js
index 1335f5db..4bd2fdf1 100644
--- a/src/script.js
+++ b/src/script.js
@@ -206,6 +206,7 @@ module.exports = {
   toStack: toStack,
 
   number: require('./script_number'),
+  signature: require('./script_signature'),
 
   isCanonicalPubKey: isCanonicalPubKey,
   isCanonicalSignature: isCanonicalSignature,
diff --git a/src/script_signature.js b/src/script_signature.js
new file mode 100644
index 00000000..29344e86
--- /dev/null
+++ b/src/script_signature.js
@@ -0,0 +1,60 @@
+var bip66 = require('bip66')
+var BigInteger = require('bigi')
+var Buffer = require('safe-buffer').Buffer
+var typeforce = require('typeforce')
+var types = require('./types')
+
+// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
+function decode (buffer) {
+  var hashType = buffer.readUInt8(buffer.length - 1)
+  var hashTypeMod = hashType & ~0x80
+  if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
+
+  var decode = bip66.decode(buffer.slice(0, -1))
+
+  return {
+    signature: {
+      r: BigInteger.fromDERInteger(decode.r),
+      s: BigInteger.fromDERInteger(decode.s)
+    },
+    hashType: hashType
+  }
+}
+
+function toRSBuffer (signature, buffer, offset) {
+  buffer = buffer || Buffer.alloc(64)
+  signature.r.toBuffer(32).copy(buffer, offset)
+  signature.s.toBuffer(32).copy(buffer, offset + 32)
+  return buffer
+}
+
+function fromRSBuffer (buffer) {
+  typeforce(types.BufferN(64), buffer)
+
+  var r = BigInteger.fromBuffer(buffer.slice(0, 32))
+  var s = BigInteger.fromBuffer(buffer.slice(32, 64))
+  return { r: r, s: s }
+}
+
+function encode (signature, hashType) {
+  var hashTypeMod = hashType & ~0x80
+  if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
+
+  var hashTypeBuffer = Buffer.allocUnsafe(1)
+  hashTypeBuffer.writeUInt8(hashType, 0)
+
+  var r = Buffer.from(signature.r.toDERInteger())
+  var s = Buffer.from(signature.s.toDERInteger())
+
+  return Buffer.concat([
+    bip66.encode(r, s),
+    hashTypeBuffer
+  ])
+}
+
+module.exports = {
+  fromRSBuffer: fromRSBuffer,
+  toRSBuffer: toRSBuffer,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
index 4574831a..1f1f4903 100644
--- a/src/transaction_builder.js
+++ b/src/transaction_builder.js
@@ -12,7 +12,6 @@ var SIGNABLE = [btemplates.types.P2PKH, btemplates.types.P2PK, btemplates.types.
 var P2SH = SIGNABLE.concat([btemplates.types.P2WPKH, btemplates.types.P2WSH])
 
 var ECPair = require('./ecpair')
-var ECSignature = require('./ecsignature')
 var Transaction = require('./transaction')
 
 function supportedType (type) {
@@ -190,7 +189,7 @@ function fixMultisigOrder (input, transaction, vin) {
       if (!signature) return false
 
       // TODO: avoid O(n) hashForSignature
-      var parsed = ECSignature.parseScriptSignature(signature)
+      var parsed = bscript.signature.decode(signature)
       var hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType)
 
       // skip if signature does not match pubKey
@@ -717,9 +716,9 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy
     )) throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH')
 
     var signature = keyPair.sign(signatureHash)
-    if (Buffer.isBuffer(signature)) signature = ECSignature.fromRSBuffer(signature)
+    if (Buffer.isBuffer(signature)) signature = bscript.signature.fromRSBuffer(signature)
 
-    input.signatures[i] = signature.toScriptSignature(hashType)
+    input.signatures[i] = bscript.signature.encode(signature, hashType)
     return true
   })
 


Test patch:
diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js
index 2eab7de1..b042ae14 100644
--- a/test/bitcoin.core.js
+++ b/test/bitcoin.core.js
@@ -198,13 +198,14 @@ describe('Bitcoin-core', function () {
     })
   })
 
-  describe('ECSignature.parseScriptSignature', function () {
+  describe('script.signature.decode', function () {
     sigCanonical.forEach(function (hex) {
       var buffer = Buffer.from(hex, 'hex')
 
       it('can parse ' + hex, function () {
-        var parsed = bitcoin.ECSignature.parseScriptSignature(buffer)
-        var actual = parsed.signature.toScriptSignature(parsed.hashType)
+        var parsed = bitcoin.script.signature.decode(buffer)
+        var actual = bitcoin.script.signature.encode(parsed.signature, parsed.hashType)
+
         assert.strictEqual(actual.toString('hex'), hex)
       })
     })
@@ -218,7 +219,7 @@ describe('Bitcoin-core', function () {
 
       it('throws on ' + description, function () {
         assert.throws(function () {
-          bitcoin.ECSignature.parseScriptSignature(buffer)
+          bitcoin.script.signature.decode(buffer)
         }, /Expected DER (integer|sequence)|(R|S) value (excessively padded|is negative)|(R|S|DER sequence) length is (zero|too short|too long|invalid)|Invalid hashType/)
       })
     })
diff --git a/test/ecdsa.js b/test/ecdsa.js
index f6c6004e..a0e07d18 100644
--- a/test/ecdsa.js
+++ b/test/ecdsa.js
@@ -2,17 +2,31 @@
 
 var assert = require('assert')
 var bcrypto = require('../src/crypto')
+var bscript = require('../src/script')
 var ecdsa = require('../src/ecdsa')
 var hoodwink = require('hoodwink')
 
 var BigInteger = require('bigi')
-var ECSignature = require('../src/ecsignature')
 
 var curve = ecdsa.__curve
 
 var fixtures = require('./fixtures/ecdsa.json')
 
 describe('ecdsa', function () {
+  function fromRaw (signature) {
+    return {
+      r: new BigInteger(signature.r, 16),
+      s: new BigInteger(signature.s, 16)
+    }
+  }
+
+  function toRaw (signature) {
+    return {
+      r: signature.r.toHex(),
+      s: signature.s.toHex()
+    }
+  }
+
   describe('deterministicGenerateK', function () {
     function checkSig () {
       return true
@@ -80,9 +94,9 @@ describe('ecdsa', function () {
       it('produces a deterministic signature for "' + f.message + '"', function () {
         var d = BigInteger.fromHex(f.d)
         var hash = bcrypto.sha256(f.message)
-        var signature = ecdsa.sign(hash, d).toDER()
+        var signature = ecdsa.sign(hash, d)
 
-        assert.strictEqual(signature.toString('hex'), f.signature)
+        assert.deepEqual(toRaw(signature), f.signature)
       })
     })
 
@@ -101,7 +115,7 @@ describe('ecdsa', function () {
       it('verifies a valid signature for "' + f.message + '"', function () {
         var d = BigInteger.fromHex(f.d)
         var H = bcrypto.sha256(f.message)
-        var signature = ECSignature.fromDER(Buffer.from(f.signature, 'hex'))
+        var signature = fromRaw(f.signature)
         var Q = curve.G.multiply(d)
 
         assert(ecdsa.verify(H, signature, Q))
@@ -112,14 +126,7 @@ describe('ecdsa', function () {
       it('fails to verify with ' + f.description, function () {
         var H = bcrypto.sha256(f.message)
         var d = BigInteger.fromHex(f.d)
-
-        var signature
-        if (f.signature) {
-          signature = ECSignature.fromDER(Buffer.from(f.signature, 'hex'))
-        } else if (f.signatureRaw) {
-          signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16))
-        }
-
+        var signature = fromRaw(f.signature)
         var Q = curve.G.multiply(d)
 
         assert.strictEqual(ecdsa.verify(H, signature, Q), false)
diff --git a/test/ecsignature.js b/test/ecsignature.js
deleted file mode 100644
index d0bc15d3..00000000
--- a/test/ecsignature.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/* global describe, it */
-
-var assert = require('assert')
-
-var BigInteger = require('bigi')
-var ECSignature = require('../src/ecsignature')
-
-var fixtures = require('./fixtures/ecsignature.json')
-
-describe('ECSignature', function () {
-  describe('toCompact', function () {
-    fixtures.valid.forEach(function (f) {
-      it('exports ' + f.compact.hex + ' correctly', function () {
-        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
-
-        var buffer = signature.toCompact(f.compact.i, f.compact.compressed)
-        assert.strictEqual(buffer.toString('hex'), f.compact.hex)
-      })
-    })
-  })
-
-  describe('parseCompact', function () {
-    fixtures.valid.forEach(function (f) {
-      it('imports ' + f.compact.hex + ' correctly', function () {
-        var buffer = Buffer.from(f.compact.hex, 'hex')
-        var parsed = ECSignature.parseCompact(buffer)
-
-        assert.strictEqual(parsed.compressed, f.compact.compressed)
-        assert.strictEqual(parsed.i, f.compact.i)
-        assert.strictEqual(parsed.signature.r.toString(), f.signature.r)
-        assert.strictEqual(parsed.signature.s.toString(), f.signature.s)
-      })
-    })
-
-    fixtures.invalid.compact.forEach(function (f) {
-      it('throws on ' + f.hex, function () {
-        var buffer = Buffer.from(f.hex, 'hex')
-
-        assert.throws(function () {
-          ECSignature.parseCompact(buffer)
-        }, new RegExp(f.exception))
-      })
-    })
-  })
-
-  describe('toDER', function () {
-    fixtures.valid.forEach(function (f) {
-      it('exports ' + f.DER + ' correctly', function () {
-        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
-
-        var DER = signature.toDER()
-        assert.strictEqual(DER.toString('hex'), f.DER)
-      })
-    })
-  })
-
-  describe('fromDER', function () {
-    fixtures.valid.forEach(function (f) {
-      it('imports ' + f.DER + ' correctly', function () {
-        var buffer = Buffer.from(f.DER, 'hex')
-        var signature = ECSignature.fromDER(buffer)
-
-        assert.strictEqual(signature.r.toString(), f.signature.r)
-        assert.strictEqual(signature.s.toString(), f.signature.s)
-      })
-    })
-
-    fixtures.invalid.DER.forEach(function (f) {
-      it('throws "' + f.exception + '" for ' + f.hex, function () {
-        var buffer = Buffer.from(f.hex, 'hex')
-
-        assert.throws(function () {
-          ECSignature.fromDER(buffer)
-        }, new RegExp(f.exception))
-      })
-    })
-  })
-
-  describe('toScriptSignature', function () {
-    fixtures.valid.forEach(function (f) {
-      it('exports ' + f.scriptSignature.hex + ' correctly', function () {
-        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
-
-        var scriptSignature = signature.toScriptSignature(f.scriptSignature.hashType)
-        assert.strictEqual(scriptSignature.toString('hex'), f.scriptSignature.hex)
-      })
-    })
-
-    fixtures.invalid.scriptSignature.forEach(function (f) {
-      it('throws ' + f.exception, function () {
-        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
-
-        assert.throws(function () {
-          signature.toScriptSignature(f.hashType)
-        }, new RegExp(f.exception))
-      })
-    })
-  })
-
-  describe('parseScriptSignature', function () {
-    fixtures.valid.forEach(function (f) {
-      it('imports ' + f.scriptSignature.hex + ' correctly', function () {
-        var buffer = Buffer.from(f.scriptSignature.hex, 'hex')
-        var parsed = ECSignature.parseScriptSignature(buffer)
-
-        assert.strictEqual(parsed.signature.r.toString(), f.signature.r)
-        assert.strictEqual(parsed.signature.s.toString(), f.signature.s)
-        assert.strictEqual(parsed.hashType, f.scriptSignature.hashType)
-      })
-    })
-
-    fixtures.invalid.scriptSignature.forEach(function (f) {
-      it('throws on ' + f.hex, function () {
-        var buffer = Buffer.from(f.hex, 'hex')
-
-        assert.throws(function () {
-          ECSignature.parseScriptSignature(buffer)
-        }, new RegExp(f.exception))
-      })
-    })
-  })
-})
diff --git a/test/fixtures/ecdsa.json b/test/fixtures/ecdsa.json
index bd2fc3c8..780ad74b 100644
--- a/test/fixtures/ecdsa.json
+++ b/test/fixtures/ecdsa.json
@@ -5,50 +5,64 @@
         "d": "01",
         "k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
         "message": "Everything should be made as simple as possible, but not simpler.",
-        "i": 0,
-        "signature": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
+        "signature": {
+          "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9",
+          "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
+        }
       },
       {
         "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
         "k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4",
         "message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",
-        "i": 0,
-        "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
+        "signature": {
+          "r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed",
+          "s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
+        }
       },
       {
         "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
         "k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5",
         "message": "Not only is the Universe stranger than we think, it is stranger than we can think.",
-        "i": 0,
-        "signature": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
+        "signature": {
+          "r": "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd0",
+          "s": "6fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
+        }
       },
       {
         "d": "0000000000000000000000000000000000000000000000000000000000000001",
         "k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f",
         "message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.",
-        "i": 1,
-        "signature": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
+        "signature": {
+          "r": "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3",
+          "s": "75afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
+        }
       },
       {
         "d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",
         "k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97",
         "message": "Computer science is no more about computers than astronomy is about telescopes.",
-        "i": 0,
-        "signature": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
+        "signature": {
+          "r": "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d",
+          "s": "0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
+        }
       },
       {
         "d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",
         "k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb",
         "message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",
-        "i": 1,
-        "signature": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
+        "signature": {
+          "r": "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda487",
+          "s": "0e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
+        }
       },
       {
         "d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",
         "k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b",
         "message": "The question of whether computers can think is like the question of whether submarines can swim.",
-        "i": 1,
-        "signature": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
+        "signature": {
+          "r": "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9",
+          "s": "06ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
+        }
       }
     ],
     "rfc6979": [
@@ -130,13 +144,16 @@
         "description": "The wrong signature",
         "d": "01",
         "message": "foo",
-        "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
+        "signature": {
+          "r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed",
+          "s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
+        }
       },
       {
         "description": "Invalid r value (< 0)",
         "d": "01",
         "message": "foo",
-        "signatureRaw": {
+        "signature": {
           "r": "-01",
           "s": "02"
         }
@@ -145,7 +162,7 @@
         "description": "Invalid r value (== 0)",
         "d": "01",
         "message": "foo",
-        "signatureRaw": {
+        "signature": {
           "r": "00",
           "s": "02"
         }
@@ -154,7 +171,7 @@
         "description": "Invalid r value (>= n)",
         "d": "01",
         "message": "foo",
-        "signatureRaw": {
+        "signature": {
           "r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
           "s": "02"
         }
@@ -163,7 +180,7 @@
         "description": "Invalid s value (< 0)",
         "d": "01",
         "message": "foo",
-        "signatureRaw": {
+        "signature": {
           "r": "02",
           "s": "-01"
         }
@@ -172,7 +189,7 @@
         "description": "Invalid s value (== 0)",
         "d": "01",
         "message": "foo",
-        "signatureRaw": {
+        "signature": {
           "r": "02",
           "s": "00"
         }
@@ -181,7 +198,7 @@
         "description": "Invalid s value (>= n)",
         "d": "01",
         "message": "foo",
-        "signatureRaw": {
+        "signature": {
           "r": "02",
           "s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
         }
@@ -190,7 +207,7 @@
         "description": "Invalid r, s values (r = s = -n)",
         "d": "01",
         "message": "foo",
-        "signatureRaw": {
+        "signature": {
           "r": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
           "s": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
         }
diff --git a/test/fixtures/ecsignature.json b/test/fixtures/ecsignature.json
deleted file mode 100644
index ee948ad1..00000000
--- a/test/fixtures/ecsignature.json
+++ /dev/null
@@ -1,214 +0,0 @@
-{
-  "valid": [
-    {
-      "compact": {
-        "hex": "1f33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262",
-        "compressed": true,
-        "i": 0
-      },
-      "scriptSignature": {
-        "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201",
-        "hashType": 1
-      },
-      "DER": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262",
-      "signature": {
-        "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
-        "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
-      }
-    },
-    {
-      "compact": {
-        "hex": "1b54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5",
-        "compressed": false,
-        "i": 0
-      },
-      "DER": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5",
-      "scriptSignature": {
-        "hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502",
-        "hashType": 2
-      },
-      "signature": {
-        "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
-        "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
-      }
-    },
-    {
-      "compact": {
-        "hex": "1fff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283",
-        "compressed": true,
-        "i": 0
-      },
-      "scriptSignature": {
-        "hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303",
-        "hashType": 3
-      },
-      "DER": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283",
-      "signature": {
-        "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904",
-        "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971"
-      }
-    },
-    {
-      "compact": {
-        "hex": "1cc0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3",
-        "compressed": false,
-        "i": 1
-      },
-      "scriptSignature": {
-        "hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381",
-        "hashType": 129
-      },
-      "DER": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3",
-      "signature": {
-        "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123",
-        "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875"
-      }
-    },
-    {
-      "compact": {
-        "hex": "1f7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6",
-        "compressed": true,
-        "i": 0
-      },
-      "scriptSignature": {
-        "hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682",
-        "hashType": 130
-      },
-      "DER": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6",
-      "signature": {
-        "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997",
-        "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862"
-      }
-    },
-    {
-      "compact": {
-        "hex": "1cfbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37",
-        "compressed": false,
-        "i": 1
-      },
-      "scriptSignature": {
-        "hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783",
-        "hashType": 131
-      },
-      "DER": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37",
-      "signature": {
-        "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671",
-        "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959"
-      }
-    },
-    {
-      "compact": {
-        "hex": "20cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef",
-        "compressed": true,
-        "i": 1
-      },
-      "scriptSignature": {
-        "hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81",
-        "hashType": 129
-      },
-      "DER": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef",
-      "signature": {
-        "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777",
-        "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839"
-      }
-    }
-  ],
-  "invalid": {
-    "compact": [
-      {
-        "exception": "Invalid signature parameter",
-        "hex": "23987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62"
-      },
-      {
-        "exception": "Expected Buffer\\(Length: 65\\), got Buffer\\(Length: 68\\)",
-        "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62000000"
-      },
-      {
-        "exception": "Expected Buffer\\(Length: 65\\), got Buffer\\(Length: 59\\)",
-        "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e9379"
-      }
-    ],
-    "DER": [
-      {
-        "exception": "DER sequence length is too short",
-        "hex": "ffffffffffffff"
-      },
-      {
-        "exception": "DER sequence length is too long",
-        "hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-      },
-      {
-        "exception": "Expected DER sequence",
-        "hex": "00ffff0400ffffff020400ffffff"
-      },
-      {
-        "exception": "DER sequence length is invalid",
-        "hex": "30ff020400ffffff020400ffffff"
-      },
-      {
-        "exception": "DER sequence length is invalid",
-        "hex": "300c030400ffffff030400ffffff0000"
-      },
-      {
-        "exception": "Expected DER integer",
-        "hex": "300cff0400ffffff020400ffffff"
-      },
-      {
-        "exception": "Expected DER integer \\(2\\)",
-        "hex": "300c020200ffffff020400ffffff"
-      },
-      {
-        "exception": "R length is zero",
-        "hex": "30080200020400ffffff"
-      },
-      {
-        "exception": "S length is zero",
-        "hex": "3008020400ffffff0200"
-      },
-      {
-        "exception": "R length is too long",
-        "hex": "300c02dd00ffffff020400ffffff"
-      },
-      {
-        "exception": "S length is invalid",
-        "hex": "300c020400ffffff02dd00ffffff"
-      },
-      {
-        "exception": "R value is negative",
-        "hex": "300c020480000000020400ffffff"
-      },
-      {
-        "exception": "S value is negative",
-        "hex": "300c020400ffffff020480000000"
-      },
-      {
-        "exception": "R value excessively padded",
-        "hex": "300c02040000ffff020400ffffff"
-      },
-      {
-        "exception": "S value excessively padded",
-        "hex": "300c020400ffffff02040000ffff"
-      }
-    ],
-    "scriptSignature": [
-      {
-        "exception": "Invalid hashType 7",
-        "hashType": 7,
-        "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207",
-        "signature": {
-          "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
-          "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
-        }
-      },
-      {
-        "exception": "Invalid hashType 140",
-        "hashType": 140,
-        "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c",
-        "signature": {
-          "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
-          "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
-        }
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/signature.json b/test/fixtures/signature.json
new file mode 100644
index 00000000..9f4023d9
--- /dev/null
+++ b/test/fixtures/signature.json
@@ -0,0 +1,140 @@
+{
+  "valid": [
+    {
+      "hashType": 1,
+      "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201",
+      "raw": {
+        "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+        "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+      }
+    },
+    {
+      "hashType": 2,
+      "hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502",
+      "raw": {
+        "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
+        "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
+      }
+    },
+    {
+      "hashType": 3,
+      "hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303",
+      "raw": {
+        "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904",
+        "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971"
+      }
+    },
+    {
+      "hashType": 129,
+      "hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381",
+      "raw": {
+        "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123",
+        "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875"
+      }
+    },
+    {
+      "hashType": 130,
+      "hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682",
+      "raw": {
+        "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997",
+        "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862"
+      }
+    },
+    {
+      "hashType": 131,
+      "hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783",
+      "raw": {
+        "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671",
+        "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959"
+      }
+    },
+    {
+      "hashType": 129,
+      "hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81",
+      "raw": {
+        "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777",
+        "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839"
+      }
+    }
+  ],
+  "invalid": [
+    {
+      "exception": "DER sequence length is too short",
+      "hex": "ffffffffffffff01"
+    },
+    {
+      "exception": "DER sequence length is too long",
+      "hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01"
+    },
+    {
+      "exception": "Expected DER sequence",
+      "hex": "00ffff0400ffffff020400ffffff01"
+    },
+    {
+      "exception": "DER sequence length is invalid",
+      "hex": "30ff020400ffffff020400ffffff01"
+    },
+    {
+      "exception": "DER sequence length is invalid",
+      "hex": "300c030400ffffff030400ffffff000001"
+    },
+    {
+      "exception": "Expected DER integer",
+      "hex": "300cff0400ffffff020400ffffff01"
+    },
+    {
+      "exception": "Expected DER integer \\(2\\)",
+      "hex": "300c020200ffffff020400ffffff01"
+    },
+    {
+      "exception": "R length is zero",
+      "hex": "30080200020400ffffff01"
+    },
+    {
+      "exception": "S length is zero",
+      "hex": "3008020400ffffff020001"
+    },
+    {
+      "exception": "R length is too long",
+      "hex": "300c02dd00ffffff020400ffffff01"
+    },
+    {
+      "exception": "S length is invalid",
+      "hex": "300c020400ffffff02dd00ffffff01"
+    },
+    {
+      "exception": "R value is negative",
+      "hex": "300c020480000000020400ffffff01"
+    },
+    {
+      "exception": "S value is negative",
+      "hex": "300c020400ffffff02048000000001"
+    },
+    {
+      "exception": "R value excessively padded",
+      "hex": "300c02040000ffff020400ffffff01"
+    },
+    {
+      "exception": "S value excessively padded",
+      "hex": "300c020400ffffff02040000ffff01"
+    },
+    {
+      "exception": "Invalid hashType 7",
+      "hashType": 7,
+      "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207",
+      "raw": {
+        "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+        "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+      }
+    },
+    {
+      "exception": "Invalid hashType 140",
+      "hashType": 140,
+      "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c",
+      "raw": {
+        "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+        "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+      }
+    }
+  ]
+}
diff --git a/test/integration/cltv.js b/test/integration/cltv.js
index 8f1488f2..82c629ee 100644
--- a/test/integration/cltv.js
+++ b/test/integration/cltv.js
@@ -56,7 +56,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
       var tx = txb.buildIncomplete()
       var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
       var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
-        alice.sign(signatureHash).toScriptSignature(hashType),
+        bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
         bitcoin.opcodes.OP_TRUE
       ], redeemScript)
       tx.setInputScript(0, redeemScriptSig)
@@ -100,7 +100,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
         var tx = txb.buildIncomplete()
         var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
         var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
-          alice.sign(signatureHash).toScriptSignature(hashType),
+          bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
           bitcoin.opcodes.OP_TRUE
         ], redeemScript)
         tx.setInputScript(0, redeemScriptSig)
@@ -154,8 +154,8 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
       var tx = txb.buildIncomplete()
       var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
       var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
-        alice.sign(signatureHash).toScriptSignature(hashType),
-        bob.sign(signatureHash).toScriptSignature(hashType),
+        bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
+        bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
         bitcoin.opcodes.OP_FALSE
       ], redeemScript)
       tx.setInputScript(0, redeemScriptSig)
@@ -196,7 +196,8 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
       var tx = txb.buildIncomplete()
       var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
       var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
-        alice.sign(signatureHash).toScriptSignature(hashType),
+        bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
+        bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
         bitcoin.opcodes.OP_TRUE
       ], redeemScript)
       tx.setInputScript(0, redeemScriptSig)
diff --git a/test/integration/crypto.js b/test/integration/crypto.js
index 716cb502..183c50e3 100644
--- a/test/integration/crypto.js
+++ b/test/integration/crypto.js
@@ -21,7 +21,7 @@ describe('bitcoinjs-lib (crypto)', function () {
 
       assert(bitcoin.script.pubKeyHash.input.check(scriptChunks), 'Expected pubKeyHash script')
       var prevOutScript = bitcoin.address.toOutputScript('1ArJ9vRaQcoQ29mTWZH768AmRwzb6Zif1z')
-      var scriptSignature = bitcoin.ECSignature.parseScriptSignature(scriptChunks[0])
+      var scriptSignature = bitcoin.script.signature.decode(scriptChunks[0])
       var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(scriptChunks[1])
 
       var m = tx.hashForSignature(vin, prevOutScript, scriptSignature.hashType)
diff --git a/test/integration/transactions.js b/test/integration/transactions.js
index 4c1cc266..23770951 100644
--- a/test/integration/transactions.js
+++ b/test/integration/transactions.js
@@ -230,7 +230,7 @@ describe('bitcoinjs-lib (transactions)', function () {
       var keyPair = keyPairs[i]
       var prevOutScript = bitcoin.address.toOutputScript(keyPair.getAddress())
       var scriptSig = bitcoin.script.pubKeyHash.input.decode(input.script)
-      var ss = bitcoin.ECSignature.parseScriptSignature(scriptSig.signature)
+      var ss = bitcoin.script.signature.decode(scriptSig.signature)
       var hash = tx.hashForSignature(i, prevOutScript, ss.hashType)
 
       assert.strictEqual(scriptSig.pubKey.toString('hex'), keyPair.getPublicKeyBuffer().toString('hex'))
diff --git a/test/script_signature.js b/test/script_signature.js
new file mode 100644
index 00000000..d57e575b
--- /dev/null
+++ b/test/script_signature.js
@@ -0,0 +1,66 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bscriptSig = require('../src/script').signature
+var BigInteger = require('bigi')
+var Buffer = require('safe-buffer').Buffer
+var fixtures = require('./fixtures/signature.json')
+
+describe('Script Signatures', function () {
+  function fromRaw (signature) {
+    return {
+      r: new BigInteger(signature.r),
+      s: new BigInteger(signature.s)
+    }
+  }
+
+  function toRaw (signature) {
+    return {
+      r: signature.r.toString(),
+      s: signature.s.toString()
+    }
+  }
+
+  describe('encode', function () {
+    fixtures.valid.forEach(function (f) {
+      it('encodes ' + f.hex, function () {
+        var buffer = bscriptSig.encode(fromRaw(f.raw), f.hashType)
+
+        assert.strictEqual(buffer.toString('hex'), f.hex)
+      })
+    })
+
+    fixtures.invalid.forEach(function (f) {
+      if (!f.raw) return
+
+      it('throws ' + f.exception, function () {
+        var signature = fromRaw(f.raw)
+
+        assert.throws(function () {
+          bscriptSig.encode(signature, f.hashType)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('decode', function () {
+    fixtures.valid.forEach(function (f) {
+      it('decodes ' + f.hex, function () {
+        var decode = bscriptSig.decode(Buffer.from(f.hex, 'hex'))
+
+        assert.deepEqual(toRaw(decode.signature), f.raw)
+        assert.strictEqual(decode.hashType, f.hashType)
+      })
+    })
+
+    fixtures.invalid.forEach(function (f) {
+      it('throws on ' + f.hex, function () {
+        var buffer = Buffer.from(f.hex, 'hex')
+
+        assert.throws(function () {
+          bscriptSig.decode(buffer)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+})