From 1a91b81de5c807e7ee31461dc3c98008e855e4d5 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Fri, 3 Jul 2026 15:41:40 +0200 Subject: [PATCH] Aggiungi CLAUDE.md per future istanze di Claude Code Documenta comandi di build/run per scanner Python e bruteforce C++, il flusso dati tra i due componenti e i dettagli architetturali non ovvi (partizionamento keyspace, euristica di rilevamento P2PK, accoppiamento tra formati file). --- CLAUDE.md | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..b873cf9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,70 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project purpose + +Educational/research suite for studying Bitcoin P2PK (Pay-to-Public-Key) transactions and demonstrating why ECDSA secp256k1 bruteforce is computationally infeasible (keyspace 2^256). All docs and CLI output are in Italian. Two independent components share data via files, not code: + +1. `databases/` — Python scanner that walks the Bitcoin blockchain via the mempool.space API, finds P2PK outputs, stores them in SQLite, and checks UTXO spent/unspent status. +2. `bruteforce/` — C++ program that loads target public keys and searches the private-key space for matches, as a performance demonstration (not a realistic attack — success probability is ~2^-256). + +Data flows one way: scanner → SQLite DB (`databases/bitcoin_p2pk_study.db`) → `extract_p2pk_utxo.py` filters unspent P2PK → `target_keys.txt` → C++ bruteforce consumes it. + +## Commands + +### Python scanner (`databases/`) +```bash +python3 -m venv .venv && source .venv/bin/activate +pip install -r requirements.txt + +cd databases +python3 scan_blockchain.py # interactive: prompts for start/end block + delay +python3 view_db.py # generates p2pk_report.html +python3 view_db.py --stats # prints stats to terminal +``` + +### C++ bruteforce (`bruteforce/`) +```bash +cd bruteforce +make install-deps # apt packages: build-essential, libsecp256k1-dev, libgmp-dev, autoconf, libtool, pkg-config +make # builds secp256k1 locally from source if bruteforce/secp256k1/ doesn't exist (~5 min first time), then compiles p2pk_bruteforce +make clean # remove binaries/object files +make clean-all # also removes the locally-built secp256k1 tree +make debug # -g -O0 build: p2pk_bruteforce_debug +make bench # 10-second timed run +make pgo # profile-guided optimization build (3-step: generate → run 30s → use) +make valgrind # leak check on the debug build +make help # list all targets + +python3 extract_p2pk_utxo.py [db_path] [output.txt] # default: ../databases/bitcoin_p2pk_study.db -> target_keys.txt +python3 extract_p2pk_utxo.py --stats # DB stats only, no extraction + +./p2pk_bruteforce [target_keys.txt] # runs until Ctrl+C; logs to progress.csv, matches to found_keys.txt +``` + +There is no test suite in this repo. + +## Architecture notes + +### `bruteforce/p2pk_bruteforce.cpp` (single file, everything lives here) +- One pthread per (core count − 1); each thread gets a disjoint slice of the 256-bit keyspace via `partition_keyspace` (only the top 64 bits are partitioned — the search relies on random start offsets within each thread's slice, not a full 256-bit range split). +- Target pubkeys are loaded from a `.txt` file (uncompressed hex, `04` prefix, one per line, header line skipped) into both an `unordered_map` (exact match) and a 64MB Bloom filter (fast negative rejection, checked first via `check_match_fast`). +- Performance trick: instead of computing `privkey * G` per candidate, it computes one EC multiplication then derives the next `EC_BATCH_SIZE` (256) keys via EC point addition against precomputed multiples of G (`precompute_generator_multiples`), which is much cheaper than repeated scalar multiplication. +- Build system auto-detects a local `bruteforce/secp256k1/` (built by `build_secp256k1.sh` targeting this specific CPU with `-march=native`) and links against it via rpath instead of the system lib; falls back to system `libsecp256k1`/`libgmp` if absent. +- Matches are written to `found_keys.txt`; periodic throughput stats go to stdout and `progress.csv` every 10s. + +### `databases/scan_blockchain.py` +- `P2PKBlockchainScanner` class wraps all mempool.space API access (`get_block_hash`, `get_block_transactions` with pagination, `check_utxo_status`) and SQLite persistence. +- P2PK detection is deliberately redundant — a script is classified as P2PK if ANY of 4 independent checks match: explicit `scriptpubkey_type`, script byte length (67 or 35 bytes), ASM pattern (` OP_CHECKSIG`), or raw hex pattern (`41ac` / `21ac`). This exists because the API's `scriptpubkey_type` field is not reliable for very old (pre-2012) P2PK outputs. +- Scanning is resumable: `scan_progress` table (single row, `id=1`) tracks `last_scanned_block`; reruns default to `last_scanned_block + 1`. `UNIQUE(txid, output_index)` on `p2pk_addresses` prevents duplicate inserts, so overlapping scan ranges are safe. +- This script and its SQLite DB/CSV outputs are intended to be committed and shared across contributors scanning different block ranges (see `.gitignore` — DB/CSV/HTML are NOT excluded). + +### `bruteforce/extract_p2pk_utxo.py` +- Reads only `is_unspent = 1` rows from the scanner's DB, strips the `41.../21...ac` script wrapper to get the raw pubkey, and re-adds the `04` prefix. +- Compressed pubkeys (33-byte, script length 70/hex prefix `21`) are explicitly skipped — the C++ bruteforce only generates and matches uncompressed public keys. + +## Key coupling to be aware of + +- The bruteforce binary's target file format (uncompressed hex pubkeys, `04` prefix, header line) is produced exclusively by `extract_p2pk_utxo.py` — if editing one side's format, update the other. +- `Makefile` CFLAGS use `-march=native`/`-mtune=native` and `-ffast-math`; binaries are not portable across different CPUs and should be rebuilt (`make clean && make`) after moving to different hardware.