# Makefile per Bitcoin P2PK Bruteforce

CC = g++

# Ottimizzazioni aggressive per CPU moderna
# -O3: massima ottimizzazione
# -march=native: usa tutte le istruzioni del processore (AVX2, SSE4.2, etc)
# -mtune=native: ottimizza per il processore specifico
# -flto: Link Time Optimization
# -ffast-math: ottimizzazioni matematiche aggressive (safe per crypto)
# -funroll-loops: srotola loop piccoli
# -finline-functions: inline aggressivo
# -fprefetch-loop-arrays: prefetch automatico
# -faligned-new: supporto per aligned new (C++17)
CFLAGS = -O3 -march=native -mtune=native -flto -ffast-math \
         -funroll-loops -finline-functions -fprefetch-loop-arrays \
         -faligned-new -pthread -Wall -Wextra -std=c++17

# Librerie necessarie
LIBS = -lsecp256k1 -lgmp

# Target
TARGET = p2pk_bruteforce
SOURCE = p2pk_bruteforce.cpp

# Percorsi libreria
INCLUDE_PATH = -I/usr/local/include -I/usr/include
LIB_PATH = -L/usr/local/lib -L/usr/lib

# Versione GPU (CUDA)
NVCC = nvcc
# Architettura GPU target: sm_61 = Pascal (es. Quadro/GTX 10xx). Sovrascrivi con
# `make gpu NVCC_ARCH=sm_75` (Turing), sm_86 (Ampere), sm_89 (Ada) etc. secondo la tua GPU.
NVCC_ARCH = sm_61
GPU_TARGET = p2pk_bruteforce_gpu
GPU_SOURCE = p2pk_bruteforce_gpu.cu

# ============================================================================
# TARGET PRINCIPALI
# ============================================================================

all: build

# Compilazione standard
build: $(SOURCE)
	@echo "========================================="
	@echo "  Bitcoin P2PK Bruteforce - Compilazione"
	@echo "========================================="
	@if [ -d "secp256k1" ]; then \
		echo "[+] Compilazione con libsecp256k1 locale..."; \
		$(CC) $(CFLAGS) \
			-I./secp256k1/include \
			-L./secp256k1/lib \
			-Wl,-rpath,$(shell pwd)/secp256k1/lib \
			-o $(TARGET) $(SOURCE) $(LIBS); \
	else \
		echo "[+] Compilazione con libsecp256k1 di sistema..."; \
		$(CC) $(CFLAGS) $(INCLUDE_PATH) $(LIB_PATH) \
			-o $(TARGET) $(SOURCE) $(LIBS); \
	fi
	@echo "[+] Compilazione completata!"
	@echo "[+] Eseguibile: ./$(TARGET)"
	@echo ""
	@echo "OTTIMIZZAZIONI ATTIVE:"
	@echo "  ✓ Batch EC point addition (256 keys/iteration)"
	@echo "  ✓ Zero-copy lookup (no serialization)"
	@echo "  ✓ SIMD-optimized Bloom filter"
	@echo "  ✓ Cache-aligned memory"
	@echo "  ✓ CPU prefetching hints"
	@echo "  ✓ LTO & aggressive inlining"
	@echo ""
	@echo "PERFORMANCE ATTESE: 800K - 2M keys/sec"
	@echo "========================================="

# ============================================================================
# PROFILE-GUIDED OPTIMIZATION (PGO)
# ============================================================================

pgo: pgo-generate pgo-run pgo-use

pgo-generate: $(SOURCE)
	@echo "[+] Step 1/3: Compilazione con profile generation..."
	@if [ -d "secp256k1" ]; then \
		$(CC) $(CFLAGS) -fprofile-generate \
			-I./secp256k1/include \
			-L./secp256k1/lib \
			-Wl,-rpath,$(shell pwd)/secp256k1/lib \
			-o $(TARGET)_pgo $(SOURCE) $(LIBS); \
	else \
		$(CC) $(CFLAGS) -fprofile-generate $(INCLUDE_PATH) $(LIB_PATH) \
			-o $(TARGET)_pgo $(SOURCE) $(LIBS); \
	fi
	@echo "[+] Pronto per eseguire il programma e generare profilo..."
	@echo "[!] Esegui: timeout 30s ./$(TARGET)_pgo"

pgo-run:
	@echo "[+] Step 2/3: Generazione profilo (30 secondi)..."
	@timeout 30s ./$(TARGET)_pgo || true
	@echo "[+] Profilo generato!"

pgo-use: $(SOURCE)
	@echo "[+] Step 3/3: Ricompilazione con Profile-Guided Optimization..."
	@if [ -d "secp256k1" ]; then \
		$(CC) $(CFLAGS) -fprofile-use -fprofile-correction \
			-I./secp256k1/include \
			-L./secp256k1/lib \
			-Wl,-rpath,$(shell pwd)/secp256k1/lib \
			-o $(TARGET) $(SOURCE) $(LIBS); \
	else \
		$(CC) $(CFLAGS) -fprofile-use -fprofile-correction $(INCLUDE_PATH) $(LIB_PATH) \
			-o $(TARGET) $(SOURCE) $(LIBS); \
	fi
	@echo "[+] PGO compilazione completata!"
	@echo "[+] Eseguibile ottimizzato: ./$(TARGET)"
	@echo "[!] Performance attese: +10-20% aggiuntivo"
	@rm -f $(TARGET)_pgo

# ============================================================================
# UTILITÀ
# ============================================================================

# Versione debug
debug: $(SOURCE)
	@echo "[+] Compilazione DEBUG..."
	$(CC) -g -O0 -pthread -Wall -Wextra -std=c++17 \
		$(INCLUDE_PATH) $(LIB_PATH) \
		-o $(TARGET)_debug $(SOURCE) $(LIBS)
	@echo "[+] Eseguibile debug: ./$(TARGET)_debug"

