I understand the basic concept ECDSA where if Bob wants to sign a message it generates a random number n, multiply it with the secp256k1, r = the x value , s = (H(x)dr)*n^-1 mod q. Also the verification is done by P=u1(G)+u2(P), where G is the generation point, and P as the public key of Bob.

I went through the transaction page of wiki. My understanding is that ECDSA takes place somewhere in the scriptSig/scriptPubKey section.

If Bob wants to spend the unspent transaction output, Bob will need to create a signature script that references to previous transactions, also provide his full public key, which will then be hashed to match previous transactions as the receiver, Bob will also need to generate a signature to prove that public key is originated from his public key.

It leaves me with a lot of questions such as the Transaction Verification steps:OP_CHECKSIG where I'm guessing most of the steps are trying to match the hash, and finally at step 10 it performs the ECDSA verification.

Does it still follow the basic concept computing u1, u2 and utilizing the full public key provided by Bob trying to match the r value at the end? Or is it doing something totally different? I can understand why pubKeyStr and sigStr is required for the ECDSA verification, but it also takes in sha256^2, which i guess is double hashing, with the (verifThisStr). I do not understand where that came from at all.

What would be substituted into the hashed message H(x) when computing s? And does Bob just randomly pick a variable just to generate the signature when it was asked for claiming the unspent transaction?

2 Answers 2


Let us take "pizza transaction" https://blockchain.info/tx/cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79


// decoded by https://blockchain.info/decode-tx
         "script_string":"OP_DUP OP_HASH160 df1bd49a6c9e34dfa8631f2c54cf39986027501b OP_EQUALVERIFY OP_CHECKSIG",
         "script_string":"04cd5e9726e6afeae357b1806be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce3388fa1abd0fa88b06c44ce81e2234aa70fe578d455d OP_CHECKSIG",

Look and decode at the input=0 script:

48  // push next 0x48 bytes
41  // push next 0x41 bytes

First push is signature concatenated with hashtype=01 (SIGHASH_ALL)

Second push is public key for address 17SkEw2md5avVNyYgj6RiXuQKNwkXaxFyQ

How do we check - is this transaction valid? Is it correctly signed?

1) Remove input script from transaction. We should remove bytes (do not forget about script len)


2) Replace it with the funding script to 17SkEw2md5avVNyYgj6RiXuQKNwkXaxFyQ

OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG

(Do not forget about script length again!)

3) Append SIGHASH_ALL as 32-bit low-endian value. The result will be


4) Hash it twice by SHA256. The digest will be 692678553d1b85ccf87d4d4443095f276cdf600f2bb7dd44f6effbd7458fd4c2

5) OK, we have now three items:

  • a) public key 042e930f39ba62c6[...cut...]6e59667ce9c4e9dcebcabb
  • b) signature 304502210099081[...cut...]d59290d2fddf25269ee0e
  • c) digest 692678553d1b85ccf87d4d4443095f276cdf600f2bb7dd44f6effbd7458fd4c2

Pass these values to standard ECDSA verify method and you will receive the result: true or false. Here is a small piece of my quick-and-dirty check whith hardcoded values:

const QByteArray xx ( QByteArray::fromHex ( "01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d41"
                                            "88fa1abd0fa88b06c44ce81e2234aa70fe578d455dac0000000001000000" ) );
const MyKey32 digest ( xx.constData ( ), xx.size ( ) ); // construct object of sha256 (sha256 ( xx ) )
_trace ( digest.toString ( ) );                         // print result
const QByteArray pubkey ( QByteArray::fromHex ( "042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb" ) );
const QByteArray signature ( QByteArray::fromHex ( "30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e" ) );
_trace ( QString ( "verify=%1" ).arg ( digest.verify ( pubkey, signature ) ) );

The output is

  • The brief run through is very useful , there are a few more minor questions regarding to it. I might be still confused, but I'll try to make sense of it .After the input script removal (Step1) , Replace with funding scrip(Step2) Append SIGHASH_ALL(Step3), which is the new transaction. According to the other answer , for the signiture s= (H(x)*d*r)n^-1 mod q,where H(x) is everything in raw tx , I'd assume that is exactly like the digest(?) So the Signature (304502...ee0e)is generated by using the digest (692678...d4c2) ,tempkey(random)and the private key ?
    – Kuriz
    Nov 4, 2014 at 18:40
  • If so , I see that your ECDSA varification only takes in 2 inputs , which is pubkey and signiture. Out put was the digest. Since the basic concept utilizes u1, and u2. It was matching u1(G)+u2(B) , which B= pulic key , G= generation point , u1 = H(x)*s^-1 , u2 = rds-1*n, where the cancellation occurs leaves n*G's x-coordinate = r = varify. But since our key.verify doesn't include the digest, is it using a different method ? by regenerating the digest with the publickey and signature?
    – Kuriz
    Nov 4, 2014 at 18:46
  • I have my own lib. Class MyKey32 is a class for performing some actions. So, the last line can be written as "digest.verify ( pubkey, signature )" where digest - is 32-byte object
    – amaclin
    Nov 5, 2014 at 5:20
  • I've edited my post.
    – amaclin
    Nov 5, 2014 at 5:28
  • 1
    >So the Signature (304502...ee0e)is generated by using the digest (692678...d4c2) ,tempkey(random)and the private key?<<< Yes! The owner of private key created in 2010 the same array of bytes, calculated digest (the same as mine, or to be correct: mine is the same as his) and created signature with privkey and digest. For creating signature he need privkey and digest. For verifying signature we need pubkey and digest.
    – amaclin
    Nov 5, 2014 at 10:48

Question is does it still follow the basic concept computing u1,u2 and utilizing the full public key provided by Bob trying to match the r value at the end ?

Yes, that's the basic idea, why would you think it was any different? There's a slightly complicated way that the hash that needs to be signed is calculated, but once the hash is calculated it's just straight ECDSA treating the hash as a 256 bit integer.

it also takes in sha256^2 , which i guess is double hashing , with the (verifThisStr) which i do not understand where that came from at all

Yeah, sha256^2(x) is just defined as sha256(sha256(x)). I'm not sure what you are trying to reference "verifThisStr", but if it's the value that has to be verified with the ECDSA, then you are just talking about the result of the double hash, treated as an integer.

Also if it still follows the basic concept , what would be substituted into the hashed message H(x) when computing s ?

The parts of the transaction that has to be double hashed and then signed depends on the SigHashType (https://bitcoin.org/en/developer-guide#signature-hash-types). For standard SIGHASH_ALL, it includes everything in the raw tx except for the scriptSigs, since you can't sign your own signature.

And does Bob just randomly pick a variable just to generate the signature when it was asked for claiming the unspent transaction ?

Yes, there is a random number chosen when making a signature, so ECDSA signatures are non-deterministic.

  • It should be noted that firstly, the random number k used to generate R should be ephemeral -- never repeated, else risk exposing your master private key. Secondly, it is highly recommended to not generate k with a random-number generator (RNG). Industry best practice is to use a deterministic-random process seeded with the transaction data itself. Then you won't risk reusing k due to an erroneously seeded RNG. See RFC 6979. Jul 22 at 14:13

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.