Bitcoin Forum
August 03, 2025, 10:15:47 AM *
News: Latest Bitcoin Core release: 29.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 ... 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 [422] 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 ... 568 »
  Print  
Author Topic: Bitcoin puzzle transaction ~32 BTC prize to who solves it  (Read 325035 times)
Denevron
Newbie
*
Offline Offline

Activity: 112
Merit: 0


View Profile
March 30, 2025, 08:24:36 PM
 #8421

I understand that I need to do it myself, but still, thank you very much for the prototype)

256-bit version with BIGNUM:

Code:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <thread>
#include <atomic>
#include <chrono>
#include <queue>
#include <mutex>
#include <unordered_map>
#include <cmath>
#include <fstream>
#include <openssl/ec.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/obj_mac.h>
#include <openssl/evp.h>

using namespace std;

// Configuration
const string TARGET_HASH160 = "b907c3a2a3b27789dfb509b730dd47703c272868";
const string BASE_KEY = "000000000000000000000000000000000000000000000000000000000005749f";
const int PUZZLE_NUM = 20;
const int WORKERS = thread::hardware_concurrency();

// Historical flip counts
const unordered_map<int, int> FLIP_TABLE = {
    {20, 8}, {21, 9}, {22, 11}, {23, 12}, {24, 9}, {25, 12}, {26, 14}, {27, 13},
    {28, 16}, {29, 18}, {30, 16}, {31, 13}, {32, 14}, {33, 15}, {34, 16}, {35, 19},
    {36, 14}, {37, 23}, {38, 21}, {39, 23}, {40, 20}, {41, 25}, {42, 24}, {43, 19},
    {44, 24}, {45, 21}, {46, 24}, {47, 27}, {48, 21}, {49, 30}, {50, 29}, {51, 25},
    {52, 27}, {53, 26}, {54, 30}, {55, 31}, {56, 31}, {57, 33}, {58, 28}, {59, 30},
    {60, 31}, {61, 25}, {62, 35}, {63, 34}, {64, 34}, {65, 37}, {66, 35}, {67, 31},
    {68, 34}
};

// Global variables
atomic<bool> stop_event(false);
mutex result_mutex;
queue<tuple<string, size_t, int>> results;

// Predict flip count
int predict_flips(int puzzle_num) {
    if (FLIP_TABLE.count(puzzle_num)) {
        return FLIP_TABLE.at(puzzle_num);
    }
    return 8; // Default
}

// Binomial coefficient
size_t combinations_count(int n, int k) {
    if (k > n) return 0;
    if (k * 2 > n) k = n - k;
    if (k == 0) return 1;

    size_t result = n;
    for(int i = 2; i <= k; ++i) {
        result *= (n - i + 1);
        result /= i;
    }
    return result;
}

// Generate combinations
vector<vector<int>> generate_combinations(int n, int k) {
    vector<vector<int>> combinations;
    vector<int> current(k, 0);
    for (int i = 0; i < k; ++i) current[i] = i;

    while (true) {
        combinations.push_back(current);

        int i = k - 1;
        while (i >= 0 && current[i] == n - k + i) --i;
        if (i < 0) break;

        ++current[i];
        for (int j = i + 1; j < k; ++j) current[j] = current[j - 1] + 1;
    }
    return combinations;
}

// Convert BIGNUM to hex string
string bn_to_hex(const BIGNUM* bn) {
    char* hex = BN_bn2hex(bn);
    string result(hex);
    OPENSSL_free(hex);
    return result;
}

// XOR operation for BIGNUM
void bn_xor(BIGNUM* result, const BIGNUM* a, const BIGNUM* b) {
    BIGNUM* tmp = BN_new();
    BN_copy(result, a);
    
    for (int i = 0; i < max(BN_num_bits(a), BN_num_bits(b)); ++i) {
        if (BN_is_bit_set(a, i) != BN_is_bit_set(b, i)) {
            BN_set_bit(result, i);
        } else {
            BN_clear_bit(result, i);
        }
    }
    
    BN_free(tmp);
}

// Compute HASH160 from BIGNUM private key
string compute_hash160(const BIGNUM* priv_key) {
    EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (!ec_key) return "";

    if (!EC_KEY_set_private_key(ec_key, priv_key)) {
        EC_KEY_free(ec_key);
        return "";
    }

    const EC_GROUP* group = EC_KEY_get0_group(ec_key);
    EC_POINT* pub_key = EC_POINT_new(group);
    if (!pub_key) {
        EC_KEY_free(ec_key);
        return "";
    }

    if (!EC_POINT_mul(group, pub_key, priv_key, nullptr, nullptr, nullptr)) {
        EC_POINT_free(pub_key);
        EC_KEY_free(ec_key);
        return "";
    }

    unsigned char pubkey[65];
    int pubkey_len = EC_POINT_point2oct(group, pub_key, POINT_CONVERSION_COMPRESSED, pubkey, sizeof(pubkey), nullptr);
    EC_POINT_free(pub_key);
    EC_KEY_free(ec_key);

    if (pubkey_len != 33) return "";

    unsigned char sha256[SHA256_DIGEST_LENGTH];
    SHA256(pubkey, pubkey_len, sha256);

    unsigned char ripemd160[RIPEMD160_DIGEST_LENGTH];
    RIPEMD160(sha256, SHA256_DIGEST_LENGTH, ripemd160);

    stringstream ss;
    for (int i = 0; i < RIPEMD160_DIGEST_LENGTH; ++i) {
        ss << hex << setw(2) << setfill('0') << (int)ripemd160[i];
    }
    return ss.str();
}

// Worker function
void worker(const BIGNUM* base_bn, int bit_length, int flip_count, size_t start_index, size_t end_index) {
    vector<vector<int>> combinations = generate_combinations(bit_length, flip_count);
    BIGNUM* current_bn = BN_new();
    BIGNUM* flip_mask = BN_new();

    for (size_t i = start_index; i < end_index && !stop_event.load(); ++i) {
        BN_zero(flip_mask);
        for (int pos : combinations[i]) {
            BN_set_bit(flip_mask, pos);
        }
        
        bn_xor(current_bn, base_bn, flip_mask);

        string hash160 = compute_hash160(current_bn);
        if (hash160 == TARGET_HASH160) {
            string hex_key = bn_to_hex(current_bn);
            lock_guard<mutex> lock(result_mutex);
            results.push(make_tuple(hex_key, i+1, flip_count));
            stop_event.store(true);
            break;
        }

        if ((i+1) % 10000 == 0) {
            cout << "Checked " << (i+1) << " combinations\r";
            cout.flush();
        }
    }

    BN_free(current_bn);
    BN_free(flip_mask);
}

