الغوص العميق في Tornado.Cash يكشف عن هجمات المرونة لمشاريع zkp

金色财经_

في المقالة السابقة ، شرحنا ثغرات المرونة في نظام الإثبات Groth16 نفسه من منظور المبدأ. في هذه المقالة ، سوف نأخذ Tornado.Cash كمثال ، تعديل بعض دوائره وأكواده ، إدخال هجوم القابلية للتطويع العملية وآمل أن تهتم أطراف مشروع zkp الأخرى أيضًا بالتدابير الوقائية المقابلة في المشروع. من بينها ، يستخدم Tornado.Cash مكتبة snarkjs للتطوير ، والتي تستند أيضًا إلى عملية التطوير التالية ، وسيتم تقديمها مباشرة لاحقًا.إذا لم تكن على دراية بالمكتبة ، يرجى قراءة المقالة الأولى في هذه السلسلة. (Beosin | تحليل متعمق لثغرة zk-SNARK برهان المعرفة الصفرية: لماذا لا يكون نظام إثبات المعرفة الصفرية مضمونًا؟)! [346a815b39293aee95668fb9b2049873] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-96823e64cc-dd1a6f-1c6801 “7076908”)

(مصدر:

** 1 Tornado.Cash Architecture **

تتضمن عملية تفاعل Tornado.Cash بشكل أساسي 4 كيانات: * المستخدم: استخدم DApp هذا لإجراء معاملات الخصوصية مع الخلاط ، بما في ذلك عمليات الإيداع والسحب.

  • صفحة الويب: صفحة الويب الأمامية الخاصة بـ DApp ، والتي تحتوي على بعض أزرار المستخدم.
  • المرحل: من أجل منع العقد الموجودة على السلسلة من تسجيل معلومات مثل عنوان IP الذي بدأ المعاملة الخاصة ، سيعيد الخادم تشغيل المعاملة بدلاً من المستخدم ، مما يعزز الخصوصية بشكل أكبر.
  • العقد: يحتوي على عقد وكيل Tornado.Cash Proxy ، والذي سيحدد تجمع Tornado المحدد لعمليات الإيداع والسحب اللاحقة وفقًا لمقدار عمليات الإيداع والسحب التي يقوم بها المستخدم. يوجد حاليًا 4 حمامات سباحة بمقادير 0.1 و 1 و 10 و 100.

يقوم المستخدم أولاً بإجراء العمليات المقابلة على صفحة الويب الأمامية لـ Tornado. نقود لبدء معاملة إيداع أو سحب ، ثم يقوم المرحل بإعادة توجيه طلب المعاملة إلى عقد Tornado.Cash Proxy على السلسلة ، ثم يحيله إلى المقابل المقابل تجمع وفقًا لمبلغ المعاملة ، وأخيراً لمعالجة الإيداعات والسحوبات ، يكون الهيكل المحدد كما يلي:! [f471dfca152796f84a6389ff3a6d96ac] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-fa8e75c3b3-dd1a6f-1c6801 “7076909”) كخلاط عملات ، لدى Tornado.Cash وظيفتان محددتان للعمل: * الإيداع: عند المستخدم يُجري معاملة إيداع ، ويختار أولاً رمز الإيداع (BNB ، ETH ، إلخ) والمبلغ المقابل على صفحة الويب الأمامية.من أجل ضمان خصوصية المستخدم بشكل أفضل ، يمكن إيداع أربعة مبالغ فقط ؛

! [fc9fe4cf9b1b8528e2446d23f39afc9a] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-22994b5b68-dd1a6f-1c6801 “7076910”)

المصدر: <

