Skip to content

Instantly share code, notes, and snippets.

@nlitsme
Last active March 10, 2024 19:41
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save nlitsme/f3c9953a420012bd413a684068a770ff to your computer and use it in GitHub Desktop.
Save nlitsme/f3c9953a420012bd413a684068a770ff to your computer and use it in GitHub Desktop.
How to calculate the bitcoin messagehash

Demonstrate how to calculate the messagehash for the two signatures in this transaction

See ecdsa_demo.py for code showing how to use this to crack the bitcoin secret key.

These are the values extracted from the example transaction below:

pk="04 db d0 c6 15 32 27 9c f7 29 81 c3 58 4f c3 22 16 e0 12 76 99 63 5c 27 89 f5 49 e0 73 0c 05 9b 81 ae 13 30 16 a6 9c 21 e2 3f 18 59 a9 5f 06 d5 2b 7b f1 49 a8 f2 fe 4e 85 35 c8 a8 29 b4 49 c5 ff"
r="d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1"
s1="44 e1 ff 2d fd 81 02 cf 7a 47 c2 1d 5c 9f d5 70 16 10 d0 49 53 c6 83 65 96 b4 fe 9d d2 f5 3e 3e"
s2="9a 5f 1c 75 e4 61 d7 ce b1 cf 3c ab 90 13 eb 2d c8 5b 6d 0d a8 c3 c6 e2 7e 3a 5a 5b 3f aa 5b ab"
m1="c0 e2 d0 a8 9a 34 8d e8 8f da 08 21 1c 70 d1 d7 e5 2c ce f2 eb 94 59 91 1b f9 77 d5 87 78 4c 6e"
m2="17 b0 f4 1c 8c 33 7a c1 e1 8c 98 75 9e 83 a8 cc cb c3 68 dd 9d 89 e5 f0 3c b6 33 c2 65 fd 0d dc"
eccalc crack2 "$pk" "$r" "$s1" "$s2" "$m1" "$m2"


note that the output script for both inputs is the same in this case: 19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac


----- hexdump of https://bitaps.com/9ec4bc49e828d924af1d1029cacf709431abbde46d59554b62bc270e3b29c4b1

 01 00 00 00
 02  -- inputs
 f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01 01 00 00 00
    8a
       47 30 44
          02 20 d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1  -- r
          02 20 44 e1 ff 2d fd 81 02 cf 7a 47 c2 1d 5c 9f d5 70 16 10 d0 49 53 c6 83 65 96 b4 fe 9d d2 f5 3e 3e  -- s1
          01
       41 04 db d0 c6 15 32 27 9c f7 29 81 c3 58 4f c3 22 16 e0 12 76 99 63 5c 27 89 f5 49 e0 73 0c 05 9b 81 ae 13 30 16 a6 9c 21 e2 3f 18 59 a9 5f 06 d5 2b 7b f1 49 a8 f2 fe 4e 85 35 c8 a8 29 b4 49 c5 ff   -- the public key
    ff ff ff ff
 29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a 01 00 00 00
    8a
       47 30 44
          02 20 d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1  -- r
          02 20 9a 5f 1c 75 e4 61 d7 ce b1 cf 3c ab 90 13 eb 2d c8 5b 6d 0d a8 c3 c6 e2 7e 3a 5a 5b 3f aa 5b ab  -- s2
          01
       41 04 db d0 c6 15 32 27 9c f7 29 81 c3 58 4f c3 22 16 e0 12 76 99 63 5c 27 89 f5 49 e0 73 0c 05 9b 81 ae 13 30 16 a6 9c 21 e2 3f 18 59 a9 5f 06 d5 2b 7b f1 49 a8 f2 fe 4e 85 35 c8 a8 29 b4 49 c5 ff   -- the public key
    ff ff ff ff
 01  -- outputs
     a0 86 01 00 00 00 00 00  19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac
 00 00 00 00

now calculate the messagehash like this:
  - replace one inputscript by the corresponding output script
  - replace the other input scripts by '00'
  - append '01 00 00 00' for the hash type at the end of the transaction
  - calculate the 'shasha'

## calculate m1

shasha(
     01 00 00 00
     02  -- inputs
     f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01 01 00 00 00
        19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac  -- replaced the first with output script, see 'txnsrc 1' below
        ff ff ff ff
     29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a 01 00 00 00
        00  -- replaced the second with empty script
        ff ff ff ff
     01  -- outputs
         a0 86 01 00 00 00 00 00  19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac
     00 00 00 00
    -- and the hashtype
     01 00 00 00
) = c0 e2 d0 a8 9a 34 8d e8 8f da 08 21 1c 70 d1 d7 e5 2c ce f2 eb 94 59 91 1b f9 77 d5 87 78 4c 6e