// Parallel search
void parallel_search() {
    BIGNUM* base_bn = BN_new();
    BN_hex2bn(&base_bn, BASE_KEY.c_str());

    int flip_count = predict_flips(PUZZLE_NUM);
    size_t total_combs = combinations_count(PUZZLE_NUM, flip_count);

    cout << "Searching Puzzle " << PUZZLE_NUM << " (256-bit)" << endl;
    cout << "Base Key: " << BASE_KEY << endl;
    cout << "Target HASH160: " << TARGET_HASH160 << endl;
    cout << "Predicted Flip Count: " << flip_count << " bits" << endl;
    cout << "Total Possible Combinations: " << total_combs << endl;
    cout << "Using " << WORKERS << " workers..." << endl;

    vector<thread> threads;
    size_t chunk_size = total_combs / WORKERS;
    auto start_time = chrono::high_resolution_clock::now();

    for (int i = 0; i < WORKERS; ++i) {
        size_t start = i * chunk_size;
        size_t end = (i == WORKERS-1) ? total_combs : start + chunk_size;
        threads.emplace_back(worker, base_bn, PUZZLE_NUM, flip_count, start, end);
    }

    for (auto& t : threads) t.join();
    BN_free(base_bn);

    if (!results.empty()) {
        auto [hex_key, checked, flips] = results.front();
        auto elapsed = chrono::duration_cast<chrono::seconds>(
            chrono::high_resolution_clock::now() - start_time).count();

        cout << "\nFound solution!" << endl;
        cout << "Private Key: " << hex_key << endl;
        cout << "Bit Flips: " << flips << endl;
        cout << "Checked " << checked << " combinations in "
             << elapsed << " seconds (" << (checked/elapsed) << " keys/sec)" << endl;

        ofstream out("solution.txt");
        out << hex_key;
        out.close();
    } else {
        cout << "\nSolution not found. Try adjusting flip count." << endl;
    }
}

int main() {
    #if OPENSSL_VERSION_NUMBER < 0x10100000L
    OpenSSL_add_all_algorithms();
    #endif

    parallel_search();

    #if OPENSSL_VERSION_NUMBER < 0x10100000L
    EVP_cleanup();
    #endif

    return 0;
}


Quote
# ./mutagen
Searching Puzzle 68 (256-bit)
Base Key: 00000000000000000000000000000000000000000000000730fc235c1942c1ae
Target HASH160: e0b8a2baee1b77fc703455f39d51477451fc8cfc
Predicted Flip Count: 34 bits
Total Possible Combinations: 47478523248093572
Using 12 workers...


Good luck searching through 47 quadrillion combinations. Grin


In Puzzle 68, the source code causes a ram usage of 100% and it can also cause a system crash

because this is a code example, it is not a fully functional program) to avoid this, you don't just need to generate all the options at once) there is still a lot of work to do)
Denevron
Newbie
*
Offline Offline

Activity: 112
Merit: 0


View Profile
March 30, 2025, 08:39:01 PM
 #8422

The program is on my github, it is at the initial stage of development)
There is also a Python version there.

https://github.com/MikeWazovksy/Mutagen

Thank you for your help @nomachine
kTimesG
Full Member
***
Offline Offline

Activity: 546
Merit: 166


View Profile
March 30, 2025, 10:36:15 PM
 #8423

deep seek comments for cyclone:

Expected Performance:
Optimization   Speed Multiplier
Base AVX2   1x
AVX-512   2x
GPU Acceleration   1000x
Precomputation   10x
Memory Optimization   1.5x
Assembly Tuning   1.2x
Total Potential   36,000x

For maximum speed, focus first on GPU implementation (biggest gain) while maintaining the AVX2 path as fallback. The combination of all optimizations can theoretically achieve over 30,000x speed improvement over the original single-threaded version.

Loads of bullshit. That's not how things work in the GPU world, buddy.

GPU acceleration is already tuned to maximum performance, and there are very little things that can be tweaked to make it a little bit faster than the current records (~7 GH / Joule, or ~7 GH/s/Watt, however you wanna look at it). And even so, it is already hundreds of times faster than any CPU you can think of, or hundreds of times more efficient, again however you wanna look at it.

CPU bullshits like AVX, SSE, memory whatever crap, assembler optimizations - these DO NOT EXIST when programming for a GPU. There are VERY VERY different problems to work with, when building a GPU kernel / app.

All the optimizations for Cyclone in the last 20 pages of this forum are just to make a very inefficient CPU software work a little less painfully slower, for people that are living in a lie ("I can't afford a GPU, but I prefer to fry my motherboard instead of renting on vast.ai and compute tons of hashes more than the ones my PC can produce, at the same price"), that's all. The Cyclone hype  DOES NOT APPLY AT ALL to GPU acceleration, no matter what deepseek or ChatGPT nonsense BS may lead you to believe.

I am astonished by how people continue to believe that adding all sorts of slowdowns actually think would makes things faster. Probabilities, skips, jumps, random selections, combinations, bit flips, base58 voodoos - guys, the slightest attempt to use ANY of these stuff just creates GAPS and SLOWDOWNS in the processing pipeline, so the performance gain factor is somewhere between zero and one (e.g. - your expected time to solve multiplies, not shortens). The net result is a loss of hash time and loss of precious computing cycles. There is no mathematical proof about any magical method to shorten a brute force attempt on a uniform distribution, so anything that interferes with the actual search process is just a guaranteed way to find the key much later rather than much sooner.

Off the grid, training pigeons to broadcast signed messages.
AlanJohnson
Member
**
Offline Offline

Activity: 185
Merit: 11


View Profile
March 31, 2025, 05:45:43 AM
 #8424

All the optimizations for Cyclone in the last 20 pages of this forum are just to make a very inefficient CPU software work a little less painfully slower, for people that are living in a lie ("I can't afford a GPU, but I prefer to fry my motherboard instead of renting on vast.ai and compute tons of hashes more than the ones my PC can produce, at the same price"), that's all. The Cyclone hype  DOES NOT APPLY AT ALL to GPU acceleration, no matter what deepseek or ChatGPT nonsense BS may lead you to believe.

I am astonished by how people continue to believe that adding all sorts of slowdowns actually think would makes things faster. Probabilities, skips, jumps, random selections, combinations, bit flips, base58 voodoos - guys, the slightest attempt to use ANY of these stuff just creates GAPS and SLOWDOWNS in the processing pipeline, so the performance gain factor is somewhere between zero and one (e.g. - your expected time to solve multiplies, not shortens). The net result is a loss of hash time and loss of precious computing cycles. There is no mathematical proof about any magical method to shorten a brute force attempt on a uniform distribution, so anything that interferes with the actual search process is just a guaranteed way to find the key much later rather than much sooner.

But this is how the things are going on this forum...

At this point we need a MASSIVE computing power to resolve any of the remaining puzzles.  If anybody counts on "luck" and "what if"  - trying to search on  home desktop  it doesn't really matter what program are you using (cyclone, keyhunt, bitcrack or some random python script) cause your chances are so small that being a bit faster or slower doesn't change anything.

