├── requirements.txt ├── .gitignore ├── bitlib ├── __init__.py ├── bitmail.py ├── bitlog.py ├── bitgen.py ├── bitconf.py └── bitnet.py ├── config.sample.ini ├── readme.md └── main.py /requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.20.0 2 | ecdsa==0.13.3 3 | base58==1.0.2 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .vscode 3 | config.ini 4 | log.txt* 5 | test.py 6 | .idea 7 | -------------------------------------------------------------------------------- /bitlib/__init__.py: -------------------------------------------------------------------------------- 1 | from .bitmail import BitMail 2 | from .bitnet import BitNet 3 | from .bitgen import BitGen 4 | from .bitconf import BitConf 5 | from .bitlog import BitLog 6 | -------------------------------------------------------------------------------- /config.sample.ini: -------------------------------------------------------------------------------- 1 | [MAIN] 2 | THREAD_COUNT = 15 3 | # Set 1 to log into file or 0 to disable it. 4 | LOG = 1 5 | 6 | [NETWORK] 7 | HTTP_PROXY_URL = 8 | HTTP_PROXY_PORT = 9 | # Use one of this as api site : 10 | # blockchain.info, blockcypher.com, blockexplorer.com, btc.com, bitaps.com 11 | API_SITE = 12 | 13 | [SMTP] 14 | # Sending email when something happens. 15 | HOST = 16 | PORT = 17 | USERNAME = 18 | PASSWORD = 19 | MAIL_FROM = 20 | MAIL_TO = 21 | -------------------------------------------------------------------------------- /bitlib/bitmail.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | 3 | 4 | class BitMail: 5 | 6 | def __init__(self, smtp_host, smtp_port, smtp_username, smtp_password, mail_from, mail_to): 7 | self.smtp_host = smtp_host 8 | self.smtp_port = smtp_port 9 | self.smtp_username = smtp_username 10 | self.smtp_password = smtp_password 11 | self.mail_from = mail_from 12 | self.mail_to = mail_to 13 | 14 | def send_email(self, subject, message): 15 | if not self.smtp_host: 16 | return 17 | 18 | message = "Subject: [randbit]{}\n\n{}".format(subject, message) 19 | server = smtplib.SMTP_SSL(self.smtp_host, self.smtp_port) 20 | server.login(self.smtp_username, self.smtp_password) 21 | server.sendmail(self.mail_from, self.mail_to, message) 22 | server.quit() 23 | -------------------------------------------------------------------------------- /bitlib/bitlog.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from logging.handlers import RotatingFileHandler 3 | 4 | 5 | class BitLog: 6 | def __init__(self): 7 | self.log_formatter = logging.Formatter( 8 | '%(asctime)s %(levelname)s %(funcName)s(%(lineno)d) %(message)s') 9 | 10 | self.logFile = 'log.txt' 11 | 12 | self.my_handler = RotatingFileHandler(self.logFile, mode='a', maxBytes=1*1024*1024, 13 | backupCount=2, encoding=None, delay=0) 14 | self.my_handler.setFormatter(self.log_formatter) 15 | self.my_handler.setLevel(logging.INFO) 16 | 17 | self.app_log = logging.getLogger('root') 18 | self.app_log.setLevel(logging.INFO) 19 | 20 | self.app_log.addHandler(self.my_handler) 21 | 22 | def log(self, message): 23 | self.app_log.info(message) 24 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Randbit 2 | Generate random bitcoin private key and check it's balance automatically. 3 | 4 | ## How to use 5 | 6 | 1. Install python 3 and then, 7 | ```python 8 | pip install -r requirements.txt 9 | ``` 10 | 11 | 2. Copy `config.sample.ini` and rename it to `config.ini`. 12 | 13 | 3. Run it 14 | ```python 15 | python main.py 16 | ``` 17 | 18 | ## Features 19 | 20 | * Multithread 21 | * Support multiple website for checking balance 22 | * Log to file and logrotate 23 | * Send email when find address with some balance 24 | 25 | 26 | ## Donation 27 | 28 | Bitcoin: 29 | 3Ch9TcvSk4cWt4EWwEJLPMttq1C8sc3HmD 30 | 31 | Ethereum: 32 | 0xC591B313875DBF4Af06EeE429a3980Af4ea75d6f 33 | 34 | Doge: 35 | DNuRLhYMPoEq74zMMVs5bffViuhgd9KQLB 36 | 37 | Litecoin: 38 | LWnnmAp6yVorqCnhfn5k7STAqb9jtrCK4s 39 | 40 | Stellar: 41 | GAVHQZEE4YHOBXL55VPMCSM2Z4Q5NQASIEESFHHD3SBZ4EW34F7SINJT 42 | 43 | Ripple: 44 | rMLizu9xfRDh61YtbY7DDjJEYSmTLer7wr 45 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import bitlib 4 | 5 | 6 | def run(name): 7 | print("{} started!".format(name)) 8 | 9 | while True: 10 | private_key = bitlib.BitGen.generate_private_key() 11 | wif = bitlib.BitGen.private2wif(private_key) 12 | address = bitlib.BitGen.private2address(private_key) 13 | balance = bitnet.get_balance(address) 14 | 15 | message = "private:{},wif:{},address:{},balance:{}".format( 16 | private_key, wif, address, balance) 17 | 18 | if bitconf.log: 19 | log_message = "{},{}".format(name, message) 20 | print(log_message) 21 | bitlog.log(log_message) 22 | 23 | if balance.isdigit() == False: 24 | print(balance) 25 | continue 26 | 27 | if balance != "0": 28 | f = open("success.txt", "a") 29 | f.write(message + "\n") 30 | f.close() 31 | print(message) 32 | bitmail.send_email("Found", message) 33 | 34 | 35 | if __name__ == '__main__': 36 | bitconf = bitlib.BitConf() 37 | bitconf.load() 38 | bitmail = bitlib.BitMail(bitconf.smtp_host, bitconf.smtp_port, bitconf.smtp_username, bitconf.smtp_password, 39 | bitconf.smtp_mail_from, bitconf.smtp_mail_to) 40 | bitnet = bitlib.BitNet(bitconf.api_url, bitconf.http_proxy_url, bitconf.http_proxy_port) 41 | 42 | bitlog = bitlib.BitLog() 43 | 44 | bitmail.send_email("Started", "I am running") 45 | for x in range(bitconf.thread_count): 46 | thread_name = "Thread-{}".format(x + 1) 47 | mythread = threading.Thread(target=run, args=(thread_name,)) 48 | mythread.start() 49 | -------------------------------------------------------------------------------- /bitlib/bitgen.py: -------------------------------------------------------------------------------- 1 | import base58 2 | import hashlib 3 | import binascii 4 | import os 5 | import ecdsa 6 | 7 | 8 | class BitGen: 9 | 10 | @staticmethod 11 | def generate_private_key(): 12 | return binascii.hexlify(os.urandom(32)).decode() 13 | 14 | @staticmethod 15 | def private2wif(private_key): 16 | # Step 1: here we have the private key 17 | private_key_static = private_key 18 | # Step 2: let's add 80 in front of it 19 | extended_key = "80"+private_key_static 20 | # Step 3: first SHA-256 21 | first_sha256 = hashlib.sha256( 22 | binascii.unhexlify(extended_key)).hexdigest() 23 | # Step 4: second SHA-256 24 | second_sha256 = hashlib.sha256( 25 | binascii.unhexlify(first_sha256)).hexdigest() 26 | # Step 5-6: add checksum to end of extended key 27 | final_key = extended_key+second_sha256[:8] 28 | # Step 7: finally the Wallet Import Format is the base 58 encode of final_key 29 | WIF = base58.b58encode(binascii.unhexlify(final_key)).decode() 30 | 31 | return WIF 32 | 33 | @staticmethod 34 | def __ripemd160(x): 35 | d = hashlib.new('ripemd160') 36 | d.update(x) 37 | return d 38 | 39 | @staticmethod 40 | def private2address(private_key): 41 | private_key = binascii.unhexlify(private_key) 42 | sk = ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1) 43 | vk = sk.get_verifying_key() 44 | publ_key = '04' + binascii.hexlify(vk.to_string()).decode() 45 | hash160 = BitGen.__ripemd160(hashlib.sha256( 46 | binascii.unhexlify(publ_key)).digest()).digest() 47 | publ_addr_a = b"\x00" + hash160 48 | checksum = hashlib.sha256(hashlib.sha256( 49 | publ_addr_a).digest()).digest()[:4] 50 | publ_addr_b = base58.b58encode(publ_addr_a + checksum) 51 | 52 | return publ_addr_b.decode() 53 | -------------------------------------------------------------------------------- /bitlib/bitconf.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | 3 | 4 | class BitConf: 5 | CONFIG_SECTION_NETWORK = "NETWORK" 6 | CONFIG_SECTION_NETWORK_HTTP_PROXY_URL = "HTTP_PROXY_URL" 7 | CONFIG_SECTION_NETWORK_HTTP_PROXY_PORT = "HTTP_PROXY_PORT" 8 | CONFIG_SECTION_NETWORK_API_URL = "API_SITE" 9 | 10 | CONFIG_SECTION_SMTP = "SMTP" 11 | CONFIG_SECTION_SMTP_HOST = "HOST" 12 | CONFIG_SECTION_SMTP_PORT = "PORT" 13 | CONFIG_SECTION_SMTP_USERNAME = "USERNAME" 14 | CONFIG_SECTION_SMTP_PASSWORD = "PASSWORD" 15 | CONFIG_SECTION_SMTP_MAIL_FROM = "MAIL_FROM" 16 | CONFIG_SECTION_SMTP_MAIL_TO = "MAIL_TO" 17 | 18 | CONFIG_SECTION_MAIN = "MAIN" 19 | CONFIG_SECTION_MAIN_THREAD_COUNT = "THREAD_COUNT" 20 | CONFIG_SECTION_MAIN_LOG = "LOG" 21 | 22 | def __init__(self): 23 | self.config = configparser.ConfigParser() 24 | self.config[self.CONFIG_SECTION_MAIN] = { 25 | self.CONFIG_SECTION_MAIN_THREAD_COUNT: 20, 26 | self.CONFIG_SECTION_MAIN_LOG: 1 27 | } 28 | self.config[self.CONFIG_SECTION_NETWORK] = { 29 | self.CONFIG_SECTION_NETWORK_HTTP_PROXY_URL: "", 30 | self.CONFIG_SECTION_NETWORK_HTTP_PROXY_PORT: 0, 31 | self.CONFIG_SECTION_NETWORK_API_URL: "" 32 | } 33 | self.config[self.CONFIG_SECTION_SMTP] = { 34 | self.CONFIG_SECTION_SMTP_HOST: "", 35 | self.CONFIG_SECTION_SMTP_PORT: 0, 36 | self.CONFIG_SECTION_SMTP_USERNAME: "", 37 | self.CONFIG_SECTION_SMTP_PASSWORD: "", 38 | self.CONFIG_SECTION_SMTP_MAIL_FROM: "", 39 | self.CONFIG_SECTION_SMTP_MAIL_TO: "", 40 | } 41 | 42 | def load(self): 43 | self.config.read('config.ini') 44 | self.http_proxy_url = self.config[self.CONFIG_SECTION_NETWORK][self.CONFIG_SECTION_NETWORK_HTTP_PROXY_URL] 45 | self.http_proxy_port = self.config[self.CONFIG_SECTION_NETWORK][self.CONFIG_SECTION_NETWORK_HTTP_PROXY_PORT] 46 | self.api_url = self.config[self.CONFIG_SECTION_NETWORK][self.CONFIG_SECTION_NETWORK_API_URL] 47 | self.smtp_host = self.config[self.CONFIG_SECTION_SMTP][self.CONFIG_SECTION_SMTP_HOST] 48 | self.smtp_port = self.config[self.CONFIG_SECTION_SMTP][self.CONFIG_SECTION_SMTP_PORT] 49 | self.smtp_username = self.config[self.CONFIG_SECTION_SMTP][self.CONFIG_SECTION_SMTP_USERNAME] 50 | self.smtp_password = self.config[self.CONFIG_SECTION_SMTP][self.CONFIG_SECTION_SMTP_PASSWORD] 51 | self.smtp_mail_from = self.config[self.CONFIG_SECTION_SMTP][self.CONFIG_SECTION_SMTP_MAIL_FROM] 52 | self.smtp_mail_to = self.config[self.CONFIG_SECTION_SMTP][self.CONFIG_SECTION_SMTP_MAIL_TO] 53 | self.thread_count = int(self.config[self.CONFIG_SECTION_MAIN][self.CONFIG_SECTION_MAIN_THREAD_COUNT]) 54 | self.log = int(self.config[self.CONFIG_SECTION_MAIN][self.CONFIG_SECTION_MAIN_LOG]) 55 | -------------------------------------------------------------------------------- /bitlib/bitnet.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | 4 | 5 | class BitNet: 6 | proxy = dict() 7 | error_count = 0 8 | MAX_ERROR_COUNT = 15 9 | 10 | def __init__(self, api_url, http_proxu_url, http_proxy_port): 11 | self.api_url = api_url 12 | self.session = requests.Session() 13 | if http_proxu_url: 14 | self.proxy = dict(http=http_proxu_url + ":" + http_proxy_port, 15 | https=http_proxu_url + ":" + http_proxy_port) 16 | 17 | def get_balance(self, address): 18 | try: 19 | if self.error_count > 0: 20 | self.error_count -= 1 21 | 22 | if self.api_url == "blockchain.info": 23 | result = self.get_balance_blockchain_info(address) 24 | elif self.api_url == "blockcypher.com": 25 | result = self.get_balance_blockcypher_com(address) 26 | elif self.api_url == "blockexplorer.com": 27 | result = self.get_balance_blockexplorer_com(address) 28 | elif self.api_url == "btc.com": 29 | result = self.get_balance_btc_com(address) 30 | else: 31 | result = self.get_balance_bitaps_com(address) 32 | 33 | if result.isdigit() == False: 34 | raise Exception("NOT A NUMBER") 35 | 36 | return result 37 | except Exception as e: 38 | print(str(e)) 39 | self.error_count += 2 40 | 41 | time.sleep(1) 42 | 43 | if self.error_count > self.MAX_ERROR_COUNT: 44 | self.error_count = 0 45 | time.sleep(10) 46 | return "0" 47 | 48 | return self.get_balance(address) 49 | 50 | def get_balance_blockchain_info(self, address): 51 | r = self.session.get( 52 | "https://blockchain.info/q/addressbalance/" + address, proxies=self.proxy) 53 | 54 | return r.text 55 | 56 | def get_balance_bitaps_com(self, address): 57 | r = self.session.get("https://api.bitaps.com/btc/v1/blockchain/address/state/" + 58 | address, proxies=self.proxy) 59 | 60 | r = r.json() 61 | if r['data'] == None: 62 | return "0" 63 | 64 | return str(r['data']['balance']) 65 | 66 | def get_balance_blockexplorer_com(self, address): 67 | r = self.session.get( 68 | "https://blockexplorer.com/api/addr/{}/balance".format(address), proxies=self.proxy) 69 | 70 | return r.text 71 | 72 | def get_balance_btc_com(self, address): 73 | r = self.session.get( 74 | "https://chain.api.btc.com/v3/address/" + address, proxies=self.proxy) 75 | 76 | r = r.json() 77 | if r['data'] == None: 78 | return "0" 79 | 80 | return str(r['data']['balance']) 81 | 82 | def get_balance_blockcypher_com(self, address): 83 | r = self.session.get( 84 | "https://api.blockcypher.com/v1/btc/main/addrs/" + address + "/balance", proxies=self.proxy) 85 | 86 | return str(r.json()['balance']) 87 | --------------------------------------------------------------------------------