## calculate m2
shasha(
     01 00 00 00
     02  -- inputs
     f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01 01 00 00 00
        00  -- replaced the first with empty script
        ff ff ff ff
     29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a 01 00 00 00
        19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac -- replaced the second with output script, see 'txnsrc 2' below
        ff ff ff ff
     01  -- outputs
         a0 86 01 00 00 00 00 00  19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac
     00 00 00 00
    -- and the hashtype
     01 00 00 00
) = 17 b0 f4 1c 8c 33 7a c1 e1 8c 98 75 9e 83 a8 cc cb c3 68 dd 9d 89 e5 f0 3c b6 33 c2 65 fd 0d dc


-------

## txnsrc 1
shasha(
     01 00 00 00
     01
     c4 c8 6a e5 40 d3 40 47 1b 03 83 3c b6 73 86 b0 60 a7 a5 63 2f 1e e7 30 c7 1e f6 90 9e 90 eb 9c 00 00 00 00
        8b 48 30 45 02 21 00 87 87 14 0a 00 fd b0 5e 55 ef 66 0f 54 c3 f5 1d 84 99 35 d1 4b c2 e2 c6 0f b9 7a 05 1a 1d a3 c7 02 20 79 7b 5e b2 65 24 6e 63 cb 06 1a b2 77 c5 41 a3 ba 42 37 d5 b3 c5 fe 94 b6 af 94 00 72 3a 87 90 01 41 04 04 c6 d6 28 a1 2e 1c bf 01 b1 d8 31 6c b1 c0 9a 38 16 33 69 f1 11 3a 26 51 35 65 a1 a2 44 5e 2e 12 fd ac 74 8c ec 24 34 42 c6 18 5e 5e 2c 26 47 f9 93 c8 8a ff 95 d9 22 f6 51 17 d7 3d a5 66 cc
        ff ff ff ff
     02 -- outputs
         d0 dc f7 05 00 00 00 00  19 76 a9 14 fc 41 ce e3 55 d1 0b 86 31 37 00 63 82 c8 09 ae c1 dd f3 3c 88 ac  --- output #0
         d0 fb 01 00 00 00 00 00  19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac  --- output #1
     00 00 00 00
) = f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01

## txnsrc 2
shasha(
     01 00 00 00
     01
     c4 c8 6a e5 40 d3 40 47 1b 03 83 3c b6 73 86 b0 60 a7 a5 63 2f 1e e7 30 c7 1e f6 90 9e 90 eb 9c 01 00 00 00
        8a 47 30 44 02 20 d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1 02 20 12 a8 c1 d5 c6 02 e3 82 c1 78 fb fc b9 57 e8 ec c3 47 f1 ba f7 8a 20 6f 20 a9 7f f4 c4 33 e1 46 01 41 04 db d0 c6 15 32 27 9c f7 29 81 c3 58 4f c3 22 16 e0 12 76 99 63 5c 27 89 f5 49 e0 73 0c 05 9b 81 ae 13 30 16 a6 9c 21 e2 3f 18 59 a9 5f 06 d5 2b 7b f1 49 a8 f2 fe 4e 85 35 c8 a8 29 b4 49 c5 ff
        ff ff ff ff
     02 -- outputs
         50 c3 00 00 00 00 00 00  19 76 a9 14 01 94 53 ca 35 e7 cd c4 31 18 dd a7 bc 81 ee 98 1b d6 f9 24 88 ac  --- output #0
         20 4e 00 00 00 00 00 00  19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac  --- output #1
     00 00 00 00
) = 29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a

A old (before witness) style transaction has the following structure:

  1. first a 4 byte version: 01 00 00 00
  2. a varint encoding the number of inputs: 02
  3. the inputs
  4. a varint encoding the number of outputs: 01
  5. the outputs
  6. a 4 byte locktime: 00 00 00 00

An input is structured like this:

  1. a 32 byte transaction hash
  2. a 4 byte zero-based output index
  3. a varint encoding the input script size
  4. the input script
  5. a 4 byte sequence number: ff ff ff ff

Note that the transaction hash as used on most blockexplorers is byte-reversed from the hash as it is stored in the input, or calculated using the shasha algorithm.

The input script commonly contains:

  1. a signature: a asn-1 BER encoded 'r' and 's' value followed by a 01.
  2. a public key.

An output is structured like this:

  1. a 8 byte bitcoin value
  2. a varint encoding the output script size
  3. the output script

The output script commonly contains:

  1. 76 - dup
  2. a9 - hash160
  3. 14 ... - the address hash
  4. 88 - equalverify
  5. ac - checksig

The asn1-BER encoded signature:

  1. 30 - a sequence tag
  2. a length, typically in range: 0x40 - 0x48
  3. 02 - a 'int' tag, the type of the 'r' value
  4. a length, typically in range: 0x1e - 0x21
  5. the bytes for the 'r' value
  6. 02 - a 'int' tag, the type of the 's' value
  7. a length, typically in range: 0x1e - 0x21
  8. the bytes for the 's' value