It would be better to make a an app for smartphone that uses ONLY ONE core (to not drain battery or overheat too much) to search for a puzzles and make millions of people all over the world installing it.  I guess it could be solved pretty quick then.  But from the other hand i doubt there is so many people interested in this madness.
nomachine
Full Member
***
Offline Offline

Activity: 714
Merit: 110


View Profile
March 31, 2025, 05:45:56 AM
 #8425

Probabilities, skips, jumps, random selections, combinations, bit flips, base58 voodoos - guys

People need something to do in their free time if they have it to spare.
It's better than doing drugs, joining a local gang, or staring at their phones, waging troll wars to ruin others' smiles out of pure spite.   Grin


The program is on my github, it is at the initial stage of development)
There is also a Python version there.

https://github.com/MikeWazovksy/Mutagen

Thank you for your help @nomachine


Code:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>
#include <thread>
#include <atomic>
#include <chrono>
#include <queue>
#include <mutex>
#include <cstring>
#include <unordered_map>
#include <cmath>
#include <openssl/ec.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/obj_mac.h>
#include <openssl/evp.h>

using namespace std;

// Configuration
const string TARGET_HASH160 = "b907c3a2a3b27789dfb509b730dd47703c272868";
const string BASE_KEY = "000000000000000000000000000000000000000000000000000000000005749f";
const int PUZZLE_NUM = 20;
const int WORKERS = thread::hardware_concurrency();
const size_t REPORT_INTERVAL = 10000;

// Historical flip counts
const unordered_map<int, int> FLIP_TABLE = {
     {20, 8},   {21, 9},  {22, 11}, {23, 12},  {24, 9},  {25, 12}, {26, 14}, {27, 13},
    {28, 16}, {29, 18}, {30, 16}, {31, 13}, {32, 14}, {33, 15}, {34, 16}, {35, 19},
    {36, 14}, {37, 23}, {38, 21}, {39, 23}, {40, 20}, {41, 25}, {42, 24}, {43, 19},
    {44, 24}, {45, 21}, {46, 24}, {47, 27}, {48, 21}, {49, 30}, {50, 29}, {51, 25},
    {52, 27}, {53, 26}, {54, 30}, {55, 31}, {56, 31}, {57, 33}, {58, 28}, {59, 30},
    {60, 31}, {61, 25}, {62, 35}, {63, 34}, {64, 34}, {65, 37}, {66, 35}, {67, 31},
    {68, 34}
};

// Global variables
vector<unsigned char> TARGET_HASH160_RAW(20);
atomic<bool> stop_event(false);
mutex result_mutex;
queue<tuple<string, size_t, int>> results;
atomic<size_t> total_checked(0);
size_t total_combinations = 0;

// Convert hex string to raw bytes
vector<unsigned char> hex_to_bytes(const string& hex) {
    vector<unsigned char> bytes;
    for (size_t i = 0; i < hex.length(); i += 2) {
        string byteString = hex.substr(i, 2);
        unsigned char byte = static_cast<unsigned char>(strtoul(byteString.c_str(), nullptr, 16));
        bytes.push_back(byte);
    }
    return bytes;
}

// Get only the last n bits of a BIGNUM
BIGNUM* get_last_n_bits(BIGNUM* num, int n) {
    BIGNUM* result = BN_new();
    BN_zero(result);
    
    for (int i = 0; i < n; ++i) {
        if (BN_is_bit_set(num, i)) {
            BN_set_bit(result, i);
        }
    }
    return result;
}

// Predict flip count
int predict_flips(int puzzle_num) {
    if (FLIP_TABLE.count(puzzle_num)) {
        return FLIP_TABLE.at(puzzle_num);
    }
    return 34; // Default for puzzle 68
}

// Binomial coefficient calculation
size_t combinations_count(int n, int k) {
    if (k > n) return 0;
    if (k * 2 > n) k = n - k;
    if (k == 0) return 1;

    size_t result = n;
    for(int i = 2; i <= k; ++i) {
        result *= (n - i + 1);
        result /= i;
    }
    return result;
}

// Memory-efficient combination generator
class CombinationGenerator {
    int n, k;
    vector<int> current;
public:
    CombinationGenerator(int n, int k) : n(n), k(k), current(k) {
        for (int i = 0; i < k; ++i) current[i] = i;
    }
  
    bool next() {
        int i = k - 1;
        while (i >= 0 && current[i] == n - k + i) --i;
        if (i < 0) return false;
      
        ++current[i];
        for (int j = i + 1; j < k; ++j)
            current[j] = current[j-1] + 1;
        return true;
    }
  
    const vector<int>& get() const { return current; }
};

// Fast BIGNUM XOR for n bits
void bn_xor_nbits(BIGNUM* r, const BIGNUM* a, const BIGNUM* b, int n) {
    BN_copy(r, a);
    for (int i = 0; i < n; ++i) {
        if (BN_is_bit_set(a, i) != BN_is_bit_set(b, i))
            BN_set_bit(r, i);
        else
            BN_clear_bit(r, i);
    }
}

// Worker function
void worker(BIGNUM* base_bn, int bit_length, int flip_count, size_t start, size_t end) {
    // One-time allocations
    BIGNUM* trimmed_base = get_last_n_bits(base_bn, bit_length);
    BIGNUM* current = BN_new();
    BIGNUM* mask = BN_new();
    EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1);
    const EC_GROUP* group = EC_KEY_get0_group(key);
    EC_POINT* pub = EC_POINT_new(group);
    unsigned char pubkey[33];
    unsigned char sha256[SHA256_DIGEST_LENGTH];
    unsigned char ripemd160[RIPEMD160_DIGEST_LENGTH];
    
    CombinationGenerator gen(bit_length, flip_count);
    for (size_t i = 0; i < start && gen.next(); ++i);

    size_t count = 0;
    do {
        // 1. Build mask
        BN_zero(mask);
        for (int pos : gen.get()) BN_set_bit(mask, pos);

        // 2. XOR operation
        bn_xor_nbits(current, trimmed_base, mask, bit_length);

        // 3. Set private key
        if (!EC_KEY_set_private_key(key, current)) continue;

        // 4. Generate public key
        if (!EC_POINT_mul(group, pub, current, nullptr, nullptr, nullptr)) continue;

        // 5. Get compressed pubkey
        if (EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED, pubkey, 33, nullptr) != 33) continue;

        // 6. Compute hashes
        SHA256(pubkey, 33, sha256);
        RIPEMD160(sha256, SHA256_DIGEST_LENGTH, ripemd160);

        // 7. Compare raw bytes
        if (memcmp(ripemd160, TARGET_HASH160_RAW.data(), 20) == 0) {
            char* hex_key = BN_bn2hex(current);
            lock_guard<mutex> lock(result_mutex);
            results.push(make_tuple(hex_key, total_checked.load(), flip_count));
            OPENSSL_free(hex_key);
            stop_event.store(true);
            break;
        }

        if (++total_checked % REPORT_INTERVAL == 0) {
            double progress = (double)total_checked / total_combinations * 100;
            cout << "Progress: " << fixed << setprecision(6) << progress << "% (";
            cout << total_checked << "/" << total_combinations << ")\r";
            cout.flush();
        }
          
    } while (gen.next() && (count++ < (end-start)) && !stop_event.load());

    // Cleanup
    EC_POINT_free(pub);
    EC_KEY_free(key);
    BN_free(mask);
    BN_free(current);
    BN_free(trimmed_base);
}

