1

I am creating a 2-of-3 multisig wallet, where the 2 hot keys are external HSM devices. I am using Bcoin to create my transactions. After the transactions are created, I will send the raw transaction to an external application to do the signing.

My question is, which part exactly needs to be signed by the private key?

For example, this is my transaction:

{
    "hash": "e82c7bdfc864ab4d0592045dd86b81a438eeee77f8415c0a84e1aa0ea8e17786",
    "witnessHash": "e82c7bdfc864ab4d0592045dd86b81a438eeee77f8415c0a84e1aa0ea8e17786",
    "fee": 1000000,
    "rate": 4424778,
    "mtime": 1568880046,
    "version": 1,
    "inputs": [
        {
            "prevout": {
                "hash": "3b1dd17cc82e2ac43ba62bf8f1c6a0fe805df43911653d22c902571eb3a212ce",
                "index": 0
            },
            "script": "000000004c6952210209ad6cf408e41362fa175d5869e4561f1890c0d8d74353c86095fdecde34459721024a92aa3f883cc4438b75205555e517a4f7cc10ffd42517297a17821ae6f0bb8821037d2a259a52f62fee96fea072844139224fbd9027116ac7582025dd446fc73e3e53ae",
            "witness": "00",
            "sequence": 4294967295,
            "coin": {
                "version": 1,
                "height": -1,
                "value": 10000000000,
                "script": "a9144de6d3580732a7c7c2b1eb043cb1b89350c265fa87",
                "address": "38nvUMbXFdXDp4PTWvbohCbnPJuLUVwzXr",
                "coinbase": false
            }
        }
    ],
    "outputs": [
        {
            "value": 5000000000,
            "script": "a91481be67198d33319415d09b03f2dc2cfa4cdb42aa87",
            "address": "3DX3BhmdRGf5vYbtzHKzazGmZ7WgUkhFRk"
        },
        {
            "value": 4999000000,
            "script": "a9144de6d3580732a7c7c2b1eb043cb1b89350c265fa87",
            "address": "38nvUMbXFdXDp4PTWvbohCbnPJuLUVwzXr"
        }
    ],
    "locktime": 0,
    "hex": "0100000001ce12a2b31e5702c9223d651139f45d80fea0c6f1f82ba63bc42a2ec87cd11d3b000000006f000000004c6952210209ad6cf408e41362fa175d5869e4561f1890c0d8d74353c86095fdecde34459721024a92aa3f883cc4438b75205555e517a4f7cc10ffd42517297a17821ae6f0bb8821037d2a259a52f62fee96fea072844139224fbd9027116ac7582025dd446fc73e3e53aeffffffff0200f2052a0100000017a91481be67198d33319415d09b03f2dc2cfa4cdb42aa87c0aff6290100000017a9144de6d3580732a7c7c2b1eb043cb1b89350c265fa8700000000"
}

If you decode the script in the inputs it is:

OP_0 OP_0 OP_0 OP_0 52210209ad6cf408e41362fa175d5869e4561f1890c0d8d74353c86095fdecde34459721024a92aa3f883cc4438b75205555e517a4f7cc10ffd42517297a17821ae6f0bb8821037d2a259a52f62fee96fea072844139224fbd9027116ac7582025dd446fc73e3e53ae

As you can see there are 4 OP_0 placeholders to input the signatures. Now my question is, which part of the transaction the external signing application should sign. Is it just the 000000004c6952210209ad6cf408e41362fa175d5869e4561f1890c0d8d74353c86095fdecde34459721024a92aa3f883cc4438b75205555e517a4f7cc10ffd42517297a17821ae6f0bb8821037d2a259a52f62fee96fea072844139224fbd9027116ac7582025dd446fc73e3e53ae part?

Any reference is highly appreciated. I have read https://en.bitcoin.it/wiki/Transaction and https://en.bitcoin.it/wiki/OP_CHECKSIG but I can't figure out for sure. Thank you.

2

The Bitcoin Wiki entry for OP_CHECKSIG answers your question. OP_CHECKMULTISIG works the same way, just applied to each signature in the sequence.

First of all, it depends on the SIGHASH type you, as the signer, choose. Most likely you will use the default SIGHASH_ALL for each of the required signatures, but you could actually use different SIGHASH methods for each individual signature.

Since you mentioned bcoin, you can review the signature hash methods in lib/primitives/tx.js here, and in the methods immediately following.

Very briefly:

The SIGHASH_ALL method will serialize all the inputs* and all the outputs of the transaction, including the nLocktime, and sign that blob.

*The input scripts are all replaced with a sinlge 0x00 byte. The script of the input being signed/checked is replaced by the corresponding output script from the funding transaction. So actually, the hex string you posted (the templated input script 000000004c695...) is the only part of the transaction that will NOT be signed by any of the multisig participants for this input!

bonus tidbit: The 2-of-3 signature template has FOUR OP_0's. Why? Well. the first one is popped off the stack by OP_CHECKMULTISIG, that's a bug Satoshi left us with. The other three are placeholders for the actual signatures. There are THREE instead of just TWO because the signatures need to be in the same order as the pubKeys in the redeem script. The extra placeholder is removed before broadcasting the transaction. In bcoin, this script template is assembled here.

  • thank you very much. Can you please elaborate what will be signed in the case there are multiple inputs with different multisig scripts for each of them. Each time the transaction is signed, are all the inputs replaced by 0x00 for all the inputs? Thank you. – madu Sep 19 at 13:12
  • 1
    Yes, in SIGHASH_ALL, each input signs the same scheme: 0x00 for every input script except the input being signed, where the script is replaced with the previous txs' output script. – pinhead Sep 19 at 14:54
  • Thank you pinhead. Makes it clear now. – madu Sep 20 at 4:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.