4

I'm trying to create my own transaction from scratch, just to see how it works.

I'm currently working backwards, and I'm stuck on the signature of a transaction...

Here's my unsigned transaction:

0100000001ff8ddda903d6e76b6c6211e1b8f3b4eaaa8d080aaa008d4b05ca01ea39116cbf0000000000ffffffff0170c9fa02000000001976a9147865b0b301119fc3eadc7f3406ff1339908e46d488ac00000000

Here's my signed transaction (I have highlighted the signature):

0100000001ff8ddda903d6e76b6c6211e1b8f3b4eaaa8d080aaa008d4b05ca01ea39116cbf000000006b | 483045022100a385d7fb16a0de4ba101145c77c0eafc4840a61b41fc94733578a7d40c14def6022014ce25daa359db1bb3489db063cc0864601609f69d6ad15b490c13c27f86ab700121 | 02e4e8b42bf9fdf18895a9574e6f5fd01ebfa594bf51e8f8ad156638aee6223918ffffffff0170c9fa02000000001976a9147865b0b301119fc3eadc7f3406ff1339908e46d488ac00000000

I like to think I understand each segment of this serialized transaction. However, I don't know how to recreate the signature. I know I need to create a message and send it through an ECDSA signing function, but I do not know how to construct the message.

So basically, what goes in to the message to create a signature for this transaction?

  • 1
    Perhaps you can explain the details of what you did to create those binary strings. It may be easier to spot the error in what you did, rather than us trying to parse the output. – Nate Eldredge Apr 26 '15 at 14:48
10

The message whose numerically interpreted hash, z, is used to construct the ECDSA signature (r,s) is constructed as follows:

  1. Start with your unsigned transaction.
  2. Remove all scriptSigs (for example, if you have multiple txins, some of which may already be signed, remove those signatures). For your example this step has no effect since there's only one txin.
  3. For the txin you're about to sign, find the corresponding UTXO's scriptPubKey, and set the current txin's scriptSig to be the value of the UTXO's scriptPubKey.
  4. Serialize the transaction.
  5. Append the SIGHASH type, serialized as a 32-bit little-endian integer (the default SIGHASH_ALL has a value of 1).

The resulting byte stream is double SHA-256 hashed and interpreted as a big-endian integer (and used for ECDSA's z parameter).

For your example, the scriptPubKey to insert comes from the UTXO at txid bf6c1139ea01ca054b8d00aa0a088daaeab4f3b8e111626c6be7d603a9dd8dff index 0, specifically it is OP_DUP OP_HASH160 d951eb562f1ff26b6cbe89f04eda365ea6bd95ce OP_EQUALVERIFY OP_CHECKSIG. Serialized, this is 76a914d951eb562f1ff26b6cbe89f04eda365ea6bd95ce88ac. The transaction constructed after completing step 3 is:

"txid" : "a80d616ca30a003448157b92df511ad5294e225fd77fc3f2d5dc367a4d27f375",
"version" : 1,
"locktime" : 0,
"vin" : [
    {
        "txid" : "bf6c1139ea01ca054b8d00aa0a088daaeab4f3b8e111626c6be7d603a9dd8dff",
        "vout" : 0,
        "scriptSig" : {
            "asm" : "OP_DUP OP_HASH160 d951eb562f1ff26b6cbe89f04eda365ea6bd95ce OP_EQUALVERIFY OP_CHECKSIG",
            "hex" : "76a914d951eb562f1ff26b6cbe89f04eda365ea6bd95ce88ac"
        },
        "sequence" : 4294967295
    }
],
"vout" : [
    {
        "value" : 0.49990000,
        "n" : 0,
        "scriptPubKey" : {
            "asm" : "OP_DUP OP_HASH160 7865b0b301119fc3eadc7f3406ff1339908e46d4 OP_EQUALVERIFY OP_CHECKSIG",
            "hex" : "76a9147865b0b301119fc3eadc7f3406ff1339908e46d488ac",
            "reqSigs" : 1,
            "type" : "pubkeyhash",
            "addresses" : [
                "1Bybuago2EGrB7Z6jJG2GAFDojp6Njr8fa"
            ]
        }
    }
]

It may look strange to have a scriptPubKey-style script in the scriptSig field, but that's the way it is. Once serialized, this becomes:

1: 0100000001ff8ddda903d6e76b6c6211e1b8f3b4eaaa8d080aaa008d4b05ca01ea39116cbf0000000019
2: 76a914d951eb562f1ff26b6cbe89f04eda365ea6bd95ce88ac
3: ffffffff0170c9fa02000000001976a9147865b0b301119fc3eadc7f3406ff1339908e46d488ac00000000
4: 01000000

Above, line 2 is the serialized scriptPubKey, and line 4 is the appended SIGHASH_ALL. This full message is then hashed and interpreted as an int, resulting in z=78289050778760245857840977078575435990304898491073736369300700378208907476567, which along with the private key is used to finally create the ECDSA signature.

Note that step 2 above assumes a SIGHASH_ALL signature. Other signature types remove additional parts of the transaction before signing, please see the SIGHASH types link for more details.

  • This is absolutely marvelous, thank you. How do I get this OP_DUP OP_HASH160 d951eb562f1ff26b6cbe89f04eda365ea6bd95ce OP_EQUALVERIFY OP_CHECKSIG in to this 76a914d951eb562f1ff26b6cbe89f04eda365ea6bd95ce88ac ? – inersha May 1 '15 at 11:01
  • @inersha Here are two possible ways: (1) via bitcoind's JSON-RPC API, e.g. run (or enter in via the console) this: bitcoin-cli createrawtransaction '[{"txid":"00", "vout":0}]' '{"1Lp5mUmmaNqu5ABrV1KjwL1p2VLKhvcAdG":1}' and then take the result and run this: bitcoin-cli decoderawtransaction <result>. (2) by hand, see here for an example: bitcoin.org/en/developer-reference#txout (and look above the example for the op code list). – Christopher Gurnee May 1 '15 at 14:03
  • Can you comment on how a node recreates the message during verification? – Jus12 Dec 26 '17 at 5:26
  • 1
    Since it has access to the serialized full transaction via the Bitcoin p2p network (or its local on-disk blockchain), it deserializes the transaction and then goes through the same steps as above. – Christopher Gurnee Dec 30 '17 at 14:56

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.