int main() {
    // Convert target hash to raw bytes
    TARGET_HASH160_RAW = hex_to_bytes(TARGET_HASH160);

    cout << "=======================================\n";
    cout << "== Mutagen Puzzle Solver by Denevron ==\n";
    cout << "=======================================\n";
  
    BIGNUM* base_bn = BN_new();
    BN_hex2bn(&base_bn, BASE_KEY.c_str());
  
    const int bit_length = PUZZLE_NUM;
    const int flip_count = predict_flips(PUZZLE_NUM);
    total_combinations = combinations_count(bit_length, flip_count);
  
    cout << "Searching Puzzle " << PUZZLE_NUM << " (" << bit_length << "-bit)\n";
    cout << "Base Key: " << BASE_KEY.substr(0, 10) << "..." << BASE_KEY.substr(BASE_KEY.length()-10) << "\n";
    cout << "Target HASH160: " << TARGET_HASH160.substr(0, 10) << "..." << TARGET_HASH160.substr(TARGET_HASH160.length()-10) << "\n";
    cout << "Predicted Flip Count: " << flip_count << " bits\n";
    cout << "Total Combinations: " << total_combinations << "\n";
    cout << "Using " << WORKERS << " workers...\n";
  
    auto start_time = chrono::high_resolution_clock::now();
    vector<thread> threads;
    size_t chunk = total_combinations / WORKERS;
  
    for (int i = 0; i < WORKERS; ++i) {
        size_t start = i * chunk;
        size_t end = (i == WORKERS-1) ? total_combinations : start + chunk;
        threads.emplace_back(worker, base_bn, bit_length, flip_count, start, end);
    }
  
    for (auto& t : threads) t.join();
    BN_free(base_bn);
  
    if (!results.empty()) {
        auto [hex_key, checked, flips] = results.front();
        auto elapsed = chrono::duration_cast<chrono::seconds>(
            chrono::high_resolution_clock::now() - start_time).count();
      
        cout << "\n=======================================\n";
        cout << "=========== SOLUTION FOUND ============\n";
        cout << "=======================================\n";
        cout << "Private Key: " << hex_key << "\n";
        cout << "Search Time: " << elapsed << " seconds\n";
        cout << "Keys Checked: " << checked << "\n";
        cout << "Bit Flips: " << flips << endl;
      
        ofstream out("puzzle_" + to_string(PUZZLE_NUM) + "_solution.txt");
        out << hex_key;
        out.close();
        cout << "Solution saved to puzzle_" << PUZZLE_NUM << "_solution.txt\n";
    } else {
        cout << "\nSolution not found. Checked " << total_checked << " combinations\n";
    }
  
    return 0;
}


Quote
# ./mutagen
=======================================
== Mutagen Puzzle Solver by Denevron ==
=======================================
Searching Puzzle 20 (20-bit)
Base Key: 0000000000...000005749f
Target HASH160: b907c3a2a3...703c272868
Predicted Flip Count: 8 bits
Total Combinations: 125970
Using 12 workers...
Progress: 47.630388% (60000/125970)
=======================================
=========== SOLUTION FOUND ============
=======================================
Private Key: 0D2C55
Search Time: 3 seconds
Keys Checked: 63547
Bit Flips: 8
Solution saved to puzzle_20_solution.txt


And so on, it can be improved infinitely. But the main question here is the number of possible combinations, which grow exponentially.

But we love useless scripts—I’m even a collector  Grin

BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
AlanJohnson
Member
**
Offline Offline

Activity: 185
Merit: 11


View Profile
March 31, 2025, 05:56:15 AM
 #8426


People need something to do in their free time if they have it to spare.
It's better than doing drugs, joining a local gang, or staring at their phones, waging troll wars to ruin others' smiles out of pure spite.   Grin


But when they finally realize they were throwed into delusion and it was a waste of time and electricity (or maybe money spent on hardware that they don't really need) the can start : "doing drugs, joining a local gang, or staring at their phones, waging troll wars to ruin others' smiles out of pure spite."  Roll Eyes
nomachine
Full Member
***
Offline Offline

Activity: 714
Merit: 110


View Profile
March 31, 2025, 06:04:18 AM
 #8427

But when they finally realize they were throwed into delusion ....

I go fishing when I reach that stage, without a phone or internet. When I forget everything, I sit down at the PC again. In between, I grill fish or read books.   Wink

BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
AlanJohnson
Member
**
Offline Offline

Activity: 185
Merit: 11


View Profile
March 31, 2025, 06:08:13 AM
 #8428

But when they finally realize they were throwed into delusion ....

I go fishing when I reach that stage, without a phone or internet. When I forget everything, I sit down at the PC again. In between, I grill fish or read books.   Wink

That's the right attitude !

 But i guess some people expect they have big chance to win in this lottery and  this is their chance to improve life financially ... i guess they can be very dissapointed at some point.
nomachine
Full Member
***
Offline Offline

Activity: 714
Merit: 110


View Profile
March 31, 2025, 06:16:41 AM
 #8429

But when they finally realize they were throwed into delusion ....

I go fishing when I reach that stage, without a phone or internet. When I forget everything, I sit down at the PC again. In between, I grill fish or read books.   Wink

That's the right attitude !

 But i guess some people expect they have big chance to win in this lottery and  this is their chance to improve life financially ... i guess they can be very dissapointed at some point.

Yeah, but if you don't participate in the lottery, you can't win.
I have no illusions—this is an impossible mission. I'm just here for fun because I don't need wealth. I've been relatively rich and gone bankrupt several times. There is no amount of money that can't be gambled away or spent.

BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
Akito S. M. Hosana
Jr. Member
*
Offline Offline

Activity: 364
Merit: 8


View Profile
March 31, 2025, 06:26:10 AM
Last edit: March 31, 2025, 08:17:17 AM by Akito S. M. Hosana
 #8430

Yeah, but if you don't participate in the lottery, you can't win.

You can't even lose if you don't participate.

I've been relatively rich and gone bankrupt several times. There is no amount of money that can't be gambled away or spent.

I've been broke all my life and have nothing to stake.  Tongue


But we love useless scripts—I’m even a collector  Grin

Can you add a random generator to CombinationGenerator with the unrank algorithm? I have a feeling that the whole puzzle is generated this way. If only you could reset the random seed to 2015.  Grin
nomachine
Full Member
***
Offline Offline

Activity: 714
Merit: 110


View Profile
March 31, 2025, 08:59:11 AM
 #8431

CombinationGenerator with the unrank algorithm?

I'll do that too, but don't ask me tomorrow for the 'stride' option, searching for a prefix by length, or for the script to output the moon phases during the day  Smiley

BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
AlanJohnson
Member
**
Offline Offline

Activity: 185
Merit: 11


View Profile
March 31, 2025, 09:19:55 AM
 #8432

For all who wants to face the truth i made that simple page:

http://jastrzeblu.cluster021.hosting.ovh.net/

It estimates the time to solve the puzzle blindly checking private keys... just enter your speed and select a puzzle...

(It does not calculate for BSGS or Kangaroo of course)

Denevron
Newbie
*
Offline Offline

Activity: 112
Merit: 0


View Profile
March 31, 2025, 11:17:37 AM
 #8433

Probabilities, skips, jumps, random selections, combinations, bit flips, base58 voodoos - guys

People need something to do in their free time if they have it to spare.
It's better than doing drugs, joining a local gang, or staring at their phones, waging troll wars to ruin others' smiles out of pure spite.   Grin


The program is on my github, it is at the initial stage of development)
There is also a Python version there.

