fork download
  1. const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
  2. const crypto = require('crypto');
  3. const fs = require('fs');
  4. const path = require('path');
  5.  
  6. const CHECKPOINT_DIR = './checkpoints';
  7. const RESULTS_DIR = './results';
  8.  
  9. function* generatePrivateKey(start, end) {
  10. let privateKey = start;
  11. while (privateKey <= end) {
  12. const hexString = privateKey.toString(16).padStart(64, '0');
  13. yield Buffer.from(hexString, 'hex');
  14. privateKey = privateKey + 1n;
  15. }
  16. }
  17.  
  18. if (isMainThread) {
  19. const readline = require('readline');
  20. const rl = readline.createInterface({
  21. input: process.stdin,
  22. output: process.stdout
  23. });
  24.  
  25. const addresses = [];
  26. let foundAddresses = new Set();
  27.  
  28. function askForAddress() {
  29. rl.question('Enter a Bitcoin address to brute force (or press Enter to start): ', (address) => {
  30. if (address.trim()) {
  31. addresses.push(address);
  32. askForAddress(); // Ask for another address if one was entered
  33. } else {
  34. if (addresses.length === 0) {
  35. console.log('Please enter at least one Bitcoin address.');
  36. askForAddress();
  37. } else {
  38. askStartMethod();
  39. }
  40. }
  41. });
  42. }
  43.  
  44. function askStartMethod() {
  45. rl.question('Start fresh or resume from checkpoint? (fresh/resume/clear): ', (answer) => {
  46. answer = answer.toLowerCase();
  47. if (answer === 'fresh') {
  48. clearCheckpoints();
  49. startBruteForce(Array(16).fill(BigInt(0)));
  50. } else if (answer === 'resume') {
  51. loadCheckpoints();
  52. } else if (answer === 'clear') {
  53. clearCheckpoints();
  54. console.log('Checkpoints cleared. Starting fresh...');
  55. startBruteForce(Array(16).fill(BigInt(0)));
  56. } else {
  57. console.log('Invalid option. Please choose "fresh", "resume", or "clear".');
  58. askStartMethod();
  59. }
  60. });
  61. }
  62.  
  63. function loadCheckpoints() {
  64. const maxKey = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
  65. const lastCheckpoints = Array(16).fill(BigInt(0));
  66.  
  67. for (let i = 0; i < 16; i++) {
  68. try {
  69. const checkpointData = fs.readFileSync(path.join(CHECKPOINT_DIR, `worker_${i}.json`), 'utf8');
  70. const { lastKey } = JSON.parse(checkpointData);
  71. lastCheckpoints[i] = BigInt('0x' + lastKey);
  72. console.log(`Worker ${i}: Resuming from checkpoint: ${lastKey}`);
  73. } catch (e) {
  74. console.error(`Worker ${i}: Error reading or parsing checkpoint:`, e.message);
  75. console.log(`Worker ${i}: No valid checkpoint found, starting from 0.`);
  76. }
  77. }
  78. startBruteForce(lastCheckpoints);
  79. }
  80.  
  81. function clearCheckpoints() {
  82. try {
  83. fs.rmSync(CHECKPOINT_DIR, { recursive: true, force: true });
  84. fs.mkdirSync(CHECKPOINT_DIR);
  85. console.log('All checkpoint files have been deleted and directory recreated.');
  86. } catch (error) {
  87. console.log('Error clearing checkpoints:', error.message);
  88. }
  89. }
  90.  
  91. function startBruteForce(lastCheckpoints) {
  92. const numWorkers = 16;
  93. const maxKey = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
  94.  
  95. const workerRanges = [
  96. { start: 10, end: 6, id: 1 }, // Worker 1
  97. { start: 5, end: 1, id: 2 }, // Worker 2
  98. { start: 11, end: 15, id: 3 }, // Worker 3
  99. { start: 16, end: 20, id: 4 }, // Worker 4
  100. { start: 30, end: 26, id: 5 }, // Worker 5
  101. { start: 25, end: 21, id: 6 }, // Worker 6
  102. { start: 50, end: 46, id: 7 }, // Worker 7
  103. { start: 45, end: 41, id: 8 }, // Worker 8
  104. { start: 40, end: 36, id: 9 }, // Worker 9
  105. { start: 35, end: 31, id: 10 }, // Worker 10
  106. { start: 51, end: 55, id: 11 }, // Worker 11
  107. { start: 56, end: 60, id: 12 }, // Worker 12
  108. { start: 61, end: 65, id: 13 }, // Worker 13
  109. { start: 66, end: 76, id: 14 }, // Worker 14
  110. { start: 77, end: 87, id: 15 }, // Worker 15
  111. { start: 88, end: 100, id: 16 } // Worker 16
  112. ];
  113.  
  114. let workers = [];
  115.  
  116. for (let i = 0; i < numWorkers; i++) {
  117. const range = workerRanges[i];
  118. const start = BigInt(Math.floor(Number(maxKey) * (range.start / 100))) + (lastCheckpoints[i] || BigInt(0));
  119. const end = BigInt(Math.floor(Number(maxKey) * (range.end / 100))) + (lastCheckpoints[i] || BigInt(0)) - 1n;
  120.  
  121. const worker = new Worker(__filename, {
  122. workerData: { addresses, workerId: i, start: start.toString(), end: end.toString(), batchSize: "10000", range }
  123. });
  124.  
  125. workers.push(worker);
  126. worker.on('message', (message) => {
  127. if (message.type === 'match') {
  128. console.log(`Match found for ${message.address} by Worker ${message.workerId}`);
  129. console.log('Private Key:', message.privateKey);
  130. saveMatch(message.address, message.privateKey);
  131. foundAddresses.add(message.address);
  132. if (foundAddresses.size === addresses.length) {
  133. console.log('All addresses matched. Stopping workers...');
  134. workers.forEach(w => w.terminate());
  135. }
  136. } else if (message.type === 'progress') {
  137. console.log(`Worker ${message.workerId}: Range ${message.range.start}% to ${message.range.end}% (${message.rangeStart} to ${message.rangeEnd}), Tried ${message.keysChecked} keys...`);
  138. }
  139.  
  140. try {
  141. fs.mkdirSync(CHECKPOINT_DIR, { recursive: true });
  142. fs.writeFileSync(path.join(CHECKPOINT_DIR, `worker_${message.workerId}.json`), JSON.stringify({ lastKey: message.rangeEnd }));
  143. } catch (writeErr) {
  144. console.error(`Failed to save checkpoint for Worker ${message.workerId}:`, writeErr.message);
  145. }
  146. });
  147.  
  148. // Initial log of worker ranges
  149. console.log(`Worker ${range.id}: Will check key range ${range.start}% to ${range.end}%`);
  150. }
  151.  
  152. process.on('SIGINT', () => {
  153. workers.forEach(w => w.terminate());
  154. process.exit();
  155. });
  156. }
  157.  
  158. function saveMatch(address, privateKey) {
  159. fs.mkdirSync(RESULTS_DIR, { recursive: true });
  160. const fileName = `${RESULTS_DIR}/${address}.txt`;
  161. fs.writeFileSync(fileName, `Address: ${address}\nPrivate Key: ${privateKey}`);
  162. console.log(`Match saved to ${fileName}`);
  163. }
  164.  
  165. askForAddress();
  166. } else {
  167. const { addresses, workerId, start, end, batchSize, range } = workerData;
  168. const ec = crypto.createECDH('secp256k1');
  169. let keysChecked = 0;
  170. let currentStart = BigInt(start);
  171.  
  172. function checkAddressMatch(addresses, publicKey) {
  173. const pubKeyHash = crypto.createHash('ripemd160')
  174. .update(crypto.createHash('sha256').update(publicKey).digest())
  175. .digest();
  176. const versionedPubKeyHash = Buffer.concat([Buffer.from([0x00]), pubKeyHash]);
  177. const hexPubKeyHash = versionedPubKeyHash.toString('hex');
  178. return addresses.find(address => address === hexPubKeyHash); // Check if any address matches
  179. }
  180.  
  181. for (const privateKey of generatePrivateKey(currentStart, BigInt(end))) {
  182. if (keysChecked % Number(batchSize) === 0) {
  183. parentPort.postMessage({
  184. type: 'progress',
  185. workerId,
  186. rangeStart: currentStart.toString(16).padStart(64, '0'),
  187. rangeEnd: (currentStart + BigInt(batchSize) - 1n).toString(16).padStart(64, '0'),
  188. keysChecked,
  189. range: range
  190. });
  191. }
  192. try {
  193. ec.setPrivateKey(privateKey);
  194. const publicKey = ec.getPublicKey('hex', 'compressed');
  195. const matchedAddress = checkAddressMatch(addresses, Buffer.from(publicKey, 'hex'));
  196. if (matchedAddress) {
  197. parentPort.postMessage({
  198. type: 'match',
  199. address: matchedAddress,
  200. privateKey: privateKey.toString('hex'),
  201. });
  202. return; // Exit the loop if a match is found
  203. }
  204. } catch (error) {
  205. console.error(`Error processing key for worker ${workerId}:`, error.message);
  206. }
  207. keysChecked++;
  208. currentStart++;
  209. }
  210. }
Success #stdin #stdout 0.1s 38140KB
stdin
Standard input is empty
stdout
Enter a Bitcoin address to brute force (or press Enter to start):