Shared Code
main.cu
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
#include <cuda_runtime.h> #include <curand_kernel.h> #include <openssl/evp.h> #include <atomic> #include <chrono> #include <cstdint> #include <cstdio> #include <cstdlib> #include <cstring> #include <fstream> #include <iomanip> #include <iostream> #include <mutex> #include <string> #include <thread> #include <vector> static constexpr int SEED_SIZE = 32; static constexpr int PUB_SIZE = 32; static constexpr int KEY_SIZE = 64; static std::atomic<bool> found(false); static std::atomic<uint64_t> tested(0); static std::mutex result_mutex; struct Result { uint8_t seed[32]; uint8_t pub[32]; std::string address; }; static Result result; /* * Solana uses Bitcoin-style Base58. */ static const char BASE58[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; std::string base58_encode(const uint8_t* data, size_t len) { if (len == 0) return ""; std::vector<uint8_t> digits((len * 138 / 100) + 1); size_t digits_len = 1; digits[0] = 0; for (size_t i = 0; i < len; ++i) { int carry = data[i]; for (size_t j = 0; j < digits_len; ++j) { int value = digits[j] * 256 + carry; digits[j] = value % 58; carry = value / 58; } while (carry) { digits[digits_len++] = carry % 58; carry /= 58; } } size_t zeros = 0; while (zeros < len && data[zeros] == 0) zeros++; std::string out; out.reserve(zeros + digits_len); for (size_t i = 0; i < zeros; ++i) out += '1'; for (size_t i = digits_len; i > 0; --i) out += BASE58[digits[i - 1]]; return out; } /* * CUDA kernel: * generate random 32-byte Ed25519 seeds. * * Each thread produces one candidate. */ __global__ void generate_candidates( uint8_t* output, uint64_t seed_base, uint64_t count ) { uint64_t idx = static_cast<uint64_t>(blockIdx.x) * blockDim.x + threadIdx.x; if (idx >= count) return; curandStatePhilox4_32_10_t state; curand_init( seed_base, idx, 0, &state ); uint8_t* dst = output + idx * SEED_SIZE; for (int i = 0; i < SEED_SIZE; i += 4) { unsigned int r = curand(&state); dst[i + 0] = (r >> 0) & 0xff; dst[i + 1] = (r >> 8) & 0xff; dst[i + 2] = (r >> 16) & 0xff; dst[i + 3] = (r >> 24) & 0xff; } } /* * Generate Ed25519 public key from 32-byte seed. * * OpenSSL Ed25519 expects the 32-byte seed. */ bool ed25519_public_key( const uint8_t seed[32], uint8_t pub[32] ) { EVP_PKEY* pkey = EVP_PKEY_new_raw_private_key( EVP_PKEY_ED25519, nullptr, seed, 32 ); if (!pkey) return false; size_t pub_len = 32; int rc = EVP_PKEY_get_raw_public_key( pkey, pub, &pub_len ); EVP_PKEY_free(pkey); return rc == 1 && pub_len == 32; } void save_keypair( const uint8_t seed[32], const uint8_t pub[32], const std::string& filename ) { std::ofstream file(filename); if (!file) { throw std::runtime_error( "Cannot open output file" ); } file << "[\n"; for (int i = 0; i < 32; ++i) { file << static_cast<unsigned int>(seed[i]) << ",\n"; } for (int i = 0; i < 32; ++i) { file << static_cast<unsigned int>(pub[i]); if (i != 31) file << ","; file << "\n"; } file << "]\n"; file.close(); } void process_batch( const uint8_t* seeds, uint64_t count, const std::string& prefix ) { #pragma omp parallel for schedule(dynamic) for (long long i = 0; i < static_cast<long long>(count); ++i) { if (found.load(std::memory_order_relaxed)) continue; const uint8_t* seed = seeds + i * SEED_SIZE; uint8_t pub[32]; if (!ed25519_public_key(seed, pub)) continue; std::string address = base58_encode(pub, 32); tested.fetch_add( 1, std::memory_order_relaxed ); if (address.rfind(prefix, 0) == 0) { bool expected = false; if (found.compare_exchange_strong(expected, true)) { std::lock_guard<std::mutex> lock( result_mutex ); memcpy(result.seed, seed, 32); memcpy(result.pub, pub, 32); result.address = address; } } } } int main(int argc, char** argv) { std::string prefix = "miaw"; if (argc >= 2) prefix = argv[1]; std::cout << "Solana CUDA Vanity Generator\n" << "Prefix: " << prefix << "\n\n"; if (prefix.empty()) { std::cerr << "Prefix cannot be empty\n"; return 1; } /* * Batch size. * * 1 million candidates = 32 MB. */ const uint64_t BATCH = 1'000'000ULL; uint8_t* d_seeds = nullptr; cudaError_t err = cudaMalloc( &d_seeds, BATCH * SEED_SIZE ); if (err != cudaSuccess) { std::cerr << "cudaMalloc failed: " << cudaGetErrorString(err) << "\n"; return 1; } std::vector<uint8_t> h_seeds( BATCH * SEED_SIZE ); const int threads = 256; const int blocks = static_cast<int>( (BATCH + threads - 1) / threads ); uint64_t batch_id = 0; auto start = std::chrono::steady_clock::now(); uint64_t last_report = 0; while (!found.load()) { uint64_t cuda_seed = static_cast<uint64_t>( std::chrono::high_resolution_clock:: now().time_since_epoch().count() ) ^ (++batch_id); generate_candidates<<< blocks, threads >>>( d_seeds, cuda_seed, BATCH ); err = cudaDeviceSynchronize(); if (err != cudaSuccess) { std::cerr << "CUDA error: " << cudaGetErrorString(err) << "\n"; break; } err = cudaMemcpy( h_seeds.data(), d_seeds, BATCH * SEED_SIZE, cudaMemcpyDeviceToHost ); if (err != cudaSuccess) { std::cerr << "cudaMemcpy failed: " << cudaGetErrorString(err) << "\n"; break; } process_batch( h_seeds.data(), BATCH, prefix ); uint64_t current = tested.load(); if (current - last_report >= 1'000'000) { last_report = current; auto now = std::chrono::steady_clock::now(); double seconds = std::chrono::duration<double>( now - start ).count(); double rate = current / seconds; std::cout << "\rTested: " << current << " | " << std::fixed << std::setprecision(2) << rate / 1'000'000.0 << " M keys/s" << std::flush; } } cudaFree(d_seeds); if (!found.load()) { std::cerr << "\nGeneration stopped.\n"; return 1; } std::cout << "\n\nFOUND!\n" << "Address: " << result.address << "\n"; /* * 64-byte Solana keypair: * * [32-byte secret seed][32-byte public key] */ save_keypair( result.seed, result.pub, "keypair.json" ); std::cout << "Saved: keypair.json\n"; return 0; } printf("c[0] = %f\n", h_c[0]); printf("c[1023] = %f\n", h_c[1023]); cudaFree(d_a); cudaFree(d_b); cudaFree(d_c); free(h_a); free(h_b); free(h_c); return 0; }
Comments (0)
to post comments and vote
No comments yet. Be the first to share your thoughts!