From f5ce83beca59a8561a9634d6460fb42fc911d62b Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 18 Apr 2014 08:33:29 +1000 Subject: [PATCH] Adds working implementation of Script.createP2SHMultisigScriptSig --- src/script.js | 52 ++++++++++++++++++++++++++++-------------------- test/script.js | 54 +++++++++++++++++++++++++------------------------- 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/src/script.js b/src/script.js index 5525f48..d8fe623 100644 --- a/src/script.js +++ b/src/script.js @@ -402,26 +402,22 @@ Script.prototype.extractPubkeys = function() { }) } -/** - * Create an m-of-n output script - */ -Script.createMultiSigOutputScript = function(m, pubkeys) { +// m [pubKeys ...] n OP_CHECKMULTISIG +Script.createMultisigOutputScript = function(m, pubKeys) { var script = new Script() - pubkeys = pubkeys.sort() + pubKeys = pubKeys.sort() script.writeOp(Opcode.map.OP_1 + m - 1) - for (var i = 0; i < pubkeys.length; ++i) { - script.writeBytes(pubkeys[i]) + for (var i = 0; i < pubKeys.length; ++i) { + script.writeBytes(pubKeys[i]) } - script.writeOp(Opcode.map.OP_1 + pubkeys.length - 1) + script.writeOp(Opcode.map.OP_1 + pubKeys.length - 1) script.writeOp(Opcode.map.OP_CHECKMULTISIG) return script } -/** - * Create a standard payToPubKeyHash input. - */ +// {signature} {pubKey} Script.createInputScript = function(signature, pubKey) { var script = new Script() script.writeBytes(signature) @@ -429,25 +425,37 @@ Script.createInputScript = function(signature, pubKey) { return script } -/** - * Create a multisig input - */ -Script.createMultiSigInputScript = function(signatures, script) { - script = new Script(script) - var k = script.chunks[0][0] - - //Not enough sigs - if (signatures.length < k) return false; - +// OP_0 [signatures ...] +Script.createMultisigScriptSig = function(signatures) { var inScript = new Script() + inScript.writeOp(Opcode.map.OP_0) signatures.map(function(sig) { inScript.writeBytes(sig) }) - inScript.writeBytes(script.buffer) + + return inScript +} + +// {serialized scriptPubKey script} +Script.createP2SHScriptSig = function(scriptSig, scriptPubKey) { + var inScript = new Script(scriptSig.buffer) + inScript.writeBytes(scriptPubKey.buffer) return inScript } +// [signatures ...] {m [pubKeys ...] n OP_CHECKSIG} +Script.createP2SHMultisigScriptSig = function(signatures, scriptPubKey) { + assert(isMultisig.call(scriptPubKey)) + + var m = scriptPubKey.chunks[0] + var k = m - (Opcode.map.OP_1 - 1) + assert(k <= signatures.length, 'Not enough signatures provided') + + var scriptSig = Script.createMultisigScriptSig(signatures) + return Script.createP2SHScriptSig(scriptSig, scriptPubKey) +} + Script.prototype.clone = function() { return new Script(this.buffer) } diff --git a/test/script.js b/test/script.js index 3229e4e..3d15610 100644 --- a/test/script.js +++ b/test/script.js @@ -102,42 +102,42 @@ describe('Script', function() { }) describe('2-of-3 Multi-Signature', function() { - var compressedPubKeys = [] - var numSigs, script, multisig + var pubKeys beforeEach(function() { - compressedPubKeys = ['02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f', + pubKeys = [ + '02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f', '02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f', - '036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19'].map(h2b) - numSigs = 2 + '036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19' + ].map(h2b) }) - it('should create valid multi-sig address', function() { - script = Script.createMultiSigOutputScript(numSigs, compressedPubKeys) - multisig = crypto.hash160(script.buffer) - var multisigAddress = new Address(multisig, network.bitcoin.scriptHash) + it('should create valid redeemScript', function() { + var redeemScript = Script.createMultisigOutputScript(2, pubKeys) + + var hash160 = crypto.hash160(redeemScript.buffer) + var multisigAddress = new Address(hash160, network.bitcoin.scriptHash) - assert.equal(multisigAddress.version, network.bitcoin.scriptHash) assert.equal(multisigAddress.toString(), '32vYjxBb7pHJJyXgNk8UoK3BdRDxBzny2v') }) + }) - it('should create valid redeemScript', function() { - var redeemScript = script.buffer - var deserialized = new Script(redeemScript) - var numOfSignatures = deserialized.chunks[deserialized.chunks.length - 2] - 80 - var signaturesRequired = deserialized.chunks[0] - 80 - var sigs = [ - b2h(deserialized.chunks[1]), - b2h(deserialized.chunks[2]), - b2h(deserialized.chunks[3]) - ] - - assert.equal(numOfSignatures, 3) - assert.equal(signaturesRequired, 2) - assert.equal(sigs[0], '02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f') - assert.equal(sigs[1], '02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f') - assert.equal(sigs[2], '036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19') - assert.equal(new Address(crypto.hash160(redeemScript), network.bitcoin.scriptHash).toString(), '32vYjxBb7pHJJyXgNk8UoK3BdRDxBzny2v') + describe('2-of-2 Multisig scriptSig', function() { + var pubKeys = [ + '02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1', + '0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a' + ].map(h2b) + var signatures = [ + '304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801', + '3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501' + ].map(h2b) + var expected = '0047304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801483045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d14050147522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae' + + it('should create a valid P2SH multisig scriptSig', function() { + var redeemScript = Script.createMultisigOutputScript(2, pubKeys) + var actual = Script.createP2SHMultisigScriptSig(signatures, redeemScript) + + assert.equal(b2h(actual.buffer), expected) }) }) })