3

I have been using the Bitcoin Wiki to know more about the CHECKSIG, and the graphic which is shown there.

This question will be rather long, but it would already help me a lot if you could just read my description and just let me know if I am correct or wrong.

My question is regarding how to calculate the hash (from the serialized transaction) which is then signed.

Generally the way I understand it, we first create a new raw transaction with input and outputs with pubKeyScripts.

Then to create the signature, we copy the pubKeyScript from the transaction we are spending into the SigScript at the input of our new transaction. Then we serialize the new transaction, appending to the string the hashType (SIGHASH_ALL/SIGHASH_NONE, etc.) and then create the signature for that string.

Then we clear the SigScript and put the public key and signature into the SigScript and have a signed transaction. When the bitcoin network validates the transaction it will create the serialized transaction string in a smiliar manner and check that the signature delivered in the SigScript of the new transaction is for the calculated string (and from the correct private key).

First of all is this correct? And if so, why is the pubKeyScript of the transaction we are spending used when calculating the serialized string of the new transaction we want to sign?

The new transaction is already referncing the ID of the spending transaction in the input of the new one. Therefore I cannot see why it is useful to also temporary copy the pubKeyScript of the spending transaction into the SigScript of the new transaction to make the signature?

Furthermore, I was trying to look in the source code from Bitcoin to find out what happens. I am not a programmer, escpecially not in C++. But I found out that the signature is checked here: https://github.com/bitcoin/bitcoin/blob/48efbdbe986355bd2478f0fdd366b20952fbf30a/src/script/interpreter.cpp#L847

The referehnce to "scriptCode" in line 838, which is used as argument to checker.CheckSig() seems to contain only the pubKeyScript from the transaction being spend (without input, outputs, etc. from the new transaction?).

I was not able to find out where exactly in the source code the function checker.CheckSig() is defined.

But does checker.CheckSig calculate the serialized transaction as I have described above by adding the scriptCode into the SigScript and serialize it? If so do you know where in the source code that happens?

I hope you can give me some inputs to it. Thank you!

3
  • Minor quibble: usually it's written scriptSig and scriptPubKey, not the other way around.
    – Nick ODell
    Sep 30, 2015 at 18:02
  • 1
    Also, we had a discussion about this recently in Bitcoin Lounge (prompted by your other question, actually) chat.stackexchange.com/transcript/message/24348979#24348979 The upshot is that the FindAndDelete call in the sourcecode you linked is not the only place the signature is removed before signing.
    – Nick ODell
    Sep 30, 2015 at 18:07
  • Nice pointing out in the Bitcoin Lounge the serialization in the code! github.com/bitcoin/bitcoin/blob/… So the scriptPubKey from the transaction referenced in the input of the new (spending) transaction is clearly used and probably the signing works as shown in the figure. I just wonder why that Script is used in the serialization? Sep 30, 2015 at 20:21

1 Answer 1

3

The purpose of signatures is to 'capture' some data about the transaction - it's outputs, and so on. Signers have control over some of it, using SIGHASH flags, but some of it is enforced by the network.

Remember that anyone verifying your signatures needs to know what you're asserting in your signature, and how to reproduce the same hash for ECDSA.

When producing the signature, and verifying one, SignatureHash() is called on every input, because each input has it's own signatures.

For each input, the transaction reserialized with a CTransactionSignatureSerializer which makes the input-specific modifications to the transaction. It will null inputs/outputs given some SIGHASH flags, and also requires that the scriptPubKey of the previous transaction is included.

It seems you were enquiring partly about this. The reason for capturing this through a hash is it means the signature can't be used on other transactions. A signature is only valid for a given input, and all the requirements of its scriptPubKey.

Hence, you will find that services which verify signatures need to have the scriptPubKey of the transaction being signed for.

Edit: Actually, more specifically, what is included as the script while signing is any script starting from the last OP_CODESEPARATOR, or from the beginning of the output script. So if the script contains OP_CODESEPARATOR, only a part of the output script is signed.

One point where you appear confused is this:

Then we clear the SigScript and put the public key and signature into the SigScript and have a signed transaction

This is not correct - the serialized form is forgotten once the hash is produced. Signatures are put into different transaction instance.

checker.CheckSig() code - Note that it calls the SignatureHash() to produce the hash, and then VerifySignature() calls pubkey.Verify(sighash, vchSig) which is the actual call to ECDSA.

So, most of what you're looking for verification-wise is at the bottom of interpreter.cpp, but also check out interpreter.h for the interfaces.

2
  • Thanks for the answer. I still don't understand why the scriptPubKey of previous transaction is included for the signature. The input already contains the transaction-hash and index to the previous output being spend. What is then the benefit of including the scriptPubKey from that previous transaction-output in the signature? The signature can only be used for transactions containing exactly that specific transaction-hash referenced in the input. And the scriptPubKey is typically the same for all outputs to a same bitcoin address (dup hash160 "bitcoin-address" equalverify checksig) Oct 2, 2015 at 19:55
  • Hi, I've updated my answer (see the edit). Not clear on benefits, but the data included in this part of the hashed transaction can sometimes be a subset of the scriptPubKey, if OP_CODESEPARATOR is used. There are varying reports as to whether its useful feature to have, it's rarely used. Let me know if this answers things for you!
    – karimkorun
    Dec 18, 2015 at 16:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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