diff --git a/src/ecpair.js b/src/ecpair.js index 960f270..cfc3649 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -115,7 +115,8 @@ ECPair.prototype.getPublicKeyBuffer = function () { ECPair.prototype.sign = function (hash) { if (!this.d) throw new Error('Missing private key') - return ecdsa.sign(hash, this.d) + let signature = ecdsa.sign(hash, this.d) + return Buffer.concat([signature.r.toBuffer(32), signature.s.toBuffer(32)], 64) } ECPair.prototype.toWIF = function () { @@ -125,6 +126,11 @@ ECPair.prototype.toWIF = function () { } ECPair.prototype.verify = function (hash, signature) { + signature = { + r: BigInteger.fromBuffer(signature.slice(0, 32)), + s: BigInteger.fromBuffer(signature.slice(32, 64)) + } + return ecdsa.verify(hash, signature, this.Q) } diff --git a/src/script_signature.js b/src/script_signature.js index 29344e8..2d915d4 100644 --- a/src/script_signature.js +++ b/src/script_signature.js @@ -1,50 +1,56 @@ -var bip66 = require('bip66') -var BigInteger = require('bigi') -var Buffer = require('safe-buffer').Buffer -var typeforce = require('typeforce') -var types = require('./types') +let bip66 = require('bip66') +let Buffer = require('safe-buffer').Buffer +let typeforce = require('typeforce') +let types = require('./types') + +let ZERO = Buffer.alloc(1, 0) +function toDER (x) { + let i = 0 + while (x[i] === 0) ++i + if (i === x.length) return ZERO + x = x.slice(i) + if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length) + return x +} + +function fromDER (x) { + if (x[0] === 0x00) x = x.slice(1) + let buffer = Buffer.alloc(32, 0) + let bstart = Math.max(0, 32 - x.length) + x.copy(buffer, bstart) + return buffer +} // 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 + let hashType = buffer.readUInt8(buffer.length - 1) + let hashTypeMod = hashType & ~0x80 if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) - var decode = bip66.decode(buffer.slice(0, -1)) + let decode = bip66.decode(buffer.slice(0, -1)) + let r = fromDER(decode.r) + let s = fromDER(decode.s) return { - signature: { - r: BigInteger.fromDERInteger(decode.r), - s: BigInteger.fromDERInteger(decode.s) - }, + signature: Buffer.concat([r, s], 64), 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 + typeforce({ + signature: types.BufferN(64), + hashType: types.UInt8 + }, { signature, hashType }) + + let hashTypeMod = hashType & ~0x80 if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) - var hashTypeBuffer = Buffer.allocUnsafe(1) + let hashTypeBuffer = Buffer.allocUnsafe(1) hashTypeBuffer.writeUInt8(hashType, 0) - var r = Buffer.from(signature.r.toDERInteger()) - var s = Buffer.from(signature.s.toDERInteger()) + let r = toDER(signature.slice(0, 32)) + let s = toDER(signature.slice(32, 64)) return Buffer.concat([ bip66.encode(r, s), @@ -53,8 +59,6 @@ function encode (signature, hashType) { } module.exports = { - fromRSBuffer: fromRSBuffer, - toRSBuffer: toRSBuffer, decode: decode, encode: encode } diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 1f1f490..acfc232 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -715,9 +715,7 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy input.prevOutType === scriptTypes.P2WSH )) throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH') - var signature = keyPair.sign(signatureHash) - if (Buffer.isBuffer(signature)) signature = bscript.signature.fromRSBuffer(signature) - + let signature = keyPair.sign(signatureHash) input.signatures[i] = bscript.signature.encode(signature, hashType) return true }) diff --git a/test/ecpair.js b/test/ecpair.js index 2530e32..6b617da 100644 --- a/test/ecpair.js +++ b/test/ecpair.js @@ -230,6 +230,7 @@ describe('ECPair', function () { this.mock(ecdsa, 'sign', function (h, d) { assert.strictEqual(h, hash) assert.strictEqual(d, keyPair.d) + return { r: BigInteger.ONE, s: BigInteger.ONE } }, 1) keyPair.sign(hash) @@ -254,7 +255,11 @@ describe('ECPair', function () { it('wraps ecdsa.verify', hoodwink(function () { this.mock(ecdsa, 'verify', function (h, s, q) { assert.strictEqual(h, hash) - assert.strictEqual(s, signature) +// assert.strictEqual(s, signature) + assert.deepEqual(s, { + r: BigInteger.fromBuffer(signature.slice(0, 32)), + s: BigInteger.fromBuffer(signature.slice(32, 64)) + }) assert.strictEqual(q, keyPair.Q) }, 1) diff --git a/test/fixtures/signature.json b/test/fixtures/signature.json index 9f4023d..e7949c5 100644 --- a/test/fixtures/signature.json +++ b/test/fixtures/signature.json @@ -4,56 +4,56 @@ "hashType": 1, "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201", "raw": { - "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561", - "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938" + "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9", + "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262" } }, { "hashType": 2, "hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502", "raw": { - "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885", - "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757" + "r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed", + "s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5" } }, { "hashType": 3, "hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303", "raw": { - "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904", - "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971" + "r": "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd0", + "s": "6fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283" } }, { "hashType": 129, "hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381", "raw": { - "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123", - "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875" + "r": "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3", + "s": "75afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3" } }, { "hashType": 130, "hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682", "raw": { - "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997", - "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862" + "r": "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d", + "s": "0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6" } }, { "hashType": 131, "hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783", "raw": { - "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671", - "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959" + "r": "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda487", + "s": "0e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37" } }, { "hashType": 129, "hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81", "raw": { - "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777", - "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839" + "r": "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9", + "s": "06ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef" } } ], @@ -123,8 +123,8 @@ "hashType": 7, "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207", "raw": { - "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561", - "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938" + "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9", + "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262" } }, { @@ -132,8 +132,8 @@ "hashType": 140, "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c", "raw": { - "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561", - "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938" + "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9", + "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262" } } ] diff --git a/test/integration/crypto.js b/test/integration/crypto.js index 4b53769..8566628 100644 --- a/test/integration/crypto.js +++ b/test/integration/crypto.js @@ -43,12 +43,14 @@ describe('bitcoinjs-lib (crypto)', function () { var inputB = tx.ins[j] // enforce matching r values - assert.strictEqual(inputA.signature.r.toString(), inputB.signature.r.toString()) - var r = inputA.signature.r - var rInv = r.modInverse(n) + let r = inputA.signature.slice(0, 32) + let rB = inputB.signature.slice(0, 32) + assert.strictEqual(r.toString('hex'), rB.toString('hex')) - var s1 = inputA.signature.s - var s2 = inputB.signature.s + var rInv = bigi.fromBuffer(r).modInverse(n) + + var s1 = bigi.fromBuffer(inputA.signature.slice(32, 64)) + var s2 = bigi.fromBuffer(inputB.signature.slice(32, 64)) var z1 = inputA.z var z2 = inputB.z diff --git a/test/script_signature.js b/test/script_signature.js index d57e575..f53bc52 100644 --- a/test/script_signature.js +++ b/test/script_signature.js @@ -2,22 +2,21 @@ 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) - } + return Buffer.concat([ + Buffer.from(signature.r, 'hex'), + Buffer.from(signature.s, 'hex') + ], 64) } function toRaw (signature) { return { - r: signature.r.toString(), - s: signature.s.toString() + r: signature.slice(0, 32).toString('hex'), + s: signature.slice(32, 64).toString('hex') } }