diff --git a/.gitignore b/.gitignore index 01a8809..c5189fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# =================================== +# Python Scanner & Database +# =================================== + # Virtual Environment .venv/ venv/ @@ -11,19 +15,52 @@ __pycache__/ *.pyo *.pyd *$py.class -*.so .Python *.egg-info/ dist/ build/ -# IDE +# =================================== +# C++ Bruteforce +# =================================== + +# Eseguibili compilati +bruteforce/p2pk_bruteforce +bruteforce/p2pk_bruteforce_debug + +# File oggetto e compilazione +*.o +*.a +*.so +*.gcda +*.gcno +*.gch + +# File generati dal bruteforce +bruteforce/found_keys.txt +bruteforce/progress.csv +bruteforce/target_keys.txt + +# =================================== +# IDE & Editor +# =================================== + .vscode/ .idea/ *.swp *.swo *~ +# =================================== # OS +# =================================== + .DS_Store Thumbs.db + +# =================================== +# Logs & Temp +# =================================== + +*.log +*.tmp \ No newline at end of file diff --git a/bruteforce/Makefile b/bruteforce/Makefile new file mode 100644 index 0000000..563fade --- /dev/null +++ b/bruteforce/Makefile @@ -0,0 +1,91 @@ +# Makefile per Bitcoin P2PK Bruteforce + +CC = g++ +CFLAGS = -O3 -march=native -mtune=native -flto -pthread -Wall -Wextra +LIBS = -lsecp256k1 -lgmp + +TARGET = p2pk_bruteforce +SOURCE = p2pk_bruteforce.cpp + +# Percorsi di default per libsecp256k1 +# Modifica se necessario in base alla tua installazione +INCLUDE_PATH = -I/usr/local/include -I/usr/include +LIB_PATH = -L/usr/local/lib -L/usr/lib + +all: $(TARGET) + +$(TARGET): $(SOURCE) + @echo "[+] Compilazione $(TARGET) con ottimizzazioni massime..." + $(CC) $(CFLAGS) $(INCLUDE_PATH) $(LIB_PATH) -o $(TARGET) $(SOURCE) $(LIBS) + @echo "[+] Compilazione completata!" + @echo "[!] Eseguibile: ./$(TARGET)" + +optimized: $(SOURCE) + @echo "[+] Compilazione con ottimizzazioni estreme (PGO)..." + $(CC) $(CFLAGS) -fprofile-generate $(INCLUDE_PATH) $(LIB_PATH) -o $(TARGET) $(SOURCE) $(LIBS) + @echo "[+] Esegui il programma per generare profilo..." + @echo "[!] Poi esegui 'make pgo-use' per ricompilare" + +pgo-use: $(SOURCE) + @echo "[+] Ricompilazione con Profile-Guided Optimization..." + $(CC) $(CFLAGS) -fprofile-use $(INCLUDE_PATH) $(LIB_PATH) -o $(TARGET) $(SOURCE) $(LIBS) + @echo "[+] Compilazione PGO completata!" + +static: $(SOURCE) + @echo "[+] Compilazione statica..." + $(CC) $(CFLAGS) -static $(INCLUDE_PATH) $(LIB_PATH) -o $(TARGET) $(SOURCE) -l:libsecp256k1.a -l:libgmp.a + @echo "[+] Compilazione statica completata!" + +debug: $(SOURCE) + @echo "[+] Compilazione in modalità debug..." + $(CC) -g -pthread -Wall -Wextra $(INCLUDE_PATH) $(LIB_PATH) -o $(TARGET)_debug $(SOURCE) $(LIBS) + @echo "[+] Compilazione debug completata!" + +test: $(TARGET) + @echo "[+] Test rapido del programma..." + ./$(TARGET) --help || echo "Test completato" + +clean: + @echo "[+] Pulizia file compilati..." + rm -f $(TARGET) $(TARGET)_debug + rm -f *.o *.gcda *.gcno + @echo "[+] Pulizia completata!" + +install-deps: + @echo "[+] Installazione dipendenze..." + @echo "[!] Questo installerà: build-essential, libsecp256k1-dev, libgmp-dev" + @echo "[!] Premi CTRL+C per annullare, ENTER per continuare..." + @read dummy + sudo apt-get update + sudo apt-get install -y build-essential libsecp256k1-dev libgmp-dev git autoconf libtool pkg-config + @echo "[+] Dipendenze installate!" + +install-secp256k1: + @echo "[+] Compilazione e installazione libsecp256k1 da sorgente..." + git clone https://github.com/bitcoin-core/secp256k1.git /tmp/secp256k1 + cd /tmp/secp256k1 && ./autogen.sh && ./configure && make && sudo make install + sudo ldconfig + @echo "[+] libsecp256k1 installata!" + +help: + @echo "===================================================" + @echo " Bitcoin P2PK Bruteforce - Makefile" + @echo "===================================================" + @echo "" + @echo "Target disponibili:" + @echo " make - Compila il programma" + @echo " make optimized - Compila con PGO step 1" + @echo " make pgo-use - Compila con PGO step 2" + @echo " make static - Compila versione statica" + @echo " make debug - Compila versione debug" + @echo " make test - Test rapido" + @echo " make clean - Rimuove file compilati" + @echo " make install-deps - Installa dipendenze" + @echo " make install-secp256k1 - Compila secp256k1 da sorgente" + @echo "" + @echo "Uso:" + @echo " ./$(TARGET) [file_chiavi.txt]" + @echo "" + @echo "===================================================" + +.PHONY: all optimized pgo-use static debug test clean install-deps install-secp256k1 help diff --git a/bruteforce/README.md b/bruteforce/README.md new file mode 100644 index 0000000..06b4425 --- /dev/null +++ b/bruteforce/README.md @@ -0,0 +1,351 @@ +# Bitcoin P2PK Bruteforce + +Programma C++ ad alte prestazioni per la ricerca di chiavi private corrispondenti a indirizzi P2PK Bitcoin con UTXO non spesi. + +## ⚠️ DISCLAIMER IMPORTANTE + +**Questo programma è SOLO per scopi educativi e di ricerca.** + +- **Probabilità di successo**: Praticamente zero (1 su 2^256) +- **Scopo**: Dimostrare la sicurezza crittografica di Bitcoin +- **Non utilizzare per attività illegali** +- **La ricerca di chiavi private altrui è illegale** + +Questo progetto serve a comprendere: +- Come funziona la crittografia a curva ellittica (secp256k1) +- Come vengono generate le chiavi pubbliche da quelle private +- La vastità dello spazio delle chiavi (2^256 possibilità) +- L'impossibilità pratica di trovare chiavi per bruteforce + +## Caratteristiche + +- **Alta efficienza**: Ottimizzato per massime prestazioni +- **Multi-threading**: Utilizza tutti i core della CPU +- **Libreria secp256k1**: La stessa usata da Bitcoin Core +- **Chiavi non compresse**: Genera pubkey in formato P2PK classico (65 bytes) +- **Ricerca incrementale**: Inizia da random, poi incrementa +- **Logging**: Salva progresso e velocità in CSV +- **Salvataggio automatico**: Se trova una corrispondenza + +## Requisiti + +### Dipendenze + +- **Compilatore**: GCC/G++ con supporto C++11 +- **libsecp256k1**: Libreria Bitcoin per operazioni su curva ellittica +- **libgmp**: GNU Multiple Precision Arithmetic Library +- **pthread**: Thread POSIX (incluso in Linux) + +### Installazione dipendenze + +#### Ubuntu/Debian + +```bash +sudo apt-get update +sudo apt-get install build-essential libsecp256k1-dev libgmp-dev git autoconf libtool pkg-config +``` + +Oppure usa il Makefile: + +```bash +cd bruteforce +make install-deps +``` + +#### Compilare secp256k1 da sorgente (opzionale) + +Se la versione nei repository è vecchia o mancante: + +```bash +make install-secp256k1 +``` + +Questo scarica, compila e installa l'ultima versione di libsecp256k1 da GitHub. + +## Compilazione + +### Compilazione standard + +```bash +cd bruteforce +make +``` + +Questo crea l'eseguibile `p2pk_bruteforce` con ottimizzazioni `-O3` e flags native. + +### Compilazione con ottimizzazioni massime + +```bash +make optimized +``` + +Questo abilita Profile-Guided Optimization (PGO) in due step: +1. Prima compilazione genera profilo di esecuzione +2. Seconda compilazione usa il profilo per ottimizzare + +### Altre opzioni di compilazione + +```bash +make static # Compilazione statica (portable) +make debug # Compilazione con simboli debug +make clean # Rimuove file compilati +make help # Mostra tutti i comandi disponibili +``` + +## Utilizzo + +### 1. Estrai le chiavi P2PK non spese + +Prima di eseguire il bruteforce, devi estrarre le chiavi pubbliche target dal database dello scanner: + +```bash +cd bruteforce +python3 extract_p2pk_utxo.py +``` + +Questo script: +- Legge il database SQLite (`../databases/bitcoin_p2pk_study.db`) +- Estrae solo i P2PK con `is_unspent = 1` +- Mostra statistiche (numero chiavi, valore totale, top 10) +- Crea il file `target_keys.txt` con le pubkey (una per riga) + +Output esempio: + +``` +============================================================ + STATISTICHE DATABASE P2PK +============================================================ +Totale P2PK: 150 +P2PK non spesi: 12 +P2PK spesi: 138 +------------------------------------------------------------ +Valore totale: 1234.56789012 BTC +Valore non speso: 50.00000000 BTC +Valore speso: 1184.56789012 BTC +============================================================ +``` + +### 2. Esegui il bruteforce + +```bash +./p2pk_bruteforce [file_chiavi.txt] +``` + +Se non specifichi il file, usa `target_keys.txt` di default. + +### 3. Monitor del progresso + +Il programma mostra: +- Numero di tentativi effettuati +- Velocità (keys/sec) +- Tempo trascorso +- Aggiornamenti ogni 1.000.000 di tentativi + +Esempio output: + +``` +======================================== + Bitcoin P2PK Bruteforce v1.0 + SOLO PER SCOPI EDUCATIVI +======================================== + +[+] Inizializzazione secp256k1... +[+] Caricamento chiavi target da target_keys.txt... +[+] Caricate 12 chiavi pubbliche target +[+] Avvio 8 thread worker... + +[+] Thread 0 avviato (seed: 1234567890) +[+] Thread 1 avviato (seed: 1234580235) +... + +[INFO] Tentativi: 10000000 | Velocità: 125000.00 keys/sec | Tempo: 80s +[INFO] Tentativi: 20000000 | Velocità: 133000.00 keys/sec | Tempo: 150s +... +``` + +### 4. Se trova una chiave + +Se il programma trova una corrispondenza, verrà stampata a schermo e salvata in `found_keys.txt`: + +``` +======================================== +🎯 CHIAVE TROVATA! 🎯 +======================================== +Private Key: 000000000000000000000000000000000000000000000000123456789abcdef +Public Key: 04a1b2c3d4e5f6... +======================================== +``` + +**NOTA**: È estremamente improbabile che questo accada mai. + +## File generati + +- **`target_keys.txt`**: Chiavi pubbliche target (input) +- **`found_keys.txt`**: Chiavi trovate (se succede) +- **`progress.csv`**: Log del progresso con timestamp, tentativi, velocità +- **`p2pk_bruteforce`**: Eseguibile compilato + +## Configurazione avanzata + +Puoi modificare i parametri nel file sorgente [`p2pk_bruteforce.cpp`](p2pk_bruteforce.cpp): + +```cpp +#define NUM_THREADS 8 // Numero di thread (default: 8) +#define BATCH_SIZE 10000 // Batch prima di sincronizzare +#define SAVE_INTERVAL 300 // Salva progresso ogni N secondi +#define PROGRESS_INTERVAL 1000000 // Mostra progresso ogni N tentativi +``` + +Dopo aver modificato, ricompila: + +```bash +make clean +make +``` + +## Performance + +### Velocità tipiche + +- **CPU moderna (8 core)**: ~100.000 - 500.000 keys/sec +- **CPU high-end (16+ core)**: ~1.000.000+ keys/sec +- **Raspberry Pi 4**: ~10.000 - 50.000 keys/sec + +### Ottimizzazioni + +1. **Usa tutti i core**: Modifica `NUM_THREADS` al numero di core della CPU +2. **Compilazione nativa**: Flag `-march=native -mtune=native` +3. **Profile-Guided Optimization**: Usa `make optimized` +4. **Batch size**: Aumenta `BATCH_SIZE` per ridurre lock contention +5. **Riduci I/O**: Aumenta `PROGRESS_INTERVAL` per stampare meno frequentemente + +## Matematica della probabilità + +### Spazio delle chiavi + +- **Chiavi private possibili**: 2^256 ≈ 1.16 × 10^77 +- **Velocità ipotetica**: 1.000.000 keys/sec +- **Tempo per testare tutte**: 3.67 × 10^63 anni +- **Età dell'universo**: 1.38 × 10^10 anni + +### Probabilità di successo + +Con **N** tentativi, la probabilità di trovare UNA specifica chiave è: + +``` +P(successo) = N / 2^256 +``` + +Esempi: +- **1 miliardo di tentativi** (10^9): P ≈ 8.6 × 10^-69 (praticamente zero) +- **1 trilione al secondo per 1 anno**: P ≈ 2.7 × 10^-60 (ancora zero) +- **Tutti i computer del mondo per 1 milione di anni**: P ≈ 10^-40 (sempre zero) + +**Conclusione**: È più probabile: +- Vincere la lotteria 10 volte consecutive +- Essere colpiti da un fulmine ogni giorno per un anno +- Trovare un atomo specifico nell'universo + +## Sicurezza di Bitcoin + +Questo progetto dimostra perché Bitcoin è sicuro: + +1. **Spazio enorme**: 2^256 chiavi possibili +2. **Impossibilità computazionale**: Anche con tutti i computer del mondo +3. **Crescita esponenziale**: Aggiungere 1 bit raddoppia il tempo necessario +4. **Crittografia provata**: secp256k1 è lo standard dell'industria + +## Troubleshooting + +### Errore: libsecp256k1 non trovata + +```bash +# Verifica installazione +ldconfig -p | grep secp256k1 + +# Se non trovata, installa: +make install-secp256k1 +``` + +### Errore di compilazione: pthread + +Assicurati di avere il flag `-pthread`: + +```bash +g++ -pthread ... -o p2pk_bruteforce p2pk_bruteforce.cpp -lsecp256k1 +``` + +### Velocità troppo bassa + +1. Verifica che `NUM_THREADS` corrisponda ai core della CPU +2. Chiudi altri programmi pesanti +3. Usa compilazione ottimizzata: `make optimized` +4. Verifica temperatura CPU (throttling termico) + +### Il programma non trova nulla + +**Questo è normale.** La probabilità di trovare una chiave è praticamente zero. + +Se vuoi testare il funzionamento: +1. Genera una chiave privata nota +2. Calcola la pubkey con secp256k1 +3. Aggiungi la pubkey a `target_keys.txt` +4. Esegui il bruteforce (ci vorranno comunque miliardi di tentativi) + +## Struttura del codice + +``` +bruteforce/ +├── p2pk_bruteforce.cpp # Codice sorgente principale +├── Makefile # Compilazione +├── extract_p2pk_utxo.py # Script estrazione chiavi +├── README.md # Questa guida +├── target_keys.txt # Chiavi target (generato) +├── found_keys.txt # Chiavi trovate (se succede) +└── progress.csv # Log progresso (generato) +``` + +## Algoritmo + +1. **Caricamento target**: Legge le pubkey P2PK dal file +2. **Inizializzazione**: Crea contesto secp256k1 e thread +3. **Loop principale**: + - Genera chiave privata casuale (256 bit) + - Calcola pubkey non compressa (65 bytes) con secp256k1 + - Confronta con tutte le pubkey target (hash set - O(1)) + - Se match: salva e stampa + - Altrimenti: incrementa privkey e riprova +4. **Multi-threading**: Ogni thread ha seed diverso +5. **Logging**: Salva progresso periodicamente + +## Licenza e crediti + +- **Scopo**: Educativo e di ricerca +- **Libreria**: [libsecp256k1](https://github.com/bitcoin-core/secp256k1) (Bitcoin Core) +- **Crittografia**: secp256k1 (ECDSA) + +## Domande frequenti + +### Q: Quanto tempo ci vorrà per trovare una chiave? + +**A**: Con la velocità attuale dei computer, circa 10^60 volte l'età dell'universo. + +### Q: E se uso una GPU? + +**A**: Anche con GPU, il tempo sarebbe ancora astronomico. La sicurezza di Bitcoin si basa proprio su questo. + +### Q: Posso parallelizzare su più macchine? + +**A**: Sì, ma non cambierebbe la sostanza. Anche con 1 miliardo di computer, le probabilità restano zero. + +### Q: Qualcuno ha mai trovato una chiave per bruteforce? + +**A**: No. E non succederà mai con questo metodo. + +### Q: Allora perché esiste questo programma? + +**A**: Per scopi educativi. Per capire come funziona Bitcoin e perché è sicuro. + +--- + +**⚠️ Ricorda**: Questo progetto dimostra l'impossibilità pratica del bruteforce su Bitcoin. La crittografia funziona. diff --git a/bruteforce/extract_p2pk_utxo.py b/bruteforce/extract_p2pk_utxo.py new file mode 100755 index 0000000..b6537f4 --- /dev/null +++ b/bruteforce/extract_p2pk_utxo.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python3 +""" +Script per estrarre chiavi pubbliche P2PK con UTXO non spesi +dal database SQLite generato dallo scanner +""" + +import sqlite3 +import sys +import os + +def extract_p2pk_unspent(db_path, output_file): + """ + Estrae le chiavi pubbliche P2PK non spese dal database + e le salva in un file di testo (una per riga) + """ + + # Verifica esistenza database + if not os.path.exists(db_path): + print(f"[ERROR] Database non trovato: {db_path}") + print("[!] Esegui prima lo scanner Python per creare il database") + return False + + try: + # Connetti al database + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # Query per ottenere solo P2PK non spesi + query = """ + SELECT + scriptpubkey, + block_height, + txid, + output_index, + value_satoshi + FROM p2pk_addresses + WHERE is_unspent = 1 + ORDER BY value_satoshi DESC + """ + + cursor.execute(query) + results = cursor.fetchall() + + if not results: + print("[!] Nessun P2PK non speso trovato nel database") + conn.close() + return False + + print(f"[+] Trovati {len(results)} P2PK non spesi") + print("[+] Estrazione in corso...") + + # Estrai le chiavi pubbliche + pubkeys = [] + total_value = 0 + + with open(output_file, 'w') as f: + # Header + f.write("# Bitcoin P2PK Public Keys (Unspent)\n") + f.write("# Format: One public key per line (hex, uncompressed)\n") + f.write("# Generated from database\n") + f.write("#\n") + + for row in results: + scriptpubkey, block_height, txid, output_index, value_sat = row + + # Il scriptpubkey è nel formato: 41ac o 21ac + # Dobbiamo estrarre solo la pubkey + + # Rimuovi il primo byte (41 o 21) e l'ultimo byte (ac - OP_CHECKSIG) + if len(scriptpubkey) == 134: # Non compresso: 41 + 130 char (65 bytes) + ac + pubkey = scriptpubkey[2:-2] # Rimuovi 41 e ac + elif len(scriptpubkey) == 70: # Compresso: 21 + 66 char (33 bytes) + ac + pubkey = scriptpubkey[2:-2] # Rimuovi 21 e ac + # NOTA: Il bruteforce genera solo pubkey non compresse + # quindi le chiavi compresse non verranno trovate + print(f"[!] SKIP chiave compressa: {txid}:{output_index}") + continue + else: + print(f"[!] SKIP formato sconosciuto: {scriptpubkey}") + continue + + # Aggiungi il prefisso 04 se non c'è (formato non compresso) + if not pubkey.startswith('04'): + pubkey = '04' + pubkey + + # Verifica lunghezza corretta (130 caratteri hex = 65 bytes) + if len(pubkey) != 130: + print(f"[!] SKIP lunghezza errata ({len(pubkey)}): {txid}:{output_index}") + continue + + # Scrivi la pubkey nel file + f.write(f"{pubkey}\n") + pubkeys.append(pubkey) + total_value += value_sat + + # Info dettagliate + btc_value = value_sat / 100000000.0 + print(f" [{len(pubkeys)}] Block {block_height} | {btc_value:.8f} BTC | {txid[:16]}...:{output_index}") + + conn.close() + + # Statistiche finali + print("\n" + "="*60) + print(" ESTRAZIONE COMPLETATA") + print("="*60) + print(f"Chiavi pubbliche estratte: {len(pubkeys)}") + print(f"Valore totale: {total_value / 100000000.0:.8f} BTC") + print(f"Valore totale: {total_value:,} satoshi") + print(f"File output: {output_file}") + print("="*60) + + return True + + except sqlite3.Error as e: + print(f"[ERROR] Errore database: {e}") + return False + except Exception as e: + print(f"[ERROR] Errore: {e}") + return False + + +def show_stats(db_path): + """ + Mostra statistiche sui P2PK nel database + """ + + if not os.path.exists(db_path): + print(f"[ERROR] Database non trovato: {db_path}") + return + + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # Statistiche generali + cursor.execute("SELECT COUNT(*) FROM p2pk_addresses") + total_p2pk = cursor.fetchone()[0] + + cursor.execute("SELECT COUNT(*) FROM p2pk_addresses WHERE is_unspent = 1") + unspent_p2pk = cursor.fetchone()[0] + + cursor.execute("SELECT SUM(value_satoshi) FROM p2pk_addresses") + total_value = cursor.fetchone()[0] or 0 + + cursor.execute("SELECT SUM(value_satoshi) FROM p2pk_addresses WHERE is_unspent = 1") + unspent_value = cursor.fetchone()[0] or 0 + + print("\n" + "="*60) + print(" STATISTICHE DATABASE P2PK") + print("="*60) + print(f"Totale P2PK: {total_p2pk}") + print(f"P2PK non spesi: {unspent_p2pk}") + print(f"P2PK spesi: {total_p2pk - unspent_p2pk}") + print(f"-" * 60) + print(f"Valore totale: {total_value / 100000000.0:.8f} BTC") + print(f"Valore non speso: {unspent_value / 100000000.0:.8f} BTC") + print(f"Valore speso: {(total_value - unspent_value) / 100000000.0:.8f} BTC") + print("="*60) + + # Top 10 P2PK non spesi per valore + print("\nTop 10 P2PK non spesi per valore:") + print("-" * 60) + + cursor.execute(""" + SELECT block_height, txid, output_index, value_satoshi, scriptpubkey + FROM p2pk_addresses + WHERE is_unspent = 1 + ORDER BY value_satoshi DESC + LIMIT 10 + """) + + for i, row in enumerate(cursor.fetchall(), 1): + block, txid, vout, value, script = row + btc = value / 100000000.0 + print(f"{i:2d}. Block {block:7d} | {btc:12.8f} BTC | {txid[:16]}...:{vout}") + + print("="*60 + "\n") + + conn.close() + + except sqlite3.Error as e: + print(f"[ERROR] Errore database: {e}") + + +def main(): + # Percorsi di default + db_path = "../databases/bitcoin_p2pk_study.db" + output_file = "target_keys.txt" + + print("="*60) + print(" Bitcoin P2PK UTXO Extractor") + print(" Estrae chiavi pubbliche non spese per bruteforce") + print("="*60) + print() + + # Controlla argomenti + if len(sys.argv) > 1: + if sys.argv[1] in ['-h', '--help']: + print("Uso:") + print(f" {sys.argv[0]} [database.db] [output.txt]") + print() + print("Esempi:") + print(f" {sys.argv[0]}") + print(f" {sys.argv[0]} custom.db keys.txt") + print(f" {sys.argv[0]} --stats") + return + elif sys.argv[1] == '--stats': + show_stats(db_path) + return + else: + db_path = sys.argv[1] + + if len(sys.argv) > 2: + output_file = sys.argv[2] + + # Mostra statistiche prima dell'estrazione + show_stats(db_path) + + # Conferma utente + print(f"[?] Database: {db_path}") + print(f"[?] Output: {output_file}") + print() + response = input("Procedere con l'estrazione? (s/n): ") + + if response.lower() not in ['s', 'y', 'si', 'yes']: + print("[!] Operazione annullata") + return + + # Estrai le chiavi + print() + if extract_p2pk_unspent(db_path, output_file): + print() + print("[+] Estrazione completata con successo!") + print(f"[+] Ora puoi eseguire: ./p2pk_bruteforce {output_file}") + else: + print() + print("[!] Estrazione fallita") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/bruteforce/p2pk_bruteforce.cpp b/bruteforce/p2pk_bruteforce.cpp new file mode 100644 index 0000000..35f1647 --- /dev/null +++ b/bruteforce/p2pk_bruteforce.cpp @@ -0,0 +1,405 @@ +/* + * Bitcoin P2PK Bruteforce - Ricerca chiavi private + * Utilizza libsecp256k1 per massima efficienza + * + * DISCLAIMER: Solo per scopi educativi e di ricerca + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Configurazione +#define BATCH_SIZE 10000 +#define SAVE_INTERVAL 300 // Salva progresso ogni 5 minuti +#define PROGRESS_INTERVAL 1000000 // Mostra progresso ogni N tentativi +#define MAX_THREADS 256 // Massimo numero di thread supportati + +// Struttura per memorizzare le chiavi pubbliche target +struct TargetKey { + uint8_t pubkey[65]; // Chiave pubblica non compressa (65 bytes) + char hex[131]; // Rappresentazione hex +}; + +// Variabili globali +static volatile int keep_running = 1; +static secp256k1_context* ctx = NULL; +static std::vector target_keys; +static std::unordered_set target_set; +static uint64_t total_attempts = 0; +static uint64_t attempts_per_thread[MAX_THREADS] = {0}; +static time_t start_time; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static FILE* log_file = NULL; +static int num_threads = 0; // Numero effettivo di thread da usare + +// Struttura per i thread +struct ThreadData { + int thread_id; + uint64_t seed; +}; + +// Rileva numero di thread/core disponibili +int get_num_threads() { + int num = (int)sysconf(_SC_NPROCESSORS_ONLN); + if (num < 1) num = 1; + if (num > MAX_THREADS) num = MAX_THREADS; + return num; +} + +// Signal handler per chiusura pulita +void sigint_handler(int sig) { + (void)sig; + keep_running = 0; + printf("\n\n[!] Interruzione rilevata, chiusura in corso...\n"); +} + +// Converti bytes in hex +void bytes_to_hex(const uint8_t* bytes, size_t len, char* hex) { + for (size_t i = 0; i < len; i++) { + sprintf(hex + (i * 2), "%02x", bytes[i]); + } + hex[len * 2] = '\0'; +} + +// Converti hex in bytes +int hex_to_bytes(const char* hex, uint8_t* bytes, size_t len) { + if (strlen(hex) != len * 2) return 0; + for (size_t i = 0; i < len; i++) { + sscanf(hex + (i * 2), "%2hhx", &bytes[i]); + } + return 1; +} + +// Carica le chiavi pubbliche P2PK dal file +int load_target_keys(const char* filename) { + std::ifstream file(filename); + if (!file.is_open()) { + fprintf(stderr, "[ERROR] Impossibile aprire %s\n", filename); + return 0; + } + + std::string line; + int count = 0; + + // Skip header se presente + std::getline(file, line); + + while (std::getline(file, line)) { + if (line.empty()) continue; + + // Estrai la chiave pubblica (formato: hex della pubkey) + // Il file dovrebbe contenere una pubkey per riga + std::string pubkey_hex = line; + + // Rimuovi spazi bianchi + pubkey_hex.erase(remove_if(pubkey_hex.begin(), pubkey_hex.end(), isspace), pubkey_hex.end()); + + // P2PK non compresso: 65 bytes (130 caratteri hex) + // Formato: 04 + 32 bytes X + 32 bytes Y + if (pubkey_hex.length() != 130 && pubkey_hex.length() != 128) { + continue; // Skip se non è una pubkey valida + } + + // Aggiungi 04 se manca (formato non compresso) + if (pubkey_hex.length() == 128) { + pubkey_hex = "04" + pubkey_hex; + } + + TargetKey key; + if (hex_to_bytes(pubkey_hex.c_str(), key.pubkey, 65)) { + strcpy(key.hex, pubkey_hex.c_str()); + target_keys.push_back(key); + target_set.insert(std::string((char*)key.pubkey, 65)); + count++; + } + } + + file.close(); + printf("[+] Caricate %d chiavi pubbliche target\n", count); + return count; +} + +// Genera una chiave privata casuale +void generate_random_privkey(uint8_t* privkey, uint64_t* seed) { + // Usa un PRNG veloce (xorshift64) + *seed ^= *seed << 13; + *seed ^= *seed >> 7; + *seed ^= *seed << 17; + + // Riempi i 32 bytes della privkey + uint64_t* key64 = (uint64_t*)privkey; + for (int i = 0; i < 4; i++) { + *seed ^= *seed << 13; + *seed ^= *seed >> 7; + *seed ^= *seed << 17; + key64[i] = *seed; + } + + // Assicurati che la chiave sia valida (< ordine della curva) + // In pratica, quasi tutti i 256 bit casuali sono validi +} + +// Incrementa la chiave privata +void increment_privkey(uint8_t* privkey) { + for (int i = 31; i >= 0; i--) { + if (++privkey[i] != 0) break; + } +} + +// Verifica se la pubkey corrisponde a un target +int check_match(const uint8_t* pubkey) { + std::string key_str((char*)pubkey, 65); + return target_set.find(key_str) != target_set.end(); +} + +// Salva una chiave trovata +void save_found_key(const uint8_t* privkey, const uint8_t* pubkey) { + pthread_mutex_lock(&mutex); + + char priv_hex[65], pub_hex[131]; + bytes_to_hex(privkey, 32, priv_hex); + bytes_to_hex(pubkey, 65, pub_hex); + + // Stampa a schermo + printf("\n\n"); + printf("========================================\n"); + printf("🎯 CHIAVE TROVATA! 🎯\n"); + printf("========================================\n"); + printf("Private Key: %s\n", priv_hex); + printf("Public Key: %s\n", pub_hex); + printf("========================================\n\n"); + + // Salva su file + FILE* found_file = fopen("found_keys.txt", "a"); + if (found_file) { + time_t now = time(NULL); + fprintf(found_file, "\n=== FOUND at %s", ctime(&now)); + fprintf(found_file, "Private Key: %s\n", priv_hex); + fprintf(found_file, "Public Key: %s\n", pub_hex); + fprintf(found_file, "========================================\n"); + fclose(found_file); + } + + pthread_mutex_unlock(&mutex); +} + +// Formatta numero con suffisso K, M, G, T +void format_number(uint64_t num, char* buffer) { + if (num >= 1000000000000ULL) { + sprintf(buffer, "%.2fT", num / 1000000000000.0); + } else if (num >= 1000000000ULL) { + sprintf(buffer, "%.2fG", num / 1000000000.0); + } else if (num >= 1000000ULL) { + sprintf(buffer, "%.2fM", num / 1000000.0); + } else if (num >= 1000ULL) { + sprintf(buffer, "%.2fK", num / 1000.0); + } else { + sprintf(buffer, "%lu", num); + } +} + +// Log progresso +void log_progress() { + pthread_mutex_lock(&mutex); + + time_t now = time(NULL); + double elapsed = difftime(now, start_time); + if (elapsed < 1) elapsed = 1; + + uint64_t total = 0; + for (int i = 0; i < num_threads; i++) { + total += attempts_per_thread[i]; + } + + double rate = total / elapsed; + + char total_str[32]; + char rate_str[32]; + format_number(total, total_str); + format_number((uint64_t)rate, rate_str); + + printf("[INFO] Tentativi: %s | Velocità: %s keys/sec | Tempo: %.0fs\n", + total_str, rate_str, elapsed); + + if (log_file) { + fprintf(log_file, "%ld,%lu,%.2f\n", now, total, rate); + fflush(log_file); + } + + pthread_mutex_unlock(&mutex); +} + +// Thread worker +void* worker_thread(void* arg) { + ThreadData* data = (ThreadData*)arg; + int thread_id = data->thread_id; + uint64_t seed = data->seed; + + uint8_t privkey[32]; + uint8_t pubkey[65]; + secp256k1_pubkey pubkey_obj; + size_t pubkey_len = 65; + + uint64_t local_attempts = 0; + + printf("[+] Thread %d avviato (seed: %lu)\n", thread_id, seed); + + while (keep_running) { + // Genera batch di chiavi + for (int batch = 0; batch < BATCH_SIZE && keep_running; batch++) { + // Genera chiave privata casuale + generate_random_privkey(privkey, &seed); + + // Genera chiave pubblica non compressa usando secp256k1 + if (secp256k1_ec_pubkey_create(ctx, &pubkey_obj, privkey)) { + // Serializza in formato non compresso (65 bytes) + secp256k1_ec_pubkey_serialize(ctx, pubkey, &pubkey_len, + &pubkey_obj, SECP256K1_EC_UNCOMPRESSED); + + // Verifica corrispondenza + if (check_match(pubkey)) { + save_found_key(privkey, pubkey); + } + } + + local_attempts++; + + // Incrementa la chiave privata per il prossimo tentativo + increment_privkey(privkey); + } + + // Aggiorna contatore globale + pthread_mutex_lock(&mutex); + attempts_per_thread[thread_id] = local_attempts; + pthread_mutex_unlock(&mutex); + + // Mostra progresso periodicamente + if (local_attempts % PROGRESS_INTERVAL == 0) { + log_progress(); + } + } + + printf("[+] Thread %d terminato (%lu tentativi)\n", thread_id, local_attempts); + return NULL; +} + +int main(int argc, char** argv) { + printf("========================================\n"); + printf(" Bitcoin P2PK Bruteforce v1.0\n"); + printf(" SOLO PER SCOPI EDUCATIVI\n"); + printf("========================================\n\n"); + + // Gestisci argomenti + const char* target_file = "target_keys.txt"; + if (argc > 1) { + target_file = argv[1]; + } + + // Inizializza secp256k1 + printf("[+] Inizializzazione secp256k1...\n"); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + if (!ctx) { + fprintf(stderr, "[ERROR] Impossibile creare contesto secp256k1\n"); + return 1; + } + + // Carica chiavi target + printf("[+] Caricamento chiavi target da %s...\n", target_file); + if (load_target_keys(target_file) == 0) { + fprintf(stderr, "[ERROR] Nessuna chiave target caricata\n"); + secp256k1_context_destroy(ctx); + return 1; + } + + // Setup signal handler + signal(SIGINT, sigint_handler); + signal(SIGTERM, sigint_handler); + + // Apri file di log + log_file = fopen("progress.csv", "w"); + if (log_file) { + fprintf(log_file, "timestamp,attempts,keys_per_sec\n"); + } + + // Rileva numero di thread disponibili + num_threads = get_num_threads(); + printf("[+] CPU rilevata: %d thread disponibili\n", num_threads); + + // Inizializza timestamp + start_time = time(NULL); + + // Crea threads + pthread_t threads[MAX_THREADS]; + ThreadData thread_data[MAX_THREADS]; + + printf("[+] Avvio %d thread worker...\n\n", num_threads); + + for (int i = 0; i < num_threads; i++) { + thread_data[i].thread_id = i; + thread_data[i].seed = (uint64_t)time(NULL) + i * 12345; + pthread_create(&threads[i], NULL, worker_thread, &thread_data[i]); + } + + // Loop principale - mostra progresso + while (keep_running) { + sleep(10); + log_progress(); + } + + // Attendi terminazione threads + printf("[+] Attesa terminazione threads...\n"); + for (int i = 0; i < num_threads; i++) { + pthread_join(threads[i], NULL); + } + + // Statistiche finali + printf("\n========================================\n"); + printf(" STATISTICHE FINALI\n"); + printf("========================================\n"); + + uint64_t total = 0; + char thread_str[32]; + for (int i = 0; i < num_threads; i++) { + total += attempts_per_thread[i]; + format_number(attempts_per_thread[i], thread_str); + printf("Thread %d: %s tentativi\n", i, thread_str); + } + + time_t end_time = time(NULL); + double elapsed = difftime(end_time, start_time); + if (elapsed < 1) elapsed = 1; + + char total_str[32]; + char rate_str[32]; + format_number(total, total_str); + format_number((uint64_t)(total / elapsed), rate_str); + + printf("----------------------------------------\n"); + printf("Totale tentativi: %s\n", total_str); + printf("Tempo totale: %.0f secondi\n", elapsed); + printf("Velocità media: %s keys/sec\n", rate_str); + printf("========================================\n\n"); + + // Cleanup + if (log_file) fclose(log_file); + secp256k1_context_destroy(ctx); + + printf("[+] Programma terminato\n"); + return 0; +}