4

I have the 32-bytes double hash of a transaction, a 32-bytes private key, and I would like to sign the hash using the private key.

How do I do that using BouncyCastle (or anything, really), in C# or Java? Can somebody point me to a code sample?

2

The 32-byte double-SHA256 of a transaction (TxID) is not what gets signed.

Future-proofing note: The description herein of transactions, TxID calculation, signatures and signatures scripts, etc. don't apply to segregated witness.

Let's look at an example with a transaction I created earlier. I called:

createrawtransaction '[{"txid":"0c71ea829dfb117442c1c0d0c492725794d890bbcbcd8234b1108d1b1d4ca2e9","vout":1}]' '{"1PkCAVKjPz1YK7iJwT8xTLxBXR1av8dL98":0.004}'

which created an (unsigned) transaction:

0100000001e9a24c1d1b8d10b13482cdcbbb90d894577292c4d0c0c1427411fb9d82ea710c0100000000ffffffff01801a0600000000001976a914f97df8f593e0056d337c274fd81a163f47a17d3788ac00000000

And then I asked bitcoin-rpc to sign the transaction, and received:

0100000001e9a24c1d1b8d10b13482cdcbbb90d894577292c4d0c0c1427411fb9d82ea710c010000006b483045022100d9a5433c1381b39b7e02b0b0f042990e7c16cfea252b05ccfef2e85c2dab2a6f022057c7def782fe3b0d7e5e0eae277d2a5890844da7d72309817a2dac22a6307c6001210390d78cb0c1d34d4417db7e0a9a9f125a689dc29dc2197a01a5f827a20f870f62ffffffff01801a0600000000001976a914f97df8f593e0056d337c274fd81a163f47a17d3788ac00000000

Here is that signed transaction data again, with the signature and related script data bolded: 0100000001e9a24c1d1b8d10b13482cdcbbb90d894577292c4d0c0c1427411fb9d82ea710c010000006b483045022100d9a5433c1381b39b7e02b0b0f042990e7c16cfea252b05ccfef2e85c2dab2a6f022057c7def782fe3b0d7e5e0eae277d2a5890844da7d72309817a2dac22a6307c6001210390d78cb0c1d34d4417db7e0a9a9f125a689dc29dc2197a01a5f827a20f870f62ffffffff01801a0600000000001976a914f97df8f593e0056d337c274fd81a163f47a17d3788ac00000000

If you look at the unsigned transaction, all of the material before and after that bolded section is identical (aside from one padding byte which turned from 0x00 to 0x62), because only one signature (and associated script) was required to successfully spend the input.

Here's a visual diff between the decoded versions of the unsigned transaction (left) and the signed transaction (right):

Difference between decoded unsigned and signed simple Bitcoin transactions

You'll see that the unsigned transaction has a different txid (because the TxID is the hash of the full, signed transaction). Additionally, you'll see that the unsigned transaction does not have the scriptSig, whereas the signed transaction does. The scriptSig is the bolded inserted section from earlier.

To get back to your question, signing a transaction requires access to the actual transaction (rather than just the hash), because you need to sign the transaction data itself AND insert the signature into the transaction.

On a side-note, since the signature script is part of the data which is hashed to produce the TxID, the signature can actually be modified to still be a valid signature for the data. The signature signs a hash of other portions of the transaction so those can't be altered, but nothing protects the signature script itself from modifications. Any modification to the signature script which doesn't change the functionality of the signature script changes the TxID without invalidating the transaction.

Say you propagate a transaction to the network which sends Bob 2 BTC. Any peer (including block miners) could manipulate the script signature to appear differently while still validly signing the transaction. While this doesn't allow them to redirect those 2 BTC from Bob to anyone else, this modification does change the TxID of the transaction. If someone were waiting for the original TxID to be propagated across the network, it would appear that the transaction never executed if the modified transaction is included into a block instead.

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.