https://github.com/MikeWazovksy/Mutagen

Thank you for your help @nomachine


Code:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <vector>
#include <thread>
#include <atomic>
#include <chrono>
#include <queue>
#include <mutex>
#include <cstring>
#include <unordered_map>
#include <cmath>
#include <openssl/ec.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/obj_mac.h>
#include <openssl/evp.h>

using namespace std;

// Configuration
const string TARGET_HASH160 = "b907c3a2a3b27789dfb509b730dd47703c272868";
const string BASE_KEY = "000000000000000000000000000000000000000000000000000000000005749f";
const int PUZZLE_NUM = 20;
const int WORKERS = thread::hardware_concurrency();
const size_t REPORT_INTERVAL = 10000;

// Historical flip counts
const unordered_map<int, int> FLIP_TABLE = {
     {20, 8},   {21, 9},  {22, 11}, {23, 12},  {24, 9},  {25, 12}, {26, 14}, {27, 13},
    {28, 16}, {29, 18}, {30, 16}, {31, 13}, {32, 14}, {33, 15}, {34, 16}, {35, 19},
    {36, 14}, {37, 23}, {38, 21}, {39, 23}, {40, 20}, {41, 25}, {42, 24}, {43, 19},
    {44, 24}, {45, 21}, {46, 24}, {47, 27}, {48, 21}, {49, 30}, {50, 29}, {51, 25},
    {52, 27}, {53, 26}, {54, 30}, {55, 31}, {56, 31}, {57, 33}, {58, 28}, {59, 30},
    {60, 31}, {61, 25}, {62, 35}, {63, 34}, {64, 34}, {65, 37}, {66, 35}, {67, 31},
    {68, 34}
};

// Global variables
vector<unsigned char> TARGET_HASH160_RAW(20);
atomic<bool> stop_event(false);
mutex result_mutex;
queue<tuple<string, size_t, int>> results;
atomic<size_t> total_checked(0);
size_t total_combinations = 0;

// Convert hex string to raw bytes
vector<unsigned char> hex_to_bytes(const string& hex) {
    vector<unsigned char> bytes;
    for (size_t i = 0; i < hex.length(); i += 2) {
        string byteString = hex.substr(i, 2);
        unsigned char byte = static_cast<unsigned char>(strtoul(byteString.c_str(), nullptr, 16));
        bytes.push_back(byte);
    }
    return bytes;
}

// Get only the last n bits of a BIGNUM
BIGNUM* get_last_n_bits(BIGNUM* num, int n) {
    BIGNUM* result = BN_new();
    BN_zero(result);
    
    for (int i = 0; i < n; ++i) {
        if (BN_is_bit_set(num, i)) {
            BN_set_bit(result, i);
        }
    }
    return result;
}

// Predict flip count
int predict_flips(int puzzle_num) {
    if (FLIP_TABLE.count(puzzle_num)) {
        return FLIP_TABLE.at(puzzle_num);
    }
    return 34; // Default for puzzle 68
}

// Binomial coefficient calculation
size_t combinations_count(int n, int k) {
    if (k > n) return 0;
    if (k * 2 > n) k = n - k;
    if (k == 0) return 1;

    size_t result = n;
    for(int i = 2; i <= k; ++i) {
        result *= (n - i + 1);
        result /= i;
    }
    return result;
}

// Memory-efficient combination generator
class CombinationGenerator {
    int n, k;
    vector<int> current;
public:
    CombinationGenerator(int n, int k) : n(n), k(k), current(k) {
        for (int i = 0; i < k; ++i) current[i] = i;
    }
  
    bool next() {
        int i = k - 1;
        while (i >= 0 && current[i] == n - k + i) --i;
        if (i < 0) return false;
      
        ++current[i];
        for (int j = i + 1; j < k; ++j)
            current[j] = current[j-1] + 1;
        return true;
    }
  
    const vector<int>& get() const { return current; }
};

// Fast BIGNUM XOR for n bits
void bn_xor_nbits(BIGNUM* r, const BIGNUM* a, const BIGNUM* b, int n) {
    BN_copy(r, a);
    for (int i = 0; i < n; ++i) {
        if (BN_is_bit_set(a, i) != BN_is_bit_set(b, i))
            BN_set_bit(r, i);
        else
            BN_clear_bit(r, i);
    }
}

// Worker function
void worker(BIGNUM* base_bn, int bit_length, int flip_count, size_t start, size_t end) {
    // One-time allocations
    BIGNUM* trimmed_base = get_last_n_bits(base_bn, bit_length);
    BIGNUM* current = BN_new();
    BIGNUM* mask = BN_new();
    EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1);
    const EC_GROUP* group = EC_KEY_get0_group(key);
    EC_POINT* pub = EC_POINT_new(group);
    unsigned char pubkey[33];
    unsigned char sha256[SHA256_DIGEST_LENGTH];
    unsigned char ripemd160[RIPEMD160_DIGEST_LENGTH];
    
    CombinationGenerator gen(bit_length, flip_count);
    for (size_t i = 0; i < start && gen.next(); ++i);

    size_t count = 0;
    do {
        // 1. Build mask
        BN_zero(mask);
        for (int pos : gen.get()) BN_set_bit(mask, pos);

        // 2. XOR operation
        bn_xor_nbits(current, trimmed_base, mask, bit_length);

        // 3. Set private key
        if (!EC_KEY_set_private_key(key, current)) continue;

        // 4. Generate public key
        if (!EC_POINT_mul(group, pub, current, nullptr, nullptr, nullptr)) continue;

        // 5. Get compressed pubkey
        if (EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED, pubkey, 33, nullptr) != 33) continue;

        // 6. Compute hashes
        SHA256(pubkey, 33, sha256);
        RIPEMD160(sha256, SHA256_DIGEST_LENGTH, ripemd160);

        // 7. Compare raw bytes
        if (memcmp(ripemd160, TARGET_HASH160_RAW.data(), 20) == 0) {
            char* hex_key = BN_bn2hex(current);
            lock_guard<mutex> lock(result_mutex);
            results.push(make_tuple(hex_key, total_checked.load(), flip_count));
            OPENSSL_free(hex_key);
            stop_event.store(true);
            break;
        }

        if (++total_checked % REPORT_INTERVAL == 0) {
            double progress = (double)total_checked / total_combinations * 100;
            cout << "Progress: " << fixed << setprecision(6) << progress << "% (";
            cout << total_checked << "/" << total_combinations << ")\r";
            cout.flush();
        }
          
    } while (gen.next() && (count++ < (end-start)) && !stop_event.load());

    // Cleanup
    EC_POINT_free(pub);
    EC_KEY_free(key);
    BN_free(mask);
    BN_free(current);
    BN_free(trimmed_base);
}

