67% found this document useful (3 votes)
2K views3 pages

Recovering Bitcoin Private Keys Using Repeating R Values

The document describes how the author was able to recover private keys from Bitcoin transactions by exploiting a weakness in signatures that reused the same random value. They found a transaction with identical signature components r1 and r2, allowing calculation of the private key. This revealed the signatures were generated by a hardware wallet reusing the same non-random value. The author was then able to spend coins from the vulnerable Bitcoin address after contacting its owner.

Uploaded by

Cheick Bah
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
67% found this document useful (3 votes)
2K views3 pages

Recovering Bitcoin Private Keys Using Repeating R Values

The document describes how the author was able to recover private keys from Bitcoin transactions by exploiting a weakness in signatures that reused the same random value. They found a transaction with identical signature components r1 and r2, allowing calculation of the private key. This revealed the signatures were generated by a hardware wallet reusing the same non-random value. The author was then able to spend coins from the vulnerable Bitcoin address after contacting its owner.

Uploaded by

Cheick Bah
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 3

Nils Schneider

Posts Projects Photos

Recovering Bitcoin private keys using weak signatures from the blockchain

On December 25th of last year I discovered a potential weakness in some Bitcoin


implementations. Have a look at this transaction:

transaction: 9ec4bc49e828d924af1d1029cacf709431abbde46d59554b62bc270e3b29c4b1

input script 1:

30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1022044
e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e0104dbd0c6153227
9cf72981c3584fc32216e0127699635c2789f549e0730c059b81ae133016a69c21e23f1859a95f
06d52b7bf149a8f2fe4e8535c8a829b449c5ff

input script 2:

30440220d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad102209a
5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab0104dbd0c6153227
9cf72981c3584fc32216e0127699635c2789f549e0730c059b81ae133016a69c21e23f1859a95f
06d52b7bf149a8f2fe4e8535c8a829b449c5ff

This transactions has two inputs and one output. If you look closely at the two input scripts you
will notice there are quite a few equal bytes at the start and at the end. Those bytes at the end is
the hex-encoded public key of the address spending the coins so there’s nothing wrong with that.
However, the first half of the script is the actual signature (r, s):

r1: d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1

r2: d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1

s1: 44e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e

s2: 9a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab

As you can see, r1 equals r2. This is a huge problem. We’ll be able to recover the private key to
this public key:

private key = (z1*s2 - z2*s1)/(r*(s1-s2))

We just need to find z1 and z2! These are the hashes of the outputs to be signed. Let’s fetch the
output transations and calculate them (it is calculated by OP_CHECKSIG):
z1: c0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e

z2: 17b0f41c8c337ac1e18c98759e83a8cccbc368dd9d89e5f03cb633c265fd0ddc

That’s it. Let’s setup our sage notebook like this:

p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

r = 0xd47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1

s1 = 0x44e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e

s2 = 0x9a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab

z1 = 0xc0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e

z2 = 0x17b0f41c8c337ac1e18c98759e83a8cccbc368dd9d89e5f03cb633c265fd0ddc

p is just the order of G, a parameter of the secp256k1 curve used by Bitcoin. Let’s create a field
for our calculations:

K = GF(p)

And calculate the private key within this field:

K((z1*s2 - z2*s1)/(r*(s1-s2)))

88865298299719117682218467295833367085649033095698151055007620974294165995
414

Convert it to a more suitable format:

hex: c477f9f65c22cce20657faa5b2d1d8122336f851a508a1ed04e479c34985bf96

WIF: 5KJp7KEffR7HHFWSFYjiCUAntRSTY69LAQEX1AUzaSBHHFdKEpQ

And import it to your favourite Bitcoin wallet. It’ll calculate the correct bitcoin address and you’ll
be able to spend coins send to this address.

There are a few vulnerable bitcoin addresses in the blockchain. After some research I was able to
contact the owner of this address. He allowed me to spend the funds.

Why did this work? ECDSA requires a random number for each signature. If this random number
is ever used twice with the same private key it can be recovered. This transaction was generated
by a hardware bitcoin wallet using a pseudo-random number generator that was returning the
same “random” number every time.

Published January 28, 2013


Home

Projects

Photos

Impressum

RSS

Email

You might also like