Merge pull request #143 from dcousens/multisigfix
Multi-sig ScriptSig Support
This commit is contained in:
commit
21aa517cd2
2 changed files with 59 additions and 51 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue