---
title: "⁦EIP-1271⁩: توقيع والتحقق من توقيعات العقود الذكية"
description: "نظرة عامة على إنشاء توقيع العقد الذكي والتحقق منه باستخدام ⁦EIP-1271⁩. نستعرض أيضًا تنفيذ ⁦EIP-1271⁩ المستخدم في Safe (سابقًا Gnosis Safe) لتقديم مثال عملي لمطوري العقود الذكية للبناء عليه."
author: "ناثان إتش. ليونغ"
lang: ar
tags: ["eip-1271", "العقود الذكية", "التحقق", "التوقيع"]
skill: intermediate
breadcrumb: "توقيعات ⁦EIP-1271⁩"
published: 2023-01-12
---

يتيح معيار [<span dir="ltr">EIP-1271</span>](https://eips.ethereum.org/EIPS/eip-1271) للعقود الذكية التحقق من التوقيعات.

في هذا البرنامج التعليمي، نقدم نظرة عامة على التوقيعات الرقمية، وخلفية <span dir="ltr">EIP-1271</span>، والتنفيذ المحدد لـ <span dir="ltr">EIP-1271</span> المستخدم بواسطة [<span dir="ltr">Safe</span>](https://safe.global/) (سابقًا <span dir="ltr">Gnosis Safe</span>). يمكن أن يكون هذا بمثابة نقطة انطلاق لتنفيذ <span dir="ltr">EIP-1271</span> في عقودك الخاصة.

## ما هو التوقيع؟ {#what-is-a-signature}

في هذا السياق، التوقيع (وبشكل أدق، "التوقيع الرقمي") هو رسالة بالإضافة إلى نوع من الإثبات على أن الرسالة جاءت من شخص/مرسل/عنوان محدد.

على سبيل المثال، قد يبدو التوقيع الرقمي هكذا:

1. الرسالة: "أريد تسجيل الدخول إلى هذا الموقع باستخدام محفظة إيثيريوم الخاصة بي."
2. المُوقِّع: عنواني هو `0x000…`
3. الإثبات: إليك بعض الإثباتات على أنني، `0x000…`، قمت بالفعل بإنشاء هذه الرسالة بالكامل (عادةً ما يكون هذا شيئًا متعلقًا بعلم التشفير).

من المهم ملاحظة أن التوقيع الرقمي يتضمن كلاً من "رسالة" و"توقيع".

لماذا؟ على سبيل المثال، إذا أعطيتني عقدًا لأوقعه، ثم قمت بقطع صفحة التوقيع وأعدت لك توقيعاتي فقط دون بقية العقد، فلن يكون العقد صالحًا.

وبنفس الطريقة، لا يعني التوقيع الرقمي أي شيء بدون رسالة مرتبطة به!

## لماذا يوجد <span dir="ltr">EIP-1271</span>؟ {#why-does-eip-1271-exist}

من أجل إنشاء توقيع رقمي لاستخدامه على سلاسل الكتل القائمة على إيثيريوم، تحتاج عمومًا إلى مفتاح خاص سري لا يعرفه أحد غيرك. هذا ما يجعل توقيعك خاصًا بك (لا يمكن لأي شخص آخر إنشاء نفس التوقيع دون معرفة المفتاح السري).

يحتوي حساب إيثيريوم الخاص بك (أي حسابك المملوك خارجيًا/<span dir="ltr">EOA</span>) على مفتاح خاص مرتبط به، وهذا هو المفتاح الخاص الذي يُستخدم عادةً عندما يطلب منك موقع ويب أو تطبيق لامركزي (dapp) توقيعًا (على سبيل المثال، من أجل "تسجيل الدخول باستخدام إيثيريوم").

يمكن للتطبيق [التحقق من التوقيع](https://www.alchemy.com/docs/how-to-verify-a-message-signature-on-ethereum) الذي تنشئه باستخدام مكتبة خارجية مثل <span dir="ltr">Ethers.js</span> [دون معرفة مفتاحك الخاص](https://en.wikipedia.org/wiki/Public-key_cryptography) ويكون واثقًا من أنك _أنت_ من أنشأ التوقيع.

> في الواقع، نظرًا لأن التوقيعات الرقمية للحسابات المملوكة خارجيًا (<span dir="ltr">EOA</span>) تستخدم علم التشفير بالمفتاح العام، يمكن إنشاؤها والتحقق منها **خارج السلسلة**! هكذا يعمل تصويت المنظمات المستقلة اللامركزية (<span dir="ltr">DAO</span>) بدون غاز — بدلاً من إرسال الأصوات على السلسلة، يمكن إنشاء التوقيعات الرقمية والتحقق منها خارج السلسلة باستخدام مكتبات علم التشفير.

بينما تحتوي حسابات <span dir="ltr">EOA</span> على مفتاح خاص، فإن حسابات العقود الذكية لا تحتوي على أي نوع من المفاتيح الخاصة أو السرية (لذلك لا يمكن لـ "تسجيل الدخول باستخدام إيثيريوم" وما إلى ذلك أن تعمل بشكل أصلي مع حسابات العقود الذكية).

المشكلة التي يهدف <span dir="ltr">EIP-1271</span> إلى حلها: كيف يمكننا معرفة أن توقيع العقد الذكي صالح إذا لم يكن لدى العقد الذكي "سر" يمكنه دمجه في التوقيع؟

## كيف يعمل <span dir="ltr">EIP-1271</span>؟ {#how-does-eip-1271-work}

لا تحتوي العقود الذكية على مفاتيح خاصة يمكن استخدامها لتوقيع الرسائل. إذن كيف يمكننا معرفة ما إذا كان التوقيع أصليًا؟

حسنًا، إحدى الأفكار هي أنه يمكننا ببساطة _سؤال_ العقد الذكي عما إذا كان التوقيع أصليًا!

ما يفعله <span dir="ltr">EIP-1271</span> هو أنه يوحد فكرة "سؤال" العقد الذكي عما إذا كان توقيع معين صالحًا.

يجب أن يحتوي العقد الذي ينفذ <span dir="ltr">EIP-1271</span> على دالة تسمى `isValidSignature` والتي تأخذ رسالة وتوقيعًا. يمكن للعقد بعد ذلك تشغيل بعض منطق التحقق (لا تفرض المواصفات أي شيء محدد هنا) ثم إرجاع قيمة تشير إلى ما إذا كان التوقيع صالحًا أم لا.

إذا أرجعت `isValidSignature` نتيجة صالحة، فهذا يعني إلى حد كبير أن العقد يقول "نعم، أنا أوافق على هذا التوقيع + الرسالة!"

### الواجهة {#interface}

إليك الواجهة الدقيقة في مواصفات <span dir="ltr">EIP-1271</span> (سنتحدث عن المعلمة `_hash` أدناه، ولكن في الوقت الحالي، فكر فيها على أنها الرسالة التي يتم التحقق منها):

```jsx
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);
}
```

## مثال على تنفيذ <span dir="ltr">EIP-1271</span>: <span dir="ltr">Safe</span> {#example-eip-1271-implementation-safe}

يمكن للعقود تنفيذ `isValidSignature` بعدة طرق — المواصفات لا تقول الكثير عن التنفيذ الدقيق.

أحد العقود البارزة التي تنفذ <span dir="ltr">EIP-1271</span> هو <span dir="ltr">Safe</span> (سابقًا <span dir="ltr">Gnosis Safe</span>).

في كود <span dir="ltr">Safe</span>، [يتم تنفيذ](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol) `isValidSignature` بحيث يمكن إنشاء التوقيعات والتحقق منها [بطريقتين](https://ethereum.stackexchange.com/questions/122635/signing-messages-as-a-gnosis-safe-eip1271-support):

1. الرسائل على السلسلة
   1. الإنشاء: يقوم مالك <span dir="ltr">Safe</span> بإنشاء معاملة <span dir="ltr">Safe</span> جديدة لـ "توقيع" رسالة، وتمرير الرسالة كبيانات في المعاملة. بمجرد أن يوقع عدد كافٍ من المالكين على المعاملة للوصول إلى حد متعدد التوقيعات، يتم بث المعاملة وتشغيلها. في المعاملة، توجد دالة <span dir="ltr">Safe</span> تسمى (`signMessage(bytes calldata _data)`) والتي تضيف الرسالة إلى قائمة الرسائل "الموافق عليها".
   2. التحقق: استدعاء `isValidSignature` على عقد <span dir="ltr">Safe</span>، وتمرير الرسالة للتحقق منها كمعلمة الرسالة و[قيمة فارغة لمعلمة التوقيع](https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L32) (أي `0x`). سيرى <span dir="ltr">Safe</span> أن معلمة التوقيع فارغة وبدلاً من التحقق من التوقيع باستخدام علم التشفير، سيعرف أنه يجب عليه المضي قدمًا والتحقق مما إذا كانت الرسالة موجودة في قائمة الرسائل "الموافق عليها".
2. الرسائل خارج السلسلة:
   1. الإنشاء: يقوم مالك <span dir="ltr">Safe</span> بإنشاء رسالة خارج السلسلة، ثم يجعل مالكي <span dir="ltr">Safe</span> الآخرين يوقعون على الرسالة كل على حدة حتى يكون هناك عدد كافٍ من التوقيعات لتجاوز حد الموافقة متعدد التوقيعات.
   2. التحقق: استدعاء `isValidSignature`. في معلمة الرسالة، قم بتمرير الرسالة المراد التحقق منها. في معلمة التوقيع، قم بتمرير التوقيعات الفردية لكل مالك <span dir="ltr">Safe</span> متسلسلة معًا، ظهرًا لظهر. سيتحقق <span dir="ltr">Safe</span> من وجود توقيعات كافية لتلبية الحد **و** أن كل توقيع صالح. إذا كان الأمر كذلك، فسيرجع قيمة تشير إلى نجاح التحقق من التوقيع.

## ما هي بالضبط المعلمة `_hash`؟ لماذا لا يتم تمرير الرسالة بأكملها؟ {#what-exactly-is-the-hash-parameter-why-not-pass-the-whole-message}

ربما لاحظت أن الدالة `isValidSignature` في [واجهة <span dir="ltr">EIP-1271</span>](https://eips.ethereum.org/EIPS/eip-1271) لا تأخذ الرسالة نفسها، بل تأخذ بدلاً من ذلك المعلمة `_hash`. ما يعنيه هذا هو أنه بدلاً من تمرير الرسالة الكاملة ذات الطول العشوائي إلى `isValidSignature`، فإننا نمرر بدلاً من ذلك تجزئة بحجم <span dir="ltr">32 byte</span> للرسالة (عمومًا <span dir="ltr">keccak256</span>).

كل بايت من بيانات الاستدعاء — أي بيانات معلمة الدالة التي يتم تمريرها إلى دالة العقد الذكي — [يكلف <span dir="ltr">16 gas</span> (<span dir="ltr">4 gas</span> إذا كان البايت صفرًا)](https://eips.ethereum.org/EIPS/eip-2028)، لذلك يمكن أن يوفر هذا الكثير من الغاز إذا كانت الرسالة طويلة.

### مواصفات <span dir="ltr">EIP-1271</span> السابقة {#previous-eip-1271-specifications}

هناك مواصفات <span dir="ltr">EIP-1271</span> قيد الاستخدام الفعلي تحتوي على دالة `isValidSignature` مع معلمة أولى من النوع `bytes` (طول عشوائي، بدلاً من طول ثابت `bytes32`) واسم المعلمة `message`. هذه [نسخة أقدم](https://github.com/safe-global/safe-contracts/issues/391#issuecomment-1075427206) من معيار <span dir="ltr">EIP-1271</span>.

## كيف يجب تنفيذ <span dir="ltr">EIP-1271</span> في عقودي الخاصة؟ {#how-should-eip-1271-be-implemented-in-my-own-contracts}

المواصفات مفتوحة للغاية هنا. يحتوي تنفيذ <span dir="ltr">Safe</span> على بعض الأفكار الجيدة:

- يمكنك اعتبار توقيعات <span dir="ltr">EOA</span> من "مالك" العقد صالحة.
- يمكنك تخزين قائمة بالرسائل الموافق عليها واعتبارها فقط صالحة.

في النهاية، الأمر متروك لك كمطور للعقد!

## الخاتمة {#conclusion}

[<span dir="ltr">EIP-1271</span>](https://eips.ethereum.org/EIPS/eip-1271) هو معيار متعدد الاستخدامات يسمح للعقود الذكية بالتحقق من التوقيعات. إنه يفتح الباب أمام العقود الذكية للعمل بشكل أكبر مثل حسابات <span dir="ltr">EOA</span> — على سبيل المثال توفير طريقة لـ "تسجيل الدخول باستخدام إيثيريوم" للعمل مع العقود الذكية — ويمكن تنفيذه بعدة طرق (يحتوي <span dir="ltr">Safe</span> على تنفيذ مثير للاهتمام وغير بديهي يستحق النظر فيه).