See wikipedia for details on the BER encoding.

@nlitsme
Copy link
Author

nlitsme commented Nov 21, 2022

That is how pay-to-script transactions work, and because of the witness part, this is a P2SH+P2WSH transaction.

The address:
35ipDTBWHU7C7rE6mTfysoZYCHkyqugaXf = base58(5, 2c378fb269e524d6778a74b287fa457da26d1838)

is the has of the SigScript:
2c378fb269e524d6778a74b287fa457da26d1838 = sharip(0020 d8793be235d12d1cde8b0144647ae0695580b3892a27d7294b56aaf5de6ba602)

The has in the SigScript, is the has of the P2SH script.
d8793be235d12d1cde8b0144647ae0695580b3892a27d7294b56aaf5de6ba602 = sha256(
52
210260e173e8b3f1039eb860210576b85609c5695ce90e9f8711a147466c24e3eb45
21026673d16ae7a751952064e42715d52831a0ecca70e8e794a121c55eec134c4abc
2102ece72a894cdafb8c2aa469ce357f5a8049d9699e3e114fbe538f372f80aab7f8
53
ae -- CHECKMULTISIG
)

This last part has 3 pubkeys, you need 2-out-of-3 signatures in the witness part.

The numbers starting with 304.... are the signatures in the witness part.
The last item in the witness list is the (multisig) P2SH script.

@JoeBrar
Copy link

JoeBrar commented Nov 22, 2022

Thanks you for the insight.
So as I understand, this wallet will have the same SigScript in all its transactions.
So the signatures in the witness part (starting with 304....) will have to be same for this wallet to be cracked. Or is there some way it can still be cracked with the same SigScript.

Also, how can we find r,s and z values from the witness.

@JoeBrar
Copy link

JoeBrar commented Nov 22, 2022

...?

@nlitsme
Copy link
Author

nlitsme commented Nov 22, 2022

How to hash a witness transaction is specified here: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification

@JoeBrar
Copy link

JoeBrar commented Nov 23, 2022

Thanks.
So the signatures in the witness part (starting with 304....) will have to be same for this wallet to be cracked. Or is there some way it can still be cracked with the same SigScript?

@nlitsme
Copy link
Author

nlitsme commented Nov 23, 2022

The easy crack, where you have two different signatures with the same r-value for the same pubkey then yes.

But there are other ways to crack keys. You could for instance try to bruteforce them, some keys have week passwords.

for instance this one: https://blockchair.com/bitcoin/address/1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm
it has private key: 00...01

In this transaction you can see that the pubkey is the ecdsa generator point:
https://bitaps.com/57bd645d11fc3404ec7d24277e9fa5dbce3c68d17bff0e15a9e1914eb910d829/1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm

@Ruby3434
Copy link

Ruby3434 commented Nov 23, 2022

@nlitsme Hello, I didn't understand why it's not working for https://www.blockchain.com/explorer/transactions/btc/e0377229deb9dcd2e0aabd3c56deb397eb24b762c5c0eca8cfaf2c268e48c4f6.

I can't find correct private key for 1K3iZPSqMCxtMd5o5hw4gfpFq3i9zqL61o.

I used 4,5 inputs to find s1, s2, z1, z2. Here the values:

30440220 1cf895af787f8d897cbb72bf9d39d3edbd603c4b23ea8f2f3dfaafc9e3fa5907 0220 62f8260583709b26b102af5ab4c615073921a0af1d21b9a0e96969307ff3a44e

30440220 1cf895af787f8d897cbb72bf9d39d3edbd603c4b23ea8f2f3dfaafc9e3fa5907 0220 17d4a1b146b7dcebbb604574f90f4569e18f7ab7f828cdd9ee5a2cce59cb09a4

0100000005e75a72a15d95a874e05531f005c5dff4047c6b6f25990baf54045209e10f97130200000000ffffffff8ea572f15ad54edec3a9d3a0f57eeafa179810254f060a54bfeedf3d4269f13a0000000000ffffffff5531bbd9c004c69fff9374918f9eb64a3603c045d38362002e25a06316e7d73f0000000000ffffffff6f116755042b1b1aef9d809ab04f79afa63f71aa31616c2daa1a7d82d305b13a000000001976a9142926402d832870745c37979bdff8f030e6a2d75988acffffffffef1a5d83a8cd639224c9876fe1e157a3ed239d596d2bb62c556c9dcc1bb550370000000000ffffffff01ccba0f00000000001976a9142926402d832870745c37979bdff8f030e6a2d75988ac0000000001000000

