
فحص قابل للإثبات لـ CVE-2022-40769: هل يقع المفتاح الخاص لحساب EOA ضمن فضاء المفاتيح الذي يمكن الوصول إليه عبر Profanity؟
فحص قابل للإثبات لـ CVE-2022-40769: هل يقع المفتاح الخاص لعنوان EOA ضمن فضاء المفاتيح الذي يمكن الوصول إليه بواسطة مولّد العناوين الجمالية Profanity؟ إذا كان الجواب نعم، فإن المفتاح قابل للاسترداد والحساب (وكل ما يتحكم به) قابل للسحب من قبل أي شخص.
لا استدلالات تقريبية. النتيجة قيمة منطقية مدعومة ببحث كامل في فضاء المفاتيح الدقيق، قابلة لإعادة الإنتاج بإعادة تشغيل نفس الشريحة (shard).
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 لذلك المفتاح وتمضي قدمًا، بزيادة المفتاح بمقدار واحد في كل جولة حتى يطابق العنوان النمط المطلوب. لذا فإن فضاء المفاتيح الكامل القابل للوصول هو:
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 قد أنشأ المفتاح، فإن إحدى هذه النقاط هي مفتاح عام لبذرة (seed).x يشتق mt19937_64(x) وعنوانه.P_j هو المفتاح العام للبذرة، لذا فإن المفتاح الخاص للمرشّح هو seed(x) + j — قابل للاسترداد، وبالتالي قابل للسحب.التطابق هو إثبات. عدم التطابق عبر نطاق البذور الكامل هو إثبات للعكس، حتى العمق المختار.
std::mt19937_64 الخام للبذور 0، 1، 12345 و4294967295 طرفًا بطرف مقابل برنامج g++ يستخدم std::mt19937_64 + std::uniform_int_distribution<unsigned long long>؛ متطابقة.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 — المفتاح العام غير المضغوط للمرشّح (64 بايت من x||y، مع أو بدون البادئة 0x04). استرجعه من أي معاملة وقّعها العنوان. بدونه، يمكن اختبار موضع السلسلة 0 فقط.--shard i/n — الشريحة من فضاء البذور ذي 32 بت المراد فحصها، بحيث يتوازى العمل عبر الأجهزة.--depth — إلى أي مدى على سلسلة المولّد يتم البحث. 2^24 يغطي عنوانًا جماليًا من ستة أحرف مع هامش إضافي؛ العمق الأكبر يكلّف ذاكرة ووقتًا.المخرجات سطر JSON واحد، على سبيل المثال:
{"address":"0x...","shard":"0/64","depth":16777216,"seeds_checked":67108864,"seconds":833.4,"match":true}
لا يتم أبدًا طباعة أو تخزين البذرة والمفتاح الخاص. يتم إخراج القيمة المنطقية والعنوان والشريحة فقط، بحيث يمكن نشر النتيجة دون تسليم المفتاح لأي شخص.
.github/workflows/verify.yml يوزّع البحث على مصفوفة من مهام (candidate, shard) على مشغّلات عامة.
الإنتاجية المقاسة: ~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 الخاص بـ libstdc++، وهو ما تغطيه المقارنة طرفًا بطرف. البناءات مقابل مكتبة قياسية مختلفة سيكون لها تعيين مختلف.depth يحدّ البحث. المرشّح المُولَّد بعد بحث طويل بشكل غير معتاد (أنماط جمالية طويلة جدًا) قد يقع خارج هذا الحد.