int main() {
    // Convert target hash to raw bytes
    TARGET_HASH160_RAW = hex_to_bytes(TARGET_HASH160);

    cout << "=======================================\n";
    cout << "== Mutagen Puzzle Solver by Denevron ==\n";
    cout << "=======================================\n";
  
    BIGNUM* base_bn = BN_new();
    BN_hex2bn(&base_bn, BASE_KEY.c_str());
  
    const int bit_length = PUZZLE_NUM;
    const int flip_count = predict_flips(PUZZLE_NUM);
    total_combinations = combinations_count(bit_length, flip_count);
  
    cout << "Searching Puzzle " << PUZZLE_NUM << " (" << bit_length << "-bit)\n";
    cout << "Base Key: " << BASE_KEY.substr(0, 10) << "..." << BASE_KEY.substr(BASE_KEY.length()-10) << "\n";
    cout << "Target HASH160: " << TARGET_HASH160.substr(0, 10) << "..." << TARGET_HASH160.substr(TARGET_HASH160.length()-10) << "\n";
    cout << "Predicted Flip Count: " << flip_count << " bits\n";
    cout << "Total Combinations: " << total_combinations << "\n";
    cout << "Using " << WORKERS << " workers...\n";
  
    auto start_time = chrono::high_resolution_clock::now();
    vector<thread> threads;
    size_t chunk = total_combinations / WORKERS;
  
    for (int i = 0; i < WORKERS; ++i) {
        size_t start = i * chunk;
        size_t end = (i == WORKERS-1) ? total_combinations : start + chunk;
        threads.emplace_back(worker, base_bn, bit_length, flip_count, start, end);
    }
  
    for (auto& t : threads) t.join();
    BN_free(base_bn);
  
    if (!results.empty()) {
        auto [hex_key, checked, flips] = results.front();
        auto elapsed = chrono::duration_cast<chrono::seconds>(
            chrono::high_resolution_clock::now() - start_time).count();
      
        cout << "\n=======================================\n";
        cout << "=========== SOLUTION FOUND ============\n";
        cout << "=======================================\n";
        cout << "Private Key: " << hex_key << "\n";
        cout << "Search Time: " << elapsed << " seconds\n";
        cout << "Keys Checked: " << checked << "\n";
        cout << "Bit Flips: " << flips << endl;
      
        ofstream out("puzzle_" + to_string(PUZZLE_NUM) + "_solution.txt");
        out << hex_key;
        out.close();
        cout << "Solution saved to puzzle_" << PUZZLE_NUM << "_solution.txt\n";
    } else {
        cout << "\nSolution not found. Checked " << total_checked << " combinations\n";
    }
  
    return 0;
}


Quote
# ./mutagen
=======================================
== Mutagen Puzzle Solver by Denevron ==
=======================================
Searching Puzzle 20 (20-bit)
Base Key: 0000000000...000005749f
Target HASH160: b907c3a2a3...703c272868
Predicted Flip Count: 8 bits
Total Combinations: 125970
Using 12 workers...
Progress: 47.630388% (60000/125970)
=======================================
=========== SOLUTION FOUND ============
=======================================
Private Key: 0D2C55
Search Time: 3 seconds
Keys Checked: 63547
Bit Flips: 8
Solution saved to puzzle_20_solution.txt


And so on, it can be improved infinitely. But the main question here is the number of possible combinations, which grow exponentially.

But we love useless scripts—I’m even a collector  Grin

Well, there is no need to improve it forever, because you will simply get tired of doing it  Grin
and whether it is useless and the idea itself, time will tell)
Desyationer
Jr. Member
*
Offline Offline

Activity: 64
Merit: 2


View Profile
March 31, 2025, 11:29:51 AM
 #8434

This is truly unfortunate… Each conversion of a number into a Bitcoin address requires around 1,700 simple operations. Even if this process could be optimized to a single basic operation, brute-forcing the 68th range would still take at least six months, even on the most powerful GPUs like the RTX 4090 or 5090. As far as I know, all existing brute-force programs such as KeyHunt and BitCrack utilize only the CUDA cores of GPUs. However, there is an untapped source of power tensor cores which remain unused. The theoretical performance of CUDA cores is around ~80 TFLOPS for the RTX 4090 and ~100 TFLOPS for the RTX 5090, while tensor cores offer significantly higher performance: 285 TFLOPS for the RTX 4090 and 400 TFLOPS for the RTX 5090.  If tensor cores could be utilized, the speed of brute-force calculations could be increased several times over. In theory, tensor cores are also capable of handling matrix multiplications and similar computations. Currently, the maximum speed achievable using publicly available CUDA-based programs from GitHub with an RTX 5090 is around 9GKeys per second.
kTimesG
Full Member
***
Offline Offline

Activity: 546
Merit: 166


View Profile
March 31, 2025, 11:53:32 AM
 #8435

This is truly unfortunate… Each conversion of a number into a Bitcoin address requires around 1,700 simple operations. Even if this process could be optimized to a single basic operation, brute-forcing the 68th range would still take at least six months, even on the most powerful GPUs like the RTX 4090 or 5090. As far as I know, all existing brute-force programs such as KeyHunt and BitCrack utilize only the CUDA cores of GPUs. However, there is an untapped source of power tensor cores which remain unused. The theoretical performance of CUDA cores is around ~80 TFLOPS for the RTX 4090 and ~100 TFLOPS for the RTX 5090, while tensor cores offer significantly higher performance: 285 TFLOPS for the RTX 4090 and 400 TFLOPS for the RTX 5090.  If tensor cores could be utilized, the speed of brute-force calculations could be increased several times over. In theory, tensor cores are also capable of handling matrix multiplications and similar computations. Currently, the maximum speed achievable using publicly available CUDA-based programs from GitHub with an RTX 5090 is around 9GKeys per second.