ثم يقوم الخادم بتوليد رقمين عشوائيين مكونين من 31 بايتًا وسريًا ، وبعد تجزيئهما معًا ، قم بإجراء عملية pedersenHash للحصول على الالتزام ، وإعادة المبطل + السر بالإضافة إلى البادئة كملاحظة للمستخدم. الملاحظة هي كما يلي :! [83feeca678c53c26a5cfe70f55d29f10] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-64aba8733a-dd1a6f-1c6801 “7076911”) * ثم تبدأ معاملة الإيداع لإرسال الالتزام والبيانات الأخرى إلى Tornado.Cash Proxy العقد على السلسلة ، يقوم العقد بالوكالة بإعادة توجيه البيانات إلى المجمع المقابل وفقًا لمبلغ الإيداع ، وأخيراً يُدرج عقد التجمع الالتزام كعقدة ورقية في شجرة Merkle ، ويخزن الجذر المحسوب في عقد التجمع.

  • السحب: عندما يقوم المستخدم بإجراء معاملة سحب ، أدخل بيانات الملاحظة أولاً وعنوان الاستلام الذي تم إرجاعه عند إدخال الإيداع في صفحة الويب الأمامية ؛

! [49898b341e39bdbebd651b5d3918faef] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-54deb436c4-dd1a6f-1c6801 “7076912”)

مصدر الصورة: <* ثم يقوم الخادم باسترداد جميع أحداث الإيداع الخاصة بـ Tornadocash ضمن السلسلة ، واستخراج الالتزامات لبناء شجرة Merkle ضمن السلسلة ، وإنشاء الالتزام والمطابقة Merkle وفقًا لبيانات الملاحظة (nullifier + secret) المعطى بواسطة مسار المستخدم والجذر المقابل كمدخلات دائرة للحصول على إثبات SNARK للمعرفة الصفرية ؛ أخيرًا ، يتم بدء معاملة سحب إلى Tornado.Cash Proxy عقد على السلسلة ، ثم ينتقل إلى عقد التجمع المقابل للتحقق الإثبات وفقًا للمعايير ، ويتم إضافة الأموال إلى عنوان المستلم المحدد من قبل المستخدم.

من بينها ، جوهر الانسحاب من Tornado.Cash هو في الواقع إثبات وجود التزام معين على شجرة Merkle دون الكشف عن المبطل والسر الذي يحتفظ به المستخدم. هيكل شجرة Merkle المحدد هو كما يلي:! [a56d827c9d275989d6948e23280123ce] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-2215203ef5-dd1a6f-1c6801 “7076913”) ## ** 2 Tornado.Cash magic النسخة المعدلة **

** 2.1 تورنادو التغيير السحري النقدي **

بالنسبة للمقالة الأولى ، مبدأ هجوم المرونة Groth16 ، نعلم أن المهاجم يمكنه في الواقع إنشاء عدة أدلة مختلفة باستخدام نفس المبطل والسري. إذا لم يفكر المطور في هجوم الإنفاق المزدوج الناتج عن إعادة عرض الإثبات ، فسيهدد تمويل المشروع . ** قبل التعديل السحري لـ Tornado.Cash ، تقدم هذه المقالة أولاً الكود الموجود في المسبح حيث يتولى Tornado.Cash أخيرًا معالجة الانسحاب:

/ \ * \ *dev سحب وديعة من العقد. الإثبات عبارة عن بيانات إثبات zkSNARK ، والإدخال عبارة عن مجموعة من مصفوفة المدخلات العامة للدائرة تتكون من: - جذر Merkle لجميع الإيداعات في العقد - تجزئة إلغاء الإيداع الفريد لمنع الإنفاق المزدوج - مستلم الأموال - رسوم اختيارية تذهب إلى مرسل المعاملة (عادةً ما يكون مرحلًا) \ * / سحب الوظيفة (بايت بيانات المكالمة \ _ عازلة ، بايت 32 \ _ الجذر ، بايت 32 \ _nullifierHash ، العنوان المستحق الدفع \ _المستلم ، العنوان المستحق الدفع \ _ relayer ، uint256 \ _ الرسوم ، uint256 \ _ استرداد) غير مستأجر خارجي مستحق الدفع { تتطلب (\ _ الرسم <= المذهب ، “الرسوم تتجاوز قيمة التحويل”) ؛ تتطلب (! nullifierHashes [\ _ nullifierHash]، “تم إنفاق الملاحظة بالفعل”)؛ تتطلب (isKnownRoot (\ _ root) ، “لا يمكن العثور على جذر Merkle الخاص بك”) ؛ // تأكد من استخدام آخر يتطلب (verifier.verifyProof (\ _proof، [uint256 (\ _ root)، uint256 (\ _ nullifierHash)، uint256 (\ _ Receiver)، uint256 (\ _ relayer)، \ _fee، \ _refund]) ، “إثبات سحب غير صالح”) ؛ nullifierHashes [\ _ nullifierHash] = صحيح ؛ \ _عملية سحب (\ _ المستلم ، \ _ relayer ، \ _ رسوم ، \ _ استرداد) ؛ ينبعث الانسحاب (\ _ المستلم ، \ _nullifierHash ، \ _ relayer ، \ _fee) ؛ }

في الشكل أعلاه ، من أجل منع المهاجمين من استخدام نفس الدليل لتنفيذ هجمات مزدوجة الإنفاق دون الكشف عن المبطل والسري ، يضيف Tornado.Cash أداة إلغاء إشارة عامة إلى الدائرة ، والتي يتم الحصول عليها عن طريق تجزئة بيدرسن للبطل. ويمكن استخدامه كمعامل تم تمريره إلى السلسلة ، ثم يستخدم عقد المجمع هذا المتغير لتحديد ما إذا كان قد تم استخدام إثبات صحيح. ومع ذلك ، إذا لم يستخدم طرف المشروع طريقة تعديل الدائرة ، ولكنه يسجل طريقة الإثبات مباشرةً لمنع الإنفاق المزدوج ، ففي النهاية ، يمكن أن يقلل ذلك من قيود الدائرة ويوفر التكاليف ، ولكن هل يمكنه تحقيق الهدف؟ بالنسبة لهذا التخمين ، ستحذف هذه المقالة إشارة nullifierHash العامة المضافة حديثًا في الدائرة ، وتغيير التحقق من العقد إلى إثبات التحقق. منذ حصول Tornado.Cash على جميع أحداث الإيداع في كل مرة يتم فيها الانسحاب ، ويبني شجرة Merkle ثم يتحقق مما إذا كانت قيمة الجذر التي تم إنشاؤها ضمن آخر 30 ، فإن العملية برمتها مزعجة للغاية ، لذلك ستحذف الدائرة في هذه المقالة أيضًا دائرة merkleTree ، يتم ترك الدائرة الأساسية لجزء السحب فقط ، وتكون الدائرة المحددة كما يلي:

تشمل “…/…/…/…/node_modules/circomlib/circuits/bitify.circom” ؛ تضمين “…/…/…/…/node_modules/circomlib/circuits/pedersen.circom”؛// يحسب Pedersen (المبطل + السر) نموذج CommitmentHasher () {مُبطل إدخال الإشارة ؛ سر إدخال الإشارة ؛ التزام خرج الإشارة ؛ // إشارة الخرج المبطل // حذف عنصر التزامهاشر = بيدرسن (496) ؛ // component nullifierHasher = Pedersen (248) ؛ مكون nullifierBits = Num2Bits (248) ؛ المكون secretBits = Num2Bits (248) ؛ nullifierBits.in <== المبطل ؛ secretBits.in <== سر ؛ لـ (i = 0 ؛ i <248 ؛ i ++) {// nullifierHasher.in [i] <== nullifierBits.out [i] ؛ // حذف الالتزام [i] <== nullifierBits.out [i] ؛ التزام Hasher.in [i + 248] <== secretBits.out [i] ؛ } التزام <== التزام Hasher.out [0] ؛ // nullifierHash <== nullifierHasher.out [0] ؛ // delete} // تتحقق من أن الالتزام الذي يتوافق مع السر والمُبطل المحدد متضمن في شجرة Merkle للودائع التي تلتزم بإخراج الإشارات ؛ مستلم إدخال الإشارة ؛ // عدم المشاركة في أي حسابات لإدخال إشارة الإدخال ؛ // عدم المشاركة في أي رسوم إدخال إشارة حسابية ؛ // عدم المشاركة في أي استرداد لإدخال إشارة حسابية ؛ // عدم المشاركة في أي حسابات لإبطال إدخال إشارة ؛ سر إدخال الإشارة ؛ تجزئة المكون = CommitmentHasher () ، hasher.nullifier <== nullifier ؛ hasher.secret <== secret؛ الالتزام <== hasher.commitment ؛ // أضف إشارات مخفية للتأكد من أن العبث بالمستلم أو الرسوم سيؤدي إلى إبطال إثبات الشق // على الأرجح أنه ليس مطلوبًا ، ولكن من الأفضل البقاء في الجانب الآمن ولا يتطلب الأمر سوى قيدين فقط // يتم استخدام المربعات لمنع محسن من إزالة تلك القيود إشارة المتلقي مربع ؛ رسوم الإشارةمربع ؛ مرحل الإشارة استرداد الإشارة مربع المستلم <== المستلم \ * المستلم ؛ رسوم مربع <== رسوم \ * رسوم ؛ relayerSquare <== relayer \ * relayer ؛ استرداد مربع <== استرداد \ * استرداد ؛} مكون رئيسي = سحب (20) ؛

  • ملاحظة: وجدنا خلال التجربة أن TornadoCash في أحدث إصدار من الكود في GitHub (دائرة السحب تفتقر إلى إشارة خرج وتتطلب تصحيحًا يدويًا لتعمل بشكل صحيح. * وفقًا للدائرة المعدلة أعلاه ، استخدم مكتبة snarkjs ، وما إلى ذلك لمتابعة عملية التطوير الواردة في بداية هذه المقالة خطوة بخطوة ، وإنشاء الدليل العادي التالي ، والذي يتم تسجيله كدليل 1:

الإثبات: {pi_a: [12731245758885665844440940942625335911548255472545721927606279036884288780352n، 1102956704503334056654836789330405294645731963296066905393227192287626] 44564670704503334056654836789330405294645731963296066905393227192287626] 187546754094667837383166479615474515182183878046002081n، 8088104569927474555610665242983621221932062943927262293572649061565902268616n] ، [919424846311598694098111942484631159869409811 6n، 18373139073981696655136870665800393986130876498128887091087060068369811557306n]، [1n، 0n]]، pi_c: [1626407734863381433630916916203225704171957179582490143 178253544576299821079735144068419595539416984653646546215n ، 1n] ، البروتوكول: "groth16 منحنى: “bn128”}

