12

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

17

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

01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d415db55d07a1000000008b4830450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e0141042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabbffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b1806be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce3388fa1abd0fa88b06c44ce81e2234aa70fe578d455dac00000000


// decoded by https://blockchain.info/decode-tx
{
   "lock_time":0,
   "size":300,
   "inputs":[
      {
         "prev_out":{
            "index":0,
            "hash":"a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d"
         },
         "script":"4830450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e0141042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb"
      }
   ],
   "version":1,
   "vin_sz":1,
   "hash":"cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79",
   "vout_sz":2,
   "out":[
      {
         "script_string":"OP_DUP OP_HASH160 df1bd49a6c9e34dfa8631f2c54cf39986027501b OP_EQUALVERIFY OP_CHECKSIG",
         "address":"1MLh2UVHgonJY4ZtsakoXtkcXDJ2EPU6RY",
         "value":577700000000,
         "script":"76a914df1bd49a6c9e34dfa8631f2c54cf39986027501b88ac"
      },
      {
         "script_string":"04cd5e9726e6afeae357b1806be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce3388fa1abd0fa88b06c44ce81e2234aa70fe578d455d OP_CHECKSIG",
         "address":"13TETb2WMr58mexBaNq1jmXV1J7Abk2tE2",
         "value":422300000000,
         "script":"4104cd5e9726e6afeae357b1806be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce3388fa1abd0fa88b06c44ce81e2234aa70fe578d455dac"
      }
   ]
}

Look and decode at the input=0 script:

48  // push next 0x48 bytes
30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e01
41  // push next 0x41 bytes
042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb

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)

8b4830450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d
075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59
290d2fddf25269ee0e0141042e930f39ba62c6534ee98ed20ca98959d34aa9e0
57cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8
526e59667ce9c4e9dcebcabb

2) Replace it with the funding script to 17SkEw2md5avVNyYgj6RiXuQKNwkXaxFyQ

OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG
1976a91446af3fb481837fadbb421727f9959c2d32a3682988ac

(Do not forget about script length again!)

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

01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d41
5db55d07a1000000001976a91446af3fb481837fadbb421727f9959c2d32a368
2988acffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c
54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b180
6be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce33
88fa1abd0fa88b06c44ce81e2234aa70fe578d455dac0000000001000000

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"
                                            "5db55d07a1000000001976a91446af3fb481837fadbb421727f9959c2d32a368"
                                            "2988acffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c"
                                            "54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b180"
                                            "6be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce33"
                                            "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

"692678553d1b85ccf87d4d4443095f276cdf600f2bb7dd44f6effbd7458fd4c2"
"verify=1"
4
  • 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
    Commented 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
    Commented 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
    Commented Nov 5, 2014 at 5:20
  • 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
    Commented Nov 5, 2014 at 10:48
2

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.

1
  • 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.
    – jesseaam
    Commented Jul 22, 2022 at 14:13

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.