Tensor cores only do 8-bit and 16-bit float ops (e.g. extremely low precision for floating point numbers). So those TFLOPS you see are relative to these kind of numbers, not 32-bit integers/floats. We'd need some Bernstein-level genius mind to help us make use of them when dealing with ECC. They can potentially be put to use to accelerate the inversion, but this requires coming up with a new inversion algorithm. Something that can work via approximations instead of exact values, to find the inverse faster.

Off the grid, training pigeons to broadcast signed messages.
Desyationer
Jr. Member
*
Offline Offline

Activity: 64
Merit: 2


View Profile
March 31, 2025, 12:05:26 PM
 #8436

This is truly unfortunate… Each conversion of a number into a Bitcoin address requires around 1,700 simple operations. Even if this process could be optimized to a single basic operation, brute-forcing the 68th range would still take at least six months, even on the most powerful GPUs like the RTX 4090 or 5090. As far as I know, all existing brute-force programs such as KeyHunt and BitCrack utilize only the CUDA cores of GPUs. However, there is an untapped source of power tensor cores which remain unused. The theoretical performance of CUDA cores is around ~80 TFLOPS for the RTX 4090 and ~100 TFLOPS for the RTX 5090, while tensor cores offer significantly higher performance: 285 TFLOPS for the RTX 4090 and 400 TFLOPS for the RTX 5090.  If tensor cores could be utilized, the speed of brute-force calculations could be increased several times over. In theory, tensor cores are also capable of handling matrix multiplications and similar computations. Currently, the maximum speed achievable using publicly available CUDA-based programs from GitHub with an RTX 5090 is around 9GKeys per second.

Tensor cores only do 8-bit and 16-bit float ops (e.g. extremely low precision for floating point numbers). So those TFLOPS you see are relative to these kind of numbers, not 32-bit integers/floats. We'd need some Bernstein-level genius mind to help us make use of them when dealing with ECC. They can potentially be put to use to accelerate the inversion, but this requires coming up with a new inversion algorithm. Something that can work via approximations instead of exact values, to find the inverse faster.

I wasn't aware of such limitations of tensor cores now it makes sense why they haven't been used for key enumeration yet. I'm curious, if it were possible to leverage them at least for auxiliary inversion, what theoretical speedup could be expected?
kTimesG
Full Member
***
Offline Offline

Activity: 546
Merit: 166


View Profile
March 31, 2025, 01:51:45 PM
 #8437

I wasn't aware of such limitations of tensor cores now it makes sense why they haven't been used for key enumeration yet. I'm curious, if it were possible to leverage them at least for auxiliary inversion, what theoretical speedup could be expected?

If the inversion step is commented out of the code (basically making it a no-op and ignoring that the addition results are incorrect), the speed of EC public key addition, on a GPU, doubles, more or less. So the maximum speedup of the EC workload would be at most 100%, but this assumes an ideal condition that inversion is offloaded entirely to Tensor cores, which is unrealistic. No one can know for sure, until an implementation actually takes advantage of those cores, but we need an algorithm to exist first Smiley

I ignored everything related to the hashing workload here.

Off the grid, training pigeons to broadcast signed messages.
POD5
Member
**
Offline Offline

Activity: 323
Merit: 10

Keep smiling if you're loosing!


View Profile
March 31, 2025, 02:33:00 PM
 #8438

You can use this to both control RAM and thread usage. Count is not working properly.


Code:
// g++ -O3 -march=native -std=c++17 mutagenT.cpp -lssl -lcrypto -lpthread -o mutagenT
// ./mutagenT -t 8  # Use 8 threads

#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <thread>
#include <atomic>
#include <chrono>
#include <queue>
#include <mutex>
#include <unordered_map>
#include <cmath>
#include <fstream>
#include <openssl/ec.h>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/obj_mac.h>
#include <openssl/evp.h>
#include <cstring> // For memset
#include <algorithm> // For min/max

using namespace std;

// Configuration
const string TARGET_HASH160 = "e0b8a2baee1b77fc703455f39d51477451fc8cfc";
const string BASE_KEY = "00000000000000000000000000000000000000000000000730fc235c1942c1ae";
const int PUZZLE_NUM = 68;
int WORKERS = thread::hardware_concurrency(); // Now modifiable via -t flag
const string PROGRESS_FILE = "mutagen_checkpoint.txt";

// Historical flip counts
const unordered_map<int, int> FLIP_TABLE = {
    {20, 8}, {21, 9}, {22, 11}, {23, 12}, {24, 9}, {25, 12}, {26, 14}, {27, 13},
    {28, 16}, {29, 18}, {30, 16}, {31, 13}, {32, 14}, {33, 15}, {34, 16}, {35, 19},
    {36, 14}, {37, 23}, {38, 21}, {39, 23}, {40, 20}, {41, 25}, {42, 24}, {43, 19},
    {44, 24}, {45, 21}, {46, 24}, {47, 27}, {48, 21}, {49, 30}, {50, 29}, {51, 25},
    {52, 27}, {53, 26}, {54, 30}, {55, 31}, {56, 31}, {57, 33}, {58, 28}, {59, 30},
    {60, 31}, {61, 25}, {62, 35}, {63, 34}, {64, 34}, {65, 37}, {66, 35}, {67, 31},
    {68, 34}
};

// Global variables
atomic<bool> stop_event(false);
mutex result_mutex;
queue<tuple<string, size_t, int>> results;

// Save progress to file
void save_progress(size_t current_index, int flip_count) {
    ofstream out(PROGRESS_FILE);
    out << current_index << " " << flip_count;
    out.close();
}

// Load progress from file
bool load_progress(size_t &saved_index, int &flip_count) {
    ifstream in(PROGRESS_FILE);
    if (!in) return false;
    in >> saved_index >> flip_count;
    in.close();
    return true;
}

// Predict flip count
int predict_flips(int puzzle_num) {
    if (FLIP_TABLE.count(puzzle_num)) {
        return FLIP_TABLE.at(puzzle_num);
    }
    return 8; // Default
}

// Binomial coefficient (n choose k)
size_t combinations_count(int n, int k) {
    if (k > n) return 0;
    if (k * 2 > n) k = n - k;
    if (k == 0) return 1;

    size_t result = n;
    for(int i = 2; i <= k; ++i) {
        result *= (n - i + 1);
        result /= i;
    }
    return result;
}

// Generate combinations on-the-fly (avoids storing all in RAM)
void generate_combinations(int n, int k, size_t start, size_t end, function<void(const vector<int>&)> callback) {
    vector<int> current(k);
    for (int i = 0; i < k; ++i) current[i] = i;

    size_t count = 0;
    while (count < end) {
        if (count >= start) {
            callback(current);
        }

        int i = k - 1;
        while (i >= 0 && current[i] == n - k + i) --i;
        if (i < 0) break;

        ++current[i];
        for (int j = i + 1; j < k; ++j) current[j] = current[j - 1] + 1;
        ++count;
    }
}

