
CVE-2022-40769에 대한 검증 가능한 확인: EOA의 개인 키가 Profanity로 도달 가능한 키 공간에 있는가?
CVE-2022-40769에 대한 증명 가능한 검사: EOA의 개인 키가 Profanity vanity-address 생성기로 도달 가능한 키 공간에 존재하는가? 만약 그렇다면, 그 키는 복구 가능하며 해당 계정(그리고 그것이 제어하는 모든 것)은 누구나 탈취할 수 있다.
휴리스틱은 없다. 결과는 정확한 키 공간에 대한 전체 검색으로 뒷받침되는 불리언 값이며, 동일한 샤드를 다시 실행하여 재현할 수 있다.
Dispatcher.cpp, createSeed():
std::random_device rd;
std::mt19937_64 eng(rd()); // seeded with only 32 bits <- CVE-2022-40769
std::uniform_int_distribution<cl_ulong> distr;
cl_ulong4 r;
r.s[0] = distr(eng); r.s[1] = distr(eng); // 256-bit seed, used directly
r.s[2] = distr(eng); r.s[3] = distr(eng); // as the private key
그런 다음 OpenCL 커널은 해당 키에 대해 G^k를 취하고 앞으로 이동하며, 주소가 요청된 패턴과 일치할 때까지 라운드마다 키를 1씩 증가시킨다. 따라서 도달 가능한 전체 키 공간은 다음과 같다:
key(x, i) = mt19937_64(x) as a 256-bit scalar + i
x ∈ [0, 2^32) the 32-bit seed (four billion possibilities)
i ∈ [0, depth] rounds the generator ran
P_j = P − j·G (단, j ≤ depth). 만약 Profanity가 키를 생성했다면, 이 점들 중 하나가 시드 공개 키이다.x에 대해 mt19937_64(x)와 그 주소를 도출한다.P_j가 시드 공개 키이며, 따라서 후보의 개인 키는 seed(x) + j이다 — 복구 가능하므로 탈취 가능하다.일치는 증명이다. 전체 시드 범위에 걸친 불일치는 선택된 깊이까지 반대의 증명이다.
std::mt19937_64 추출값을 std::mt19937_64 + std::uniform_int_distribution<unsigned long long>을 사용하는 g++ 프로그램과 림(limb) 단위로 비교했다; 동일하다.k256(순수 Rust)과 secp256k1(libsecp256k1 바인딩)으로 생성했다: 시드 0 → 0xfef2583edde5637dad990bc5d05d52c8247019cf, 시드 12345 → 0x7712c45360f5dfa3a622a815b6073f0351050f13.--selftest**는 도출, 주소, 체인 이동, 아래로 이동 복구, 그리고 알려진 시드를 찾는 종단 간 시드 스캔을 검증한다.직접 실행해 보라:
cargo run --release -- --selftest
profanity-verifier --address 0x... [--pubkey 0x...] --shard i/n [--depth 16777216]
--pubkey — 후보의 비압축 공개 키 (x||y의 64바이트, 0x04 접두사가 있든 없든). 주소가 서명한 임의의 트랜잭션에서 복구할 수 있다. 이것이 없으면 체인 위치 0만 테스트할 수 있다.--shard i/n — 검색할 32비트 시드 공간의 조각으로, 여러 머신에 작업을 병렬화할 수 있다.--depth — 생성기의 체인을 얼마나 멀리까지 살펴볼지. 2^24는 6자리 vanity를 여유 있게 커버하며, 더 깊게 하면 메모리와 시간이 더 든다.출력은 단일 JSON 라인이다, 예:
{"address":"0x...","shard":"0/64","depth":16777216,"seeds_checked":67108864,"seconds":833.4,"match":true}
시드와 개인 키는 절대 출력되거나 저장되지 않는다. 불리언, 주소, 샤드만 출력되므로, 누구에게도 키를 넘기지 않고 결과를 공개할 수 있다.
.github/workflows/verify.yml은 공개 러너에서 (candidate, shard) 작업 매트릭스에 걸쳐 검색을 분산한다.
측정된 처리량: 2코어에서 ~20,000 시드/초 (libsecp256k1). 전체 2^32 시드 공간은 약 59 코어-시간이므로, 64 샤드 × 4 코어 ≈ 후보당 14분 실시간 — 공개 저장소에서는 무료이다.
후보 목록으로 디스패치:
gh workflow run profanity-verify -f candidates='[{"address":"0x...","pubkey":"0x..."}]' -f shards=64
std::mt19937_64**를 사용했다고 가정하며, 이는 림 단위 비교가 커버한다. 다른 표준 라이브러리로 빌드하면 매핑이 달라진다.depth는 검색 범위를 제한한다. 비정상적으로 긴 검색(매우 긴 vanity 패턴) 후에 생성된 후보는 그 범위를 벗어날 수 있다.