** 2.2 التحقق التجريبي **

** 2.2.1 إثبات التحقق - العقد الافتراضي الناتج عن شركة circom **

بادئ ذي بدء ، نستخدم العقد الافتراضي الذي تم إنشاؤه بواسطة circom للتحقق. نظرًا لأن العقد لا يسجل أي معلومات متعلقة بالإثبات تم استخدامها على الإطلاق ، يمكن للمهاجم إعادة عرض الإثبات 1 عدة مرات للتسبب في هجوم مزدوج الإنفاق. في التجارب التالية ، يمكن إعادة الإثبات بلا حدود لنفس المدخلات من نفس الدائرة ، ويمكن لكل منهم اجتياز التحقق. ! [caaf8474774d0ffaaea894961231e604] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-36bda9ebd9-dd1a6f-1c6801 “7076914”) الصورة أدناه هي لقطة شاشة للتجربة باستخدام proof1 في العقد الافتراضي لإثبات أن التحقق تم اجتيازه ، بما في ذلك المقالة السابقة معاملات الإثبات A و B و C المستخدمة في ، والنتيجة النهائية:

! [8796de83786dab2e1d2fe8988a2a8c3c] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-1d87d37558-dd1a6f-1c6801 “7076915”)

الشكل أدناه هو نتيجة استخدام نفس الإثبات 1 لاستدعاء وظيفة التحقق عدة مرات للتحقق من الإثبات. وجدت التجربة أنه بالنسبة للإدخال نفسه ، بغض النظر عن عدد المرات التي استخدم فيها المهاجم الإثبات 1 للتحقق ، يمكن أن يمر:! [058bfa45cfac5803990db4cb707c737b] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-6f3b277d3a-dd1a6f-1c6801 “7076916”) بالطبع ، نحن نختبر في مكتبة أكواد js الأصلية من snarkjs ، ولم نختبر الدليل المستخدم بالفعل والذي تم تمريره للحماية ، النتائج التجريبية هي كما يلي: ## ** 2.2.2 إثبات التحقق - عقد عادي ضد إعادة التشغيل **

بالنسبة لثغرة إعادة التشغيل في العقد الافتراضي الذي تم إنشاؤه بواسطة circom ، تسجل هذه المقالة قيمة في الدليل الصحيح (الإثبات 1) الذي تم استخدامه لمنع هجمات الإعادة باستخدام الدليل الذي تم التحقق منه ، كما هو موضح في الشكل التالي:! [9afeb481747b16752a00b70c5562bac2] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-384e9b2889-dd1a6f-1c6801 “7076917”) استمر في استخدام الإثبات 1 للتحقق. وجدت التجربة أنه عند استخدام نفس الدليل للتحقق الثانوي ، تم إرجاع المعاملة خطأ: “تم صرف الملاحظة بالفعل” ، والنتيجة كما هو موضح في الشكل أدناه:! [40293d602538a60400dffa795e0454dd] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-d09fb1e9c2-dd1a6f-1c6801 “7076918”) ولكن ** على الرغم من أن الغرض من منع هجمات إعادة الإثبات العادية قد تحقق في هذا الوقت ، المقدمة السابقة هناك مشكلة قابلية للضعف في خوارزمية groth16 ، ولا يزال من الممكن تجاوز هذا الإجراء الوقائي. لذلك قمنا ببناء PoC في الشكل أدناه ، وقمنا بإنشاء شهادة zk-SNARK وهمية لنفس المدخلات وفقًا للخوارزمية في المقالة الأولى.وجدت التجربة أنه لا يزال بإمكانها اجتياز التحقق. كود PoC لتوليد الإثبات المزور 2 هو كما يلي: **