// Convert BIGNUM to hex string
string bn_to_hex(const BIGNUM* bn) {
    char* hex = BN_bn2hex(bn);
    string result(hex);
    OPENSSL_free(hex);
    return result;
}

// XOR operation for BIGNUM (optimized)
void bn_xor(BIGNUM* result, const BIGNUM* a, const BIGNUM* b) {
    BN_copy(result, a);
    for (int i = 0; i < max(BN_num_bits(a), BN_num_bits(b)); ++i) {
        if (BN_is_bit_set(a, i) != BN_is_bit_set(b, i)) {
            BN_set_bit(result, i);
        } else {
            BN_clear_bit(result, i);
        }
    }
}

// Compute HASH160 (optimized to reuse buffers)
string compute_hash160(const BIGNUM* priv_key) {
    EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (!ec_key) return "";

    if (!EC_KEY_set_private_key(ec_key, priv_key)) {
        EC_KEY_free(ec_key);
        return "";
    }

    unsigned char pubkey[33]; // Compressed pubkey
    EC_POINT* pub_point = EC_POINT_new(EC_KEY_get0_group(ec_key));
    if (!pub_point || !EC_POINT_mul(EC_KEY_get0_group(ec_key), pub_point, priv_key, nullptr, nullptr, nullptr)) {
        EC_POINT_free(pub_point);
        EC_KEY_free(ec_key);
        return "";
    }

    EC_POINT_point2oct(EC_KEY_get0_group(ec_key), pub_point, POINT_CONVERSION_COMPRESSED, pubkey, sizeof(pubkey), nullptr);
    EC_POINT_free(pub_point);
    EC_KEY_free(ec_key);

    unsigned char sha256[SHA256_DIGEST_LENGTH];
    SHA256(pubkey, sizeof(pubkey), sha256);

    unsigned char ripemd160[RIPEMD160_DIGEST_LENGTH];
    RIPEMD160(sha256, SHA256_DIGEST_LENGTH, ripemd160);

    stringstream ss;
    for (int i = 0; i < RIPEMD160_DIGEST_LENGTH; ++i) {
        ss << hex << setw(2) << setfill('0') << (int)ripemd160[i];
    }
    return ss.str();
}

// Worker function (optimized for RAM)
void worker(const BIGNUM* base_bn, int bit_length, int flip_count, size_t start_index, size_t end_index) {
    BIGNUM* current_bn = BN_new();
    BIGNUM* flip_mask = BN_new();

    generate_combinations(bit_length, flip_count, start_index, end_index, [&](const vector<int>& combo) {
        BN_zero(flip_mask);
        for (int pos : combo) {
            BN_set_bit(flip_mask, pos);
        }
       
        bn_xor(current_bn, base_bn, flip_mask);

        string hash160 = compute_hash160(current_bn);
        if (hash160 == TARGET_HASH160) {
            string hex_key = bn_to_hex(current_bn);
            lock_guard<mutex> lock(result_mutex);
            results.push(make_tuple(hex_key, start_index + 1, flip_count));
            stop_event.store(true);
        }
    });

    BN_free(current_bn);
    BN_free(flip_mask);
}

// Parse command-line arguments
void parse_args(int argc, char* argv[]) {
    for (int i = 1; i < argc; ++i) {
        if (strcmp(argv[i], "-t") == 0 && i + 1 < argc) {
            WORKERS = max(1, min(256, atoi(argv[i + 1])));
            ++i;
        }
    }
}

// Parallel search (optimized)
void parallel_search() {
    BIGNUM* base_bn = BN_new();
    BN_hex2bn(&base_bn, BASE_KEY.c_str());

    int flip_count = predict_flips(PUZZLE_NUM);
    size_t total_combs = combinations_count(PUZZLE_NUM, flip_count);

    size_t start_from = 0;
    if (load_progress(start_from, flip_count)) {
        cout << "Resuming from index: " << start_from << endl;
    }

    cout << "Searching Puzzle " << PUZZLE_NUM << " (256-bit)" << endl;
    cout << "Base Key: " << BASE_KEY << endl;
    cout << "Target HASH160: " << TARGET_HASH160 << endl;
    cout << "Predicted Flip Count: " << flip_count << " bits" << endl;
    cout << "Total Possible Combinations: " << total_combs << endl;
    cout << "Using " << WORKERS << " workers..." << endl;

    vector<thread> threads;
    size_t chunk_size = (total_combs - start_from) / WORKERS;
    auto start_time = chrono::high_resolution_clock::now();

    for (int i = 0; i < WORKERS; ++i) {
        size_t start = start_from + (i * chunk_size);
        size_t end = (i == WORKERS - 1) ? total_combs : start + chunk_size;
        threads.emplace_back([=]() {
            worker(base_bn, PUZZLE_NUM, flip_count, start, end);
            if (i == 0) { // Only thread 0 saves progress
                static atomic<size_t> last_saved(0);
                if (start - last_saved >= 100000) {
                    save_progress(start, flip_count);
                    last_saved = start;
                }
            }
        });
    }

    for (auto& t : threads) t.join();
    BN_free(base_bn);

    if (!results.empty()) {
        auto [hex_key, checked, flips] = results.front();
        auto elapsed = chrono::duration_cast<chrono::seconds>(
            chrono::high_resolution_clock::now() - start_time).count();

        cout << "\nFound solution!" << endl;
        cout << "Private Key: " << hex_key << endl;
        cout << "Bit Flips: " << flips << endl;
        cout << "Checked " << checked << " combinations in "
             << elapsed << " seconds (" << (checked/elapsed) << " keys/sec)" << endl;

        ofstream out("solution.txt");
        out << hex_key;
        out.close();
    } else {
        cout << "\nSolution not found. Try adjusting flip count." << endl;
    }
}

int main(int argc, char* argv[]) {
    parse_args(argc, argv); // Parse -t <threads>

    #if OPENSSL_VERSION_NUMBER < 0x10100000L
    OpenSSL_add_all_algorithms();
    #endif

    parallel_search();

    #if OPENSSL_VERSION_NUMBER < 0x10100000L
    EVP_cleanup();
    #endif

    return 0;
}

bc1qtmtmhzp54yvkz7asnqxc9j7ls6y5g93hg08msa
nomachine
Full Member
***
Offline Offline

Activity: 714
Merit: 110


View Profile
March 31, 2025, 03:46:00 PM
 #8439

You can use this to both control RAM and thread usage. Count is not working properly.

I'll upload the next version to GitHub. It's too long for posts, especially if someone quotes it. Otherwise, users would have to scroll through the post for half an hour, making it pointless  Wink

BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
POD5
Member
**
Offline Offline

Activity: 323
Merit: 10

Keep smiling if you're loosing!


View Profile
March 31, 2025, 03:56:26 PM
 #8440

Do you all have telegram?  Grin

bc1qtmtmhzp54yvkz7asnqxc9j7ls6y5g93hg08msa
Pages: « 1 ... 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 [422] 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 ... 568 »
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!