From 9af8d95daf2438b3674cb555344da5deb3e9dfb6 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 23 Apr 2014 05:31:24 +1000 Subject: [PATCH 1/7] Removes applyMultisigs and adds setScriptSig --- src/transaction.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index 00083bc..a721e73 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -319,8 +319,9 @@ Transaction.prototype.sign = function(index, key, type, network) { var script = Script.createOutputScript(address, network) var hash = this.hashTransactionForSignature(script, index, type) var sig = key.sign(hash).concat([type]) + var scriptSig = Script.createInputScript(sig, key.pub) - this.ins[index].script = Script.createInputScript(sig, key.pub) + this.setScriptSig(index, scriptSig) } // Takes outputs of the form [{ output: 'txhash:index', address: 'address' },...] @@ -369,10 +370,8 @@ Transaction.prototype.p2shsign = function(index, script, key, type) { return sig } -Transaction.prototype.multisign = Transaction.prototype.p2shsign - -Transaction.prototype.applyMultisigs = function(index, script, sigs/*, type*/) { - this.ins[index].script = Script.createMultiSigInputScript(sigs, script) +Transaction.prototype.setScriptSig = function(index, script) { + this.ins[index].script = script } Transaction.prototype.validateSig = function(index, script, sig, pub) { From 5546cae92863d4b6bda26b0736852f484832a6db Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 23 Apr 2014 05:33:11 +1000 Subject: [PATCH 2/7] Removes type coercion for a stricter TX API --- src/transaction.js | 17 +++++++---------- test/transaction.js | 10 ++++------ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index a721e73..29590eb 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -362,23 +362,20 @@ Transaction.prototype.signWithKeys = function(keys, outputs, type) { * Signs a P2SH output at some index with the given key */ Transaction.prototype.p2shsign = function(index, script, key, type) { - script = new Script(script) - key = new ECKey(key) type = type || SIGHASH_ALL - var hash = this.hashTransactionForSignature(script, index, type), - sig = key.sign(hash).concat([type]) - return sig + var hash = this.hashTransactionForSignature(script, index, type) + return key.sign(hash).concat([type]) } Transaction.prototype.setScriptSig = function(index, script) { this.ins[index].script = script } -Transaction.prototype.validateSig = function(index, script, sig, pub) { - script = new Script(script) - var hash = this.hashTransactionForSignature(script,index,1) - return ecdsa.verify(hash, convert.coerceToBytes(sig), - convert.coerceToBytes(pub)) +Transaction.prototype.validateSig = function(index, script, pub, sig, type) { + type = type || SIGHASH_ALL + var hash = this.hashTransactionForSignature(script, index, type) + + return pub.verify(hash, sig) } Transaction.feePerKb = 20000 diff --git a/test/transaction.js b/test/transaction.js index dfc9fdd..425cace 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -171,11 +171,10 @@ describe('Transaction', function() { var key = ECKey.fromWIF('L44f7zxJ5Zw4EK9HZtyAnzCYz2vcZ5wiJf9AuwhJakiV4xVkxBeb') tx.sign(0, key) - var pub = key.pub.toBuffer() - var script = prevTx.outs[0].script.buffer + var script = prevTx.outs[0].script var sig = tx.ins[0].script.chunks[0] - assert.equal(tx.validateSig(0, script, sig, pub), true) + assert.equal(tx.validateSig(0, script, key.pub, sig), true) }) }) @@ -188,11 +187,10 @@ describe('Transaction', function() { it('returns true for valid signature', function(){ var key = ECKey.fromWIF('L44f7zxJ5Zw4EK9HZtyAnzCYz2vcZ5wiJf9AuwhJakiV4xVkxBeb') - var pub = key.pub.toBuffer() - var script = prevTx.outs[0].script.buffer + var script = prevTx.outs[0].script var sig = validTx.ins[0].script.chunks[0] - assert.equal(validTx.validateSig(0, script, sig, pub), true) + assert.equal(validTx.validateSig(0, script, key.pub, sig), true) }) }) From 1c52f9f3d839e5806267da36ff051bc70b8f11af Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 23 Apr 2014 05:34:39 +1000 Subject: [PATCH 3/7] Removes convert module --- test/transaction.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/transaction.js b/test/transaction.js index 425cace..07db8cf 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -1,5 +1,4 @@ var assert = require('assert') -var convert = require('../src/convert') var Address = require('../src/address') var ECKey = require('../src/eckey').ECKey @@ -13,6 +12,9 @@ var fixtureTx1Hex = fixtureTxes.prevTx var fixtureTx2Hex = fixtureTxes.tx var fixtureTxBigHex = fixtureTxes.bigTx +function b2h(b) { return new Buffer(b).toString('hex') } +function h2b(h) { return new Buffer(h, 'hex') } + describe('Transaction', function() { describe('deserialize', function() { var tx, serializedTx @@ -30,8 +32,9 @@ describe('Transaction', function() { it('returns the original after serialized again', function() { var actual = tx.serialize() - var expected = convert.hexToBytes(serializedTx) - assert.deepEqual(actual, expected) + var expected = serializedTx + + assert.equal(b2h(actual), expected) }) it('decodes version correctly', function(){ @@ -51,7 +54,7 @@ describe('Transaction', function() { assert.equal(input.outpoint.index, 0) assert.equal(input.outpoint.hash, "69d02fc05c4e0ddc87e796eee42693c244a3112fffe1f762c3fb61ffcb304634") - assert.equal(convert.bytesToHex(input.script.buffer), + assert.equal(b2h(input.script.buffer), "493046022100ef89701f460e8660c80808a162bbf2d676f40a331a243592c36d6bd1f81d6bdf022100d29c072f1b18e59caba6e1f0b8cadeb373fd33a25feded746832ec179880c23901") }) @@ -61,14 +64,14 @@ describe('Transaction', function() { var output = tx.outs[0] assert.equal(output.value, 5000000000) - assert.equal(convert.bytesToHex(output.script.toScriptHash()), "dd40dedd8f7e37466624c4dacc6362d8e7be23dd") + assert.equal(b2h(output.script.toScriptHash()), "dd40dedd8f7e37466624c4dacc6362d8e7be23dd") // assert.equal(output.address.toString(), "n1gqLjZbRH1biT5o4qiVMiNig8wcCPQeB9") // TODO: address is wrong because it's a testnet transaction. Transaction needs to support testnet }) it('assigns hash to deserialized object', function(){ var hashHex = "a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c" - assert.deepEqual(tx.hash, convert.hexToBytes(hashHex)) + assert.equal(b2h(tx.hash), hashHex) }) it('decodes large inputs correctly', function() { @@ -158,7 +161,7 @@ describe('Transaction', function() { var output = tx.outs[0] assert.equal(output.value, 40000) - assert.deepEqual(convert.bytesToHex(output.script.buffer), "76a9143443bc45c560866cfeabf1d52f50a6ed358c69f288ac") + assert.equal(b2h(output.script.buffer), "76a9143443bc45c560866cfeabf1d52f50a6ed358c69f288ac") } }) From fbf8211cab10def1a9ec3aa4ca57b777aec004fa Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 23 Apr 2014 05:35:44 +1000 Subject: [PATCH 4/7] Adds tests for TX.prototype.p2shsign --- test/transaction.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/transaction.js b/test/transaction.js index 07db8cf..68ddf84 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -6,6 +6,7 @@ var T = require('../src/transaction') var Transaction = T.Transaction var TransactionOut = T.TransactionOut var Script = require('../src/script') +var network = require('..').network var fixtureTxes = require('./fixtures/mainnet_tx') var fixtureTx1Hex = fixtureTxes.prevTx @@ -220,6 +221,33 @@ describe('Transaction', function() { }) }) + describe('p2shsign', function() { + var tx = new Transaction() + tx.addInput('deadbeefcafe', 0) + tx.addOutput('mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r', 1, network.testnet) + + var privKeys = [ + '5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf', + '5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAvUcVfH' + ].map(function(wif) { + return ECKey.fromWIF(wif) + }) + var pubKeys = privKeys.map(function(eck) { return eck.pub }) + var pubKeyBuffers = pubKeys.map(function(q) { return q.toBuffer() }) + var redeemScript = Script.createMultisigOutputScript(2, pubKeyBuffers) + + var signatures = privKeys.map(function(eck) { + return tx.p2shsign(0, redeemScript, eck) + }) + + var scriptSig = Script.createP2SHMultisigScriptSig(signatures, redeemScript) + tx.setScriptSig(0, scriptSig) + + var expected = '0100000001fecaefbeadde00000000fd1b0100483045022100a165904d2a3123ae887bd573b685e903a0ce158b1d21faba2ed4a42b3ca6126e02205f4e0e0cb333666d5b6b0b017fe0df0ac15a20f296a3fb8eab4e1572da2b3dea01473044022054e0cb54d62465a4003a2d0876048cde2b43dcab9385ffe173a2886bfa4d04b00220239811a8923887aa147d92987fa5c16f09a7fb7eea1d331c1a1d5303fd81f9c8014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0101000000000000001976a914751e76e8199196d454941c45d1b3a323f1433bd688ac00000000' + + assert.equal(b2h(tx.serialize()), expected) + }) + describe('TransactionOut', function() { describe('scriptPubKey', function() { it('returns hex string', function() { From 8ad8f6f169977da457c6459974bcc3c39ca3b750 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Sat, 26 Apr 2014 03:50:41 +1000 Subject: [PATCH 5/7] Renames p2shsign to signScriptSig --- src/transaction.js | 13 +++++-------- test/transaction.js | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/transaction.js b/src/transaction.js index 29590eb..d1974b2 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -312,15 +312,15 @@ Transaction.deserialize = function(buffer) { */ Transaction.prototype.sign = function(index, key, type, network) { assert(key instanceof ECKey) - type = type || SIGHASH_ALL network = network || Network.bitcoin var address = key.pub.getAddress(network.pubKeyHash) + + // FIXME: Assumed prior TX was pay-to-pubkey-hash var script = Script.createOutputScript(address, network) - var hash = this.hashTransactionForSignature(script, index, type) - var sig = key.sign(hash).concat([type]) - var scriptSig = Script.createInputScript(sig, key.pub) + var signature = this.signScriptSig(index, script, key, type) + var scriptSig = Script.createInputScript(signature, key.pub) this.setScriptSig(index, scriptSig) } @@ -358,10 +358,7 @@ Transaction.prototype.signWithKeys = function(keys, outputs, type) { } } -/** - * Signs a P2SH output at some index with the given key - */ -Transaction.prototype.p2shsign = function(index, script, key, type) { +Transaction.prototype.signScriptSig = function(index, script, key, type) { type = type || SIGHASH_ALL var hash = this.hashTransactionForSignature(script, index, type) return key.sign(hash).concat([type]) diff --git a/test/transaction.js b/test/transaction.js index 68ddf84..743f496 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -221,7 +221,7 @@ describe('Transaction', function() { }) }) - describe('p2shsign', function() { + describe('signScriptSig', function() { var tx = new Transaction() tx.addInput('deadbeefcafe', 0) tx.addOutput('mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r', 1, network.testnet) @@ -236,8 +236,8 @@ describe('Transaction', function() { var pubKeyBuffers = pubKeys.map(function(q) { return q.toBuffer() }) var redeemScript = Script.createMultisigOutputScript(2, pubKeyBuffers) - var signatures = privKeys.map(function(eck) { - return tx.p2shsign(0, redeemScript, eck) + var signatures = privKeys.map(function(privKey) { + return tx.signScriptSig(0, redeemScript, privKey) }) var scriptSig = Script.createP2SHMultisigScriptSig(signatures, redeemScript) From a4e68d142d7b48fb38ca09d653c11421da57e9a7 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Sat, 26 Apr 2014 03:51:01 +1000 Subject: [PATCH 6/7] Adds assertions for types in signScriptSig --- src/transaction.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/transaction.js b/src/transaction.js index d1974b2..c610056 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -360,6 +360,12 @@ Transaction.prototype.signWithKeys = function(keys, outputs, type) { Transaction.prototype.signScriptSig = function(index, script, key, type) { type = type || SIGHASH_ALL + + assert(Number.isFinite(index) && (index >= 0), 'Invalid vin index') + assert(script instanceof Script, 'Invalid Script object') + assert(key instanceof ECKey, 'Invalid private key') +// assert.equal(type & 0x7F, type, 'Invalid type') // TODO + var hash = this.hashTransactionForSignature(script, index, type) return key.sign(hash).concat([type]) } From 69c0497038478fe7bf9bc68d05a5d0c439b25bd5 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Sat, 26 Apr 2014 03:58:25 +1000 Subject: [PATCH 7/7] Renames createInputScript to createPubKeyHashScriptSig --- src/script.js | 2 +- src/transaction.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/script.js b/src/script.js index 003e95f..793f227 100644 --- a/src/script.js +++ b/src/script.js @@ -419,7 +419,7 @@ Script.createMultisigOutputScript = function(m, pubKeys) { } // {signature} {pubKey} -Script.createInputScript = function(signature, pubKey) { +Script.createPubKeyHashScriptSig = function(signature, pubKey) { var script = new Script() script.writeBytes(signature) script.writeBytes(pubKey.toBuffer()) diff --git a/src/transaction.js b/src/transaction.js index c610056..f346125 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -320,7 +320,7 @@ Transaction.prototype.sign = function(index, key, type, network) { var script = Script.createOutputScript(address, network) var signature = this.signScriptSig(index, script, key, type) - var scriptSig = Script.createInputScript(signature, key.pub) + var scriptSig = Script.createPubKeyHashScriptSig(signature, key.pub) this.setScriptSig(index, scriptSig) }