# Analisi assembly generato
asm: $(SOURCE)
	@echo "[+] Generazione assembly..."
	$(CC) $(CFLAGS) -S -fverbose-asm $(INCLUDE_PATH) \
		-o $(TARGET).s $(SOURCE)
	@echo "[+] Assembly salvato in: $(TARGET).s"

# Benchmark veloce (10 secondi)
bench: build
	@echo "[+] Benchmark rapido (10 secondi)..."
	@timeout 10s ./$(TARGET) || true

# Test con valgrind (memory leaks)
valgrind: debug
	@echo "[+] Test con Valgrind..."
	valgrind --leak-check=full --show-leak-kinds=all \
		./$(TARGET)_debug

# Pulizia
clean:
	@echo "[+] Pulizia file compilati..."
	rm -f $(TARGET) $(TARGET)_debug $(TARGET)_pgo $(GPU_TARGET)
	rm -f *.o *.gcda *.gcno *.s
	rm -f progress.csv
	@echo "[+] Pulizia completata!"

clean-all: clean
	@echo "[+] Pulizia completa..."
	rm -rf secp256k1_build secp256k1
	@echo "[+] Pulizia completa terminata!"

# ============================================================================
# DIPENDENZE
# ============================================================================

install-deps:
	@echo "[+] Installazione dipendenze..."
	@echo "[!] Richiede: build-essential, libsecp256k1-dev, libgmp-dev"
	@read -p "Continuare? [y/N] " -n 1 -r; \
	echo; \
	if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
		sudo apt-get update && \
		sudo apt-get install -y build-essential libsecp256k1-dev libgmp-dev \
			git autoconf libtool pkg-config; \
		echo "[+] Dipendenze installate!"; \
	fi

build-secp256k1:
	@echo "[+] Compilazione libsecp256k1 ottimizzata..."
	@./build_secp256k1.sh

# ============================================================================
# VERSIONE GPU (CUDA)
# ============================================================================

# Richiede: NVIDIA CUDA Toolkit (nvcc) + driver NVIDIA funzionante (verifica
# con `nvidia-smi`). Su WSL2 il driver è quello del sistema Windows host: non
# va installato dentro WSL, basta il CUDA Toolkit (`nvcc --version` per controllare).
gpu: $(GPU_SOURCE)
	@echo "========================================="
	@echo "  Bitcoin P2PK Bruteforce GPU - Compilazione"
	@echo "========================================="
	@which $(NVCC) > /dev/null || (echo "[ERROR] nvcc non trovato. Installa il CUDA Toolkit."; exit 1)
	$(NVCC) -O3 -arch=$(NVCC_ARCH) -std=c++17 -diag-suppress 1650 \
		$(INCLUDE_PATH) $(LIB_PATH) \
		-o $(GPU_TARGET) $(GPU_SOURCE) -lsecp256k1
	@echo "[+] Compilazione completata!"
	@echo "[+] Eseguibile: ./$(GPU_TARGET)"
	@echo ""
	@echo "OTTIMIZZAZIONI ATTIVE:"
	@echo "  ✓ Batch EC point addition in coordinate Jacobiane (stesso algoritmo della CPU)"
	@echo "  ✓ Batch modular inversion (Montgomery) per thread"
	@echo "  ✓ Migliaia di thread paralleli invece di N core CPU"
	@echo "========================================="

gpu-info:
	@nvidia-smi --query-gpu=name,driver_version,memory.total,compute_cap --format=csv 2>&1 || \
		echo "[!] nvidia-smi non disponibile: driver NVIDIA non rilevato"
	@which $(NVCC) > /dev/null && $(NVCC) --version || echo "[!] nvcc non trovato: CUDA Toolkit non installato"

# ============================================================================
# HELP
# ============================================================================

help:
	@echo "==================================================="
	@echo "  Bitcoin P2PK Bruteforce - Makefile"
	@echo "==================================================="
	@echo ""
	@echo "Target disponibili:"
	@echo "  make                    - Compila il programma (default)"
	@echo "  make build              - Compila il programma"
	@echo "  make pgo                - Compila con Profile-Guided Optimization"
	@echo "  make debug              - Compila versione debug"
	@echo "  make asm                - Genera assembly per analisi"
	@echo "  make bench              - Benchmark rapido (10s)"
	@echo "  make valgrind           - Test memory leaks"
	@echo "  make clean              - Rimuove file compilati"
	@echo "  make clean-all          - Pulizia completa"
	@echo "  make install-deps       - Installa dipendenze"
	@echo "  make build-secp256k1    - Compila libsecp256k1 locale"
	@echo "  make gpu                - Compila la versione GPU (richiede CUDA Toolkit)"
	@echo "  make gpu-info           - Controlla driver NVIDIA e CUDA Toolkit disponibili"
	@echo ""
	@echo "Uso consigliato:"
	@echo "  1. make                 # Compila"
	@echo "  2. ./$(TARGET)          # Esegui bruteforce"
	@echo ""
	@echo "Per massime performance su CPU:"
	@echo "  make pgo                # Compila con PGO (+10-20% speed)"
	@echo ""
	@echo "Per usare la GPU (molto più veloce, se disponibile):"
	@echo "  make gpu-info           # Verifica driver/CUDA Toolkit"
	@echo "  make gpu                # Compila"
	@echo "  ./$(GPU_TARGET)         # Esegui"
	@echo ""
	@echo "==================================================="

.PHONY: all build pgo pgo-generate pgo-run pgo-use debug asm bench \
        valgrind clean clean-all install-deps build-secp256k1 gpu gpu-info help