استيراد WasmCurve من “/Users/saya/node_modules/ffjava/src/wasm_curve.js"import ZqField من” /Users/saya/node_modules/ffjava/src/f1field.js"import groth16FullProve من “/ Users /saya/node_modules/snarkjs/src/groth16_fullprove.js"import groth16 تحقق من “/Users/saya/node_modules/snarkjs/src/groth16_verify.js”؛import \ * كمنحنيات من” / Users /saya/node_modules/snarkjs/src/curves.js"؛ استيراد fs من “fs”؛ استيراد {utils} من “ffjava”؛ const {unstringifyBigInts} = utils؛ groth16 \ _exp ()؛ دالة غير متزامنة groth16 \ _exp () {let inputA = “7” ؛ اسمحوا inputB = “11” ؛ const SNARK \ _FIELD \ _SIZE = BigInt (‘21888242871839275222246405745257275088548364400416034343698204186575808495617’) ؛ // 2. 读取 string 后 转化 为 int const proof = wait unstringifyBigInts (JSON.parse (fs.readFileSync (“proof.json”، “utf8”))) ؛ console.log (“الدليل:” ، إثبات) ؛ // 生成 逆 元 , 生成 的 逆 元 必须 在 F1 域 const F = new ZqField (SNARK \ _FIELD \ _SIZE) ؛ // const F = حقل F2F جديد (SNARK \ _FIELD \ _SIZE) ؛ const X = Fe (“123456”) const invX = F.inv (X) console.log (“x:”، X) console.log (“invX”، invX) console.log (“The timesScalar is:”، F.mul (X، invX)) // 读取 椭圆 曲线 G1 、 G2 点 const vKey = JSON.parse (fs.readFileSync (“verification \ _key.json”، “utf8”)) ؛ // console.log (“المنحنى هو:” ، vKey) ؛ منحنى const = انتظار curves.getCurveFromName (vKey.curve) ؛ const G1 = curve.G1 ؛ const G2 = curve.G2 ؛ const A = G1.fromObject (proof.pi \ _a) ؛ const B = G2.fromObject (إثبات .pi \ _b) ؛ const C = G1.fromObject (proof.pi \ _c) ؛ const جديد \ _pi \ _a = G1.timesScalar (A ، X) ؛ // A '= x \ * A const new \ _pi \ _b = G2.timesScalar (B ، invX) ؛ // B '= x ^ {- 1} \ * B proof.pi \ _a = G1.toObject (G1.toAffine (A)) ؛ proof.new \ _pi \ _a = G1.toObject (G1.toAffine (new \ _pi \ _a)) proof.new \ _pi \ _b = G2.toObject (G2.toAffine (new \ _pi \ _b)) // 将 生成的 G1 、 G2 点 转化 为 دليل console.log (“proof.pi \ _a:”، proof.pi \ _a) ؛ console.log (“proof.new \ _pi \ _a:”، proof.new \ _pi \ _a) console.log (“proof.new \ _pi \ _b:”، proof.new \ _pi \ _b)}

يظهر الإثبات المزور 2 في الشكل أدناه: عند استخدام هذه المعلمة لاستدعاء وظيفة التحقق من الإثبات مرة أخرى للتحقق من الإثبات ، وجدت التجربة أن التحقق من الإثبات 2 مر مرة أخرى في حالة نفس الإدخال ، كما هو موضح أدناه:! [03d0f119ea666620685b4cece791a789] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-4c49de3755-dd1a6f-1c6801 “7076919”) على الرغم من أن البرهان المزور 2 لا يمكن استخدامه إلا مرة أخرى ، بسبب التزوير هناك عدد لا نهائي تقريبًا من البراهين ، لذلك قد يتسبب في سحب أموال العقد إلى ما لا نهاية. تستخدم هذه المقالة أيضًا رمز js الخاص بمكتبة circom للاختبار ، ويمكن للنتائج التجريبية proof1 و proof2 المزيفة اجتياز التحقق:! [9153431b50b81dcadbf68930ded584c3] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-934c4ab3e4-dd1a6f-1c6801 “7076920”) ## ** 2.2.3 إثبات التحقق - عقد إعادة الدفع النقدي **