0100000005e75a72a15d95a874e05531f005c5dff4047c6b6f25990baf54045209e10f97130200000000ffffffff8ea572f15ad54edec3a9d3a0f57eeafa179810254f060a54bfeedf3d4269f13a0000000000ffffffff5531bbd9c004c69fff9374918f9eb64a3603c045d38362002e25a06316e7d73f0000000000ffffffff6f116755042b1b1aef9d809ab04f79afa63f71aa31616c2daa1a7d82d305b13a0000000000ffffffffef1a5d83a8cd639224c9876fe1e157a3ed239d596d2bb62c556c9dcc1bb55037000000001976a9142926402d832870745c37979bdff8f030e6a2d75988acffffffff01ccba0f00000000001976a9142926402d832870745c37979bdff8f030e6a2d75988ac0000000001000000

p  = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
r  = 0x1cf895af787f8d897cbb72bf9d39d3edbd603c4b23ea8f2f3dfaafc9e3fa5907
s1 = 0x62f8260583709b26b102af5ab4c615073921a0af1d21b9a0e96969307ff3a44e
s2 = 0x17d4a1b146b7dcebbb604574f90f4569e18f7ab7f828cdd9ee5a2cce59cb09a4
z1 = 0x40ea4996d6395deb065a93d66424901513bddfb2ddf405493a41bf7a0bbb7384
z2 = 0xe6b7ebcd68dcf20b83d238e04d6601dd9a070b5b65b941529e2074c10888efe8

K = GF(p)
K((z1*s2 - z2*s1)/(r*(s1-s2)))

But in summary I getting this value of PK:

dec: 40047461853181506903710401524154105044947235713778347330990385830425961756207
hex: 588a0f66409dc2d17a2f1c3ec2d1d1bf515da3edbfccb945d6c5078944f4f62f
wif: 5JVHCVnzJQdarD46gtoQzaj6x1cAkkamNXgYjmtt4uNAyDcdUMu

But this PK wrong. Maybe I should use different value for p(eliptic curve) or try other inputs?

@Ruby3434
Copy link

Ruby3434 commented Nov 24, 2022

@nlitsme Can you help please?

@nlitsme
Copy link
Author

nlitsme commented Nov 24, 2022

your message hashes are wrong:
z1 = 0xc3d27af32c188f3698c62e6c67c6ea866a7bf0ec49cfc6a78b7bc6b2e84c15f5
z2 = 0x91a1a1bfb6409d876258bc25f610309354d37e15bb84b3e1e6b34d419bfad663

@Ruby3434
Copy link

@nlitsme How did you calculated them?

@nlitsme
Copy link
Author

nlitsme commented Nov 27, 2022

like this:

shasha(
 01000000
 05  -- inputs
   e75a72a15d95a874e05531f005c5dff4047c6b6f25990baf54045209e10f9713 02000000  00  ffffffff
   8ea572f15ad54edec3a9d3a0f57eeafa179810254f060a54bfeedf3d4269f13a 00000000  00  ffffffff
   5531bbd9c004c69fff9374918f9eb64a3603c045d38362002e25a06316e7d73f 00000000  00  ffffffff
   6f116755042b1b1aef9d809ab04f79afa63f71aa31616c2daa1a7d82d305b13a 00000000  19 76a914c5f5c988280fb5794f56421f8368ef8456c3872b88ac   ffffffff
   ef1a5d83a8cd639224c9876fe1e157a3ed239d596d2bb62c556c9dcc1bb55037 00000000  00  ffffffff
 01  -- outputs
   ccba0f0000000000  1976a9142926402d832870745c37979bdff8f030e6a2d75988ac
 00000000 -- locktime
 01000000
) = c3d27af32c188f3698c62e6c67c6ea866a7bf0ec49cfc6a78b7bc6b2e84c15f5


shasha(
 01000000
 05  -- inputs
   e75a72a15d95a874e05531f005c5dff4047c6b6f25990baf54045209e10f9713 02000000  00  ffffffff
   8ea572f15ad54edec3a9d3a0f57eeafa179810254f060a54bfeedf3d4269f13a 00000000  00  ffffffff
   5531bbd9c004c69fff9374918f9eb64a3603c045d38362002e25a06316e7d73f 00000000  00  ffffffff
   6f116755042b1b1aef9d809ab04f79afa63f71aa31616c2daa1a7d82d305b13a 00000000  00  ffffffff
   ef1a5d83a8cd639224c9876fe1e157a3ed239d596d2bb62c556c9dcc1bb55037 00000000  19 76a914c5f5c988280fb5794f56421f8368ef8456c3872b88ac ffffffff
 01  -- outputs
   ccba0f0000000000  1976a9142926402d832870745c37979bdff8f030e6a2d75988ac
 00000000 -- locktime
 01000000
) = 91a1a1bfb6409d876258bc25f610309354d37e15bb84b3e1e6b34d419bfad663

you used the output of this transaction to replace in the input, instead, you should use the output of the referenced transaction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment