Merge pull request #143 from dcousens/multisigfix

Multi-sig ScriptSig Support
This commit is contained in:
Kyle Drake 2014-04-21 09:39:03 -07:00
commit 21aa517cd2
2 changed files with 59 additions and 51 deletions

View file

@ -402,26 +402,22 @@ Script.prototype.extractPubkeys = function() {
}) })
} }
/** // m [pubKeys ...] n OP_CHECKMULTISIG
* Create an m-of-n output script Script.createMultisigOutputScript = function(m, pubKeys) {
*/
Script.createMultiSigOutputScript = function(m, pubkeys) {
var script = new Script() var script = new Script()
pubkeys = pubkeys.sort() pubKeys = pubKeys.sort()
script.writeOp(Opcode.map.OP_1 + m - 1) script.writeOp(Opcode.map.OP_1 + m - 1)
for (var i = 0; i < pubkeys.length; ++i) { for (var i = 0; i < pubKeys.length; ++i) {
script.writeBytes(pubkeys[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) script.writeOp(Opcode.map.OP_CHECKMULTISIG)
return script return script
} }
/** // {signature} {pubKey}
* Create a standard payToPubKeyHash input.
*/
Script.createInputScript = function(signature, pubKey) { Script.createInputScript = function(signature, pubKey) {
var script = new Script() var script = new Script()
script.writeBytes(signature) script.writeBytes(signature)
@ -429,25 +425,37 @@ Script.createInputScript = function(signature, pubKey) {
return script return script
} }
/** // OP_0 [signatures ...]
* Create a multisig input Script.createMultisigScriptSig = function(signatures) {
*/
Script.createMultiSigInputScript = function(signatures, script) {
script = new Script(script)
var k = script.chunks[0][0]
//Not enough sigs
if (signatures.length < k) return false;
var inScript = new Script() var inScript = new Script()
inScript.writeOp(Opcode.map.OP_0) inScript.writeOp(Opcode.map.OP_0)
signatures.map(function(sig) { signatures.map(function(sig) {
inScript.writeBytes(sig) inScript.writeBytes(sig)
}) })
inScript.writeBytes(script.buffer)
return inScript return inScript
} }
// <scriptSig> {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() { Script.prototype.clone = function() {
return new Script(this.buffer) return new Script(this.buffer)
} }

View file

@ -102,42 +102,42 @@ describe('Script', function() {
}) })
describe('2-of-3 Multi-Signature', function() { describe('2-of-3 Multi-Signature', function() {
var compressedPubKeys = [] var pubKeys
var numSigs, script, multisig
beforeEach(function() { beforeEach(function() {
compressedPubKeys = ['02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f', pubKeys = [
'02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f',
'02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f', '02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f',
'036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19'].map(h2b) '036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19'
numSigs = 2 ].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)
assert.equal(multisigAddress.version, network.bitcoin.scriptHash)
assert.equal(multisigAddress.toString(), '32vYjxBb7pHJJyXgNk8UoK3BdRDxBzny2v')
}) })
it('should create valid redeemScript', function() { it('should create valid redeemScript', function() {
var redeemScript = script.buffer var redeemScript = Script.createMultisigOutputScript(2, pubKeys)
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) var hash160 = crypto.hash160(redeemScript.buffer)
assert.equal(signaturesRequired, 2) var multisigAddress = new Address(hash160, network.bitcoin.scriptHash)
assert.equal(sigs[0], '02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f')
assert.equal(sigs[1], '02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f') assert.equal(multisigAddress.toString(), '32vYjxBb7pHJJyXgNk8UoK3BdRDxBzny2v')
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)
}) })
}) })
}) })