بعد العديد من الإخفاقات ، ألا توجد طريقة للقيام بذلك مرة واحدة وإلى الأبد؟ هنا ، وفقًا لممارسة Tornado.Cash للتحقق مما إذا كان قد تم استخدام الإدخال الأصلي ، تستمر هذه المقالة في تعديل رمز العقد على النحو التالي:! [28fabffcac9037a41e030db84f44f83b] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-dfa6f29d35-dd1a6f-1c6801 “7076921”) تجدر الإشارة إلى أنه من أجل توضيح الإجراءات البسيطة لمنع الهجوم المرن خوارزمية groth16 ، \ * \ * تتبنى هذه المقالة طريقة التسجيل المباشر لإدخال الدائرة الأصلية ، لكن هذا لا يتوافق مع مبدأ الخصوصية لإثبات عدم المعرفة ، ويجب الحفاظ على سرية إدخال الدائرة. \ * \ * على سبيل المثال ، المدخلات في Tornado.Cash كلها خاصة ، ويجب إضافة مدخلات عامة جديدة لتحديد إثبات. في هذا البحث ، نظرًا لعدم وجود شعار جديد في الدائرة ، فإن الخصوصية ضعيفة نسبيًا مقارنة بـ Tornado.Cash ، ويستخدم فقط كعرض تجريبي لإظهار النتائج على النحو التالي:! [ac4624fc066156979fae817e327c6224] (https://img-cdn.gateio.im/resized-social/moments-40baef27dd-440d87e977-dd1a6f-1c6801 “7076922”). في المرة الأولى ، لا يمكن أن يجتاز الإثبات 1 ولا الإثبات المزور 2 التحقق. ## ** 3 ملخص وتوصيات **

تتحقق هذه الورقة بشكل أساسي من صحة وأضرار ثغرة إعادة العرض من خلال تعديل دائرة TornadoCash واستخدام العقد الافتراضي الذي تم إنشاؤه بواسطة Circom ، والذي يستخدمه المطورون بشكل شائع ، ويتحقق كذلك من أن الإجراءات الشائعة المستخدمة على مستوى العقد يمكن أن تحمي من إعادة العرض الثغرة الأمنية ، ولكن لا يمكن منعها. هجوم Groth16 المرن ، في هذا الصدد ، نوصي بأن تنتبه مشاريع إثبات المعرفة الصفرية إلى ما يلي أثناء تطوير المشروع: * على عكس DApps التقليدية التي تستخدم بيانات فريدة مثل العناوين لإنشاء بيانات العقدة ، zkp عادةً ما تستخدم المشاريع مجموعة من الأرقام العشوائية لإنشاء عُقد شجرة Merkle ، عليك الانتباه إلى ما إذا كان منطق العمل يسمح بإدخال العقد بنفس القيمة. ** لأن بيانات العقدة الطرفية نفسها قد تتسبب في قفل بعض أموال المستخدم في العقد ، أو أن هناك عدة أدلة Merkle في نفس بيانات العقدة الطرفية التي تربك منطق الأعمال. **

  • عادةً ما يستخدم فريق مشروع zkp التعيين لتسجيل الدليل المستخدم لمنع هجمات الإنفاق المزدوج. ** تجدر الإشارة إلى أنه عند التطوير باستخدام Groth16 ، نظرًا لوجود هجمات ليونة ، يجب استخدام البيانات الأصلية للعقدة للتسجيل ، بدلاً من إثبات تحديد البيانات ذات الصلة فقط. **
  • قد تواجه الدوائر المعقدة مشاكل مثل عدم اليقين في الدائرة والقيود السفلية ، وشروط التحقق من العقد غير مكتملة ، وهناك ثغرات في منطق التنفيذ. ** نوصي بشدة أن يبحث طرف المشروع عن بعض الأبحاث حول الدوائر والعقود عندما يكون المشروع بدأت شركات التدقيق الأمني بإجراء عمليات تدقيق شاملة لضمان أمن المشروع قدر الإمكان. **
شاهد النسخة الأصلية
إخلاء المسؤولية: قد تكون المعلومات الواردة في هذه الصفحة من مصادر خارجية ولا تمثل آراء أو مواقف Gate. المحتوى المعروض في هذه الصفحة هو لأغراض مرجعية فقط ولا يشكّل أي نصيحة مالية أو استثمارية أو قانونية. لا تضمن Gate دقة أو اكتمال المعلومات، ولا تتحمّل أي مسؤولية عن أي خسائر ناتجة عن استخدام هذه المعلومات. تنطوي الاستثمارات في الأصول الافتراضية على مخاطر عالية وتخضع لتقلبات سعرية كبيرة. قد تخسر كامل رأس المال المستثمر. يرجى فهم المخاطر ذات الصلة فهمًا كاملًا واتخاذ قرارات مدروسة بناءً على وضعك المالي وقدرتك على تحمّل المخاطر. للتفاصيل، يرجى الرجوع إلى إخلاء المسؤولية.
تعليق
0/400
لا توجد تعليقات