const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const CHECKPOINT_DIR = './checkpoints';
const RESULTS_DIR = './results';
function* generatePrivateKey(start, end) {
let privateKey = start;
while (privateKey <= end) {
const hexString = privateKey.toString(16).padStart(64, '0');
yield Buffer.from(hexString, 'hex');
privateKey = privateKey + 1n;
}
}
if (isMainThread) {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const addresses = [];
let foundAddresses = new Set();
function askForAddress() {
rl.question('Enter a Bitcoin address to brute force (or press Enter to start): ', (address) => {
if (address.trim()) {
addresses.push(address);
askForAddress(); // Ask for another address if one was entered
} else {
if (addresses.length === 0) {
console.log('Please enter at least one Bitcoin address.');
askForAddress();
} else {
askStartMethod();
}
}
});
}
function askStartMethod() {
rl.question('Start fresh or resume from checkpoint? (fresh/resume/clear): ', (answer) => {
answer = answer.toLowerCase();
if (answer === 'fresh') {
clearCheckpoints();
startBruteForce(Array(16).fill(BigInt(0)));
} else if (answer === 'resume') {
loadCheckpoints();
} else if (answer === 'clear') {
clearCheckpoints();
console.log('Checkpoints cleared. Starting fresh...');
startBruteForce(Array(16).fill(BigInt(0)));
} else {
console.log('Invalid option. Please choose "fresh", "resume", or "clear".');
askStartMethod();
}
});
}
function loadCheckpoints() {
const maxKey = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
const lastCheckpoints = Array(16).fill(BigInt(0));
for (let i = 0; i < 16; i++) {
try {
const checkpointData = fs.readFileSync(path.join(CHECKPOINT_DIR, `worker_${i}.json`), 'utf8');
const { lastKey } = JSON.parse(checkpointData);
lastCheckpoints[i] = BigInt('0x' + lastKey);
console.log(`Worker ${i}: Resuming from checkpoint: ${lastKey}`);
} catch (e) {
console.error(`Worker ${i}: Error reading or parsing checkpoint:`, e.message);
console.log(`Worker ${i}: No valid checkpoint found, starting from 0.`);
}
}
startBruteForce(lastCheckpoints);
}
function clearCheckpoints() {
try {
fs.rmSync(CHECKPOINT_DIR, { recursive: true, force: true });
fs.mkdirSync(CHECKPOINT_DIR);
console.log('All checkpoint files have been deleted and directory recreated.');
} catch (error) {
console.log('Error clearing checkpoints:', error.message);
}
}
function startBruteForce(lastCheckpoints) {
const numWorkers = 16;
const maxKey = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
const workerRanges = [
{ start: 10, end: 6, id: 1 }, // Worker 1
{ start: 5, end: 1, id: 2 }, // Worker 2
{ start: 11, end: 15, id: 3 }, // Worker 3
{ start: 16, end: 20, id: 4 }, // Worker 4
{ start: 30, end: 26, id: 5 }, // Worker 5
{ start: 25, end: 21, id: 6 }, // Worker 6
{ start: 50, end: 46, id: 7 }, // Worker 7
{ start: 45, end: 41, id: 8 }, // Worker 8
{ start: 40, end: 36, id: 9 }, // Worker 9
{ start: 35, end: 31, id: 10 }, // Worker 10
{ start: 51, end: 55, id: 11 }, // Worker 11
{ start: 56, end: 60, id: 12 }, // Worker 12
{ start: 61, end: 65, id: 13 }, // Worker 13
{ start: 66, end: 76, id: 14 }, // Worker 14
{ start: 77, end: 87, id: 15 }, // Worker 15
{ start: 88, end: 100, id: 16 } // Worker 16
];
let workers = [];
for (let i = 0; i < numWorkers; i++) {
const range = workerRanges[i];
const start = BigInt(Math.floor(Number(maxKey) * (range.start / 100))) + (lastCheckpoints[i] || BigInt(0));
const end = BigInt(Math.floor(Number(maxKey) * (range.end / 100))) + (lastCheckpoints[i] || BigInt(0)) - 1n;
const worker = new Worker(__filename, {
workerData: { addresses, workerId: i, start: start.toString(), end: end.toString(), batchSize: "10000", range }
});
workers.push(worker);
worker.on('message', (message) => {
if (message.type === 'match') {
console.log(`Match found for ${message.address} by Worker ${message.workerId}`);
console.log('Private Key:', message.privateKey);
saveMatch(message.address, message.privateKey);
foundAddresses.add(message.address);
if (foundAddresses.size === addresses.length) {
console.log('All addresses matched. Stopping workers...');
workers.forEach(w => w.terminate());
}
} else if (message.type === 'progress') {
console.log(`Worker ${message.workerId}: Range ${message.range.start}% to ${message.range.end}% (${message.rangeStart} to ${message.rangeEnd}), Tried ${message.keysChecked} keys...`);
}
try {
fs.mkdirSync(CHECKPOINT_DIR, { recursive: true });
fs.writeFileSync(path.join(CHECKPOINT_DIR, `worker_${message.workerId}.json`), JSON.stringify({ lastKey: message.rangeEnd }));
} catch (writeErr) {
console.error(`Failed to save checkpoint for Worker ${message.workerId}:`, writeErr.message);
}
});
// Initial log of worker ranges
console.log(`Worker ${range.id}: Will check key range ${range.start}% to ${range.end}%`);
}
process.on('SIGINT', () => {
workers.forEach(w => w.terminate());
process.exit();
});
}
function saveMatch(address, privateKey) {
fs.mkdirSync(RESULTS_DIR, { recursive: true });
const fileName = `${RESULTS_DIR}/${address}.txt`;
fs.writeFileSync(fileName, `Address: ${address}\nPrivate Key: ${privateKey}`);
console.log(`Match saved to ${fileName}`);
}
askForAddress();
} else {
const { addresses, workerId, start, end, batchSize, range } = workerData;
const ec = crypto.createECDH('secp256k1');
let keysChecked = 0;
let currentStart = BigInt(start);
function checkAddressMatch(addresses, publicKey) {
const pubKeyHash = crypto.createHash('ripemd160')
.update(crypto.createHash('sha256').update(publicKey).digest())
.digest();
const versionedPubKeyHash = Buffer.concat([Buffer.from([0x00]), pubKeyHash]);
const hexPubKeyHash = versionedPubKeyHash.toString('hex');
return addresses.find(address => address === hexPubKeyHash); // Check if any address matches
}
for (const privateKey of generatePrivateKey(currentStart, BigInt(end))) {
if (keysChecked % Number(batchSize) === 0) {
parentPort.postMessage({
type: 'progress',
workerId,
rangeStart: currentStart.toString(16).padStart(64, '0'),
rangeEnd: (currentStart + BigInt(batchSize) - 1n).toString(16).padStart(64, '0'),
keysChecked,
range: range
});
}
try {
ec.setPrivateKey(privateKey);
const publicKey = ec.getPublicKey('hex', 'compressed');
const matchedAddress = checkAddressMatch(addresses, Buffer.from(publicKey, 'hex'));
if (matchedAddress) {
parentPort.postMessage({
type: 'match',
address: matchedAddress,
privateKey: privateKey.toString('hex'),
});
return; // Exit the loop if a match is found
}
} catch (error) {
console.error(`Error processing key for worker ${workerId}:`, error.message);
}
keysChecked++;
currentStart++;
}
}