EIP-1271: توقيع والتحقق من توقيعات العقود الذكية
يتيح معيار EIP-1271 (يفتح في علامة تبويب جديدة) للعقود الذكية التحقق من التوقيعات.
في هذا البرنامج التعليمي، نقدم نظرة عامة على التوقيعات الرقمية، وخلفية EIP-1271، والتنفيذ المحدد لـ EIP-1271 المستخدم بواسطة Safe (يفتح في علامة تبويب جديدة) (سابقًا Gnosis Safe). يمكن أن يكون هذا بمثابة نقطة انطلاق لتنفيذ EIP-1271 في عقودك الخاصة.
ما هو التوقيع؟
في هذا السياق، التوقيع (وبشكل أدق، "التوقيع الرقمي") هو رسالة بالإضافة إلى نوع من الإثبات على أن الرسالة جاءت من شخص/مرسل/عنوان محدد.
على سبيل المثال، قد يبدو التوقيع الرقمي هكذا:
- الرسالة: "أريد تسجيل الدخول إلى هذا الموقع باستخدام محفظة إيثيريوم الخاصة بي."
- المُوقِّع: عنواني هو
0x000… - الإثبات: إليك بعض الإثباتات على أنني،
0x000…، قمت بالفعل بإنشاء هذه الرسالة بالكامل (عادةً ما يكون هذا شيئًا متعلقًا بعلم التشفير).
من المهم ملاحظة أن التوقيع الرقمي يتضمن كلاً من "رسالة" و"توقيع".
لماذا؟ على سبيل المثال، إذا أعطيتني عقدًا لأوقعه، ثم قمت بقطع صفحة التوقيع وأعدت لك توقيعاتي فقط دون بقية العقد، فلن يكون العقد صالحًا.
وبنفس الطريقة، لا يعني التوقيع الرقمي أي شيء بدون رسالة مرتبطة به!
لماذا يوجد EIP-1271؟
من أجل إنشاء توقيع رقمي لاستخدامه على سلاسل الكتل القائمة على إيثيريوم، تحتاج عمومًا إلى مفتاح خاص سري لا يعرفه أحد غيرك. هذا ما يجعل توقيعك خاصًا بك (لا يمكن لأي شخص آخر إنشاء نفس التوقيع دون معرفة المفتاح السري).
يحتوي حساب إيثيريوم الخاص بك (أي حسابك المملوك خارجيًا/EOA) على مفتاح خاص مرتبط به، وهذا هو المفتاح الخاص الذي يُستخدم عادةً عندما يطلب منك موقع ويب أو تطبيق لامركزي (dapp) توقيعًا (على سبيل المثال، من أجل "تسجيل الدخول باستخدام إيثيريوم").
يمكن للتطبيق التحقق من التوقيع (يفتح في علامة تبويب جديدة) الذي تنشئه باستخدام مكتبة خارجية مثل Ethers.js دون معرفة مفتاحك الخاص (يفتح في علامة تبويب جديدة) ويكون واثقًا من أنك أنت من أنشأ التوقيع.
في الواقع، نظرًا لأن التوقيعات الرقمية للحسابات المملوكة خارجيًا (EOA) تستخدم علم التشفير بالمفتاح العام، يمكن إنشاؤها والتحقق منها خارج السلسلة! هكذا يعمل تصويت المنظمات المستقلة اللامركزية (DAO) بدون غاز — بدلاً من إرسال الأصوات على السلسلة، يمكن إنشاء التوقيعات الرقمية والتحقق منها خارج السلسلة باستخدام مكتبات علم التشفير.
بينما تحتوي حسابات EOA على مفتاح خاص، فإن حسابات العقود الذكية لا تحتوي على أي نوع من المفاتيح الخاصة أو السرية (لذلك لا يمكن لـ "تسجيل الدخول باستخدام إيثيريوم" وما إلى ذلك أن تعمل بشكل أصلي مع حسابات العقود الذكية).
المشكلة التي يهدف EIP-1271 إلى حلها: كيف يمكننا معرفة أن توقيع العقد الذكي صالح إذا لم يكن لدى العقد الذكي "سر" يمكنه دمجه في التوقيع؟
كيف يعمل EIP-1271؟
لا تحتوي العقود الذكية على مفاتيح خاصة يمكن استخدامها لتوقيع الرسائل. إذن كيف يمكننا معرفة ما إذا كان التوقيع أصليًا؟
حسنًا، إحدى الأفكار هي أنه يمكننا ببساطة سؤال العقد الذكي عما إذا كان التوقيع أصليًا!
ما يفعله EIP-1271 هو أنه يوحد فكرة "سؤال" العقد الذكي عما إذا كان توقيع معين صالحًا.
يجب أن يحتوي العقد الذي ينفذ EIP-1271 على دالة تسمى isValidSignature والتي تأخذ رسالة وتوقيعًا. يمكن للعقد بعد ذلك تشغيل بعض منطق التحقق (لا تفرض المواصفات أي شيء محدد هنا) ثم إرجاع قيمة تشير إلى ما إذا كان التوقيع صالحًا أم لا.
إذا أرجعت isValidSignature نتيجة صالحة، فهذا يعني إلى حد كبير أن العقد يقول "نعم، أنا أوافق على هذا التوقيع + الرسالة!"
الواجهة
إليك الواجهة الدقيقة في مواصفات EIP-1271 (سنتحدث عن المعلمة _hash أدناه، ولكن في الوقت الحالي، فكر فيها على أنها الرسالة التي يتم التحقق منها):
pragma solidity ^0.5.0;
contract ERC1271 {
// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 constant internal MAGICVALUE = 0x1626ba7e;
/**
* @dev يجب أن يُرجع ما إذا كان التوقيع المقدم صالحًا للتجزئة المقدمة
* @param _hash تجزئة البيانات المراد توقيعها
* @param _signature مصفوفة بايتات التوقيع المرتبطة بـ _hash
*
* يجب أن يُرجع القيمة السحرية bytes4 وهي 0x1626ba7e عند نجاح الدالة.
* يجب ألا يعدل الحالة (باستخدام STATICCALL لـ solc < 0.5، ومُعدِّل view لـ solc > 0.5)
* يجب أن يسمح بالاستدعاءات الخارجية
*/
function isValidSignature(
bytes32 _hash,
bytes memory _signature)
public
view
returns (bytes4 magicValue);
}
مثال على تنفيذ EIP-1271: Safe
يمكن للعقود تنفيذ isValidSignature بعدة طرق — المواصفات لا تقول الكثير عن التنفيذ الدقيق.
أحد العقود البارزة التي تنفذ EIP-1271 هو Safe (سابقًا Gnosis Safe).
في كود Safe، يتم تنفيذ (يفتح في علامة تبويب جديدة) isValidSignature بحيث يمكن إنشاء التوقيعات والتحقق منها بطريقتين (يفتح في علامة تبويب جديدة):
- الرسائل على السلسلة
- الإنشاء: يقوم مالك Safe بإنشاء معاملة Safe جديدة لـ "توقيع" رسالة، وتمرير الرسالة كبيانات في المعاملة. بمجرد أن يوقع عدد كافٍ من المالكين على المعاملة للوصول إلى حد متعدد التوقيعات، يتم بث المعاملة وتشغيلها. في المعاملة، توجد دالة Safe تسمى (
signMessage(bytes calldata _data)) والتي تضيف الرسالة إلى قائمة الرسائل "الموافق عليها". - التحقق: استدعاء
isValidSignatureعلى عقد Safe، وتمرير الرسالة للتحقق منها كمعلمة الرسالة وقيمة فارغة لمعلمة التوقيع (يفتح في علامة تبويب جديدة) (أي0x). سيرى Safe أن معلمة التوقيع فارغة وبدلاً من التحقق من التوقيع باستخدام علم التشفير، سيعرف أنه يجب عليه المضي قدمًا والتحقق مما إذا كانت الرسالة موجودة في قائمة الرسائل "الموافق عليها".
- الإنشاء: يقوم مالك Safe بإنشاء معاملة Safe جديدة لـ "توقيع" رسالة، وتمرير الرسالة كبيانات في المعاملة. بمجرد أن يوقع عدد كافٍ من المالكين على المعاملة للوصول إلى حد متعدد التوقيعات، يتم بث المعاملة وتشغيلها. في المعاملة، توجد دالة Safe تسمى (
- الرسائل خارج السلسلة:
- الإنشاء: يقوم مالك Safe بإنشاء رسالة خارج السلسلة، ثم يجعل مالكي Safe الآخرين يوقعون على الرسالة كل على حدة حتى يكون هناك عدد كافٍ من التوقيعات لتجاوز حد الموافقة متعدد التوقيعات.
- التحقق: استدعاء
isValidSignature. في معلمة الرسالة، قم بتمرير الرسالة المراد التحقق منها. في معلمة التوقيع، قم بتمرير التوقيعات الفردية لكل مالك Safe متسلسلة معًا، ظهرًا لظهر. سيتحقق Safe من وجود توقيعات كافية لتلبية الحد و أن كل توقيع صالح. إذا كان الأمر كذلك، فسيرجع قيمة تشير إلى نجاح التحقق من التوقيع.
ما هي بالضبط المعلمة _hash؟ لماذا لا يتم تمرير الرسالة بأكملها؟
ربما لاحظت أن الدالة isValidSignature في واجهة EIP-1271 (يفتح في علامة تبويب جديدة) لا تأخذ الرسالة نفسها، بل تأخذ بدلاً من ذلك المعلمة _hash. ما يعنيه هذا هو أنه بدلاً من تمرير الرسالة الكاملة ذات الطول العشوائي إلى isValidSignature، فإننا نمرر بدلاً من ذلك تجزئة بحجم 32 byte للرسالة (عمومًا keccak256).
كل بايت من بيانات الاستدعاء — أي بيانات معلمة الدالة التي يتم تمريرها إلى دالة العقد الذكي — يكلف 16 gas (4 gas إذا كان البايت صفرًا) (يفتح في علامة تبويب جديدة)، لذلك يمكن أن يوفر هذا الكثير من الغاز إذا كانت الرسالة طويلة.
مواصفات EIP-1271 السابقة
هناك مواصفات EIP-1271 قيد الاستخدام الفعلي تحتوي على دالة isValidSignature مع معلمة أولى من النوع bytes (طول عشوائي، بدلاً من طول ثابت bytes32) واسم المعلمة message. هذه نسخة أقدم (يفتح في علامة تبويب جديدة) من معيار EIP-1271.
كيف يجب تنفيذ EIP-1271 في عقودي الخاصة؟
المواصفات مفتوحة للغاية هنا. يحتوي تنفيذ Safe على بعض الأفكار الجيدة:
- يمكنك اعتبار توقيعات EOA من "مالك" العقد صالحة.
- يمكنك تخزين قائمة بالرسائل الموافق عليها واعتبارها فقط صالحة.
في النهاية، الأمر متروك لك كمطور للعقد!
الخاتمة
EIP-1271 (يفتح في علامة تبويب جديدة) هو معيار متعدد الاستخدامات يسمح للعقود الذكية بالتحقق من التوقيعات. إنه يفتح الباب أمام العقود الذكية للعمل بشكل أكبر مثل حسابات EOA — على سبيل المثال توفير طريقة لـ "تسجيل الدخول باستخدام إيثيريوم" للعمل مع العقود الذكية — ويمكن تنفيذه بعدة طرق (يحتوي Safe على تنفيذ مثير للاهتمام وغير بديهي يستحق النظر فيه).