Перейти к основному содержанию

EIP-1271: Подписание и проверка подписей умных контрактов

eip-1271
смарт-контракты
проверка
подписание
Intermediate
Nathan H. Leung
12 января 2023 г.
6 минута прочтения

Стандарт EIP-1271 (opens in a new tab) позволяет умным контрактам проверять подписи.

В этом руководстве мы даем обзор цифровых подписей, предыстории EIP-1271 и конкретной реализации EIP-1271, используемой Safe (opens in a new tab) (ранее Gnosis Safe). В совокупности это может послужить отправной точкой для реализации EIP-1271 в ваших собственных контрактах.

Что такое подпись?

В данном контексте подпись (точнее, «цифровая подпись») — это сообщение плюс некое доказательство того, что сообщение пришло от определенного человека/отправителя/адреса.

Например, цифровая подпись может выглядеть так:

  1. Сообщение: «Я хочу войти на этот сайт с помощью своего кошелька Ethereum».
  2. Подписавший: Мой адрес 0x000…
  3. Доказательство: Вот доказательство того, что я, 0x000…, действительно создал все это сообщение (обычно это нечто криптографическое).

Важно отметить, что цифровая подпись включает в себя и «сообщение», и «подпись».

Почему? Например, если бы вы дали мне на подпись контракт, а я бы отрезал страницу с подписью и вернул вам только свои подписи без остальной части контракта, контракт не был бы действительным.

Точно так же цифровая подпись ничего не значит без связанного с ней сообщения!

Почему существует EIP-1271?

Чтобы создать цифровую подпись для использования в блокчейнах на базе Ethereum, вам обычно нужен секретный приватный ключ, который никто больше не знает. Это то, что делает вашу подпись вашей (никто другой не может создать такую же подпись, не зная секретного ключа).

Ваш аккаунт Ethereum (т. е. ваш аккаунт во внешнем владении / EOA) имеет связанный с ним приватный ключ, и это тот приватный ключ, который обычно используется, когда веб-сайт или децентрализованное приложение запрашивает у вас подпись (например, для «Входа с помощью Ethereum»).

Приложение может проверить подпись (opens in a new tab), которую вы создали, с помощью сторонней библиотеки, такой как ethers.js, не зная вашего приватного ключа (opens in a new tab) и быть уверенным, что именно вы создали подпись.

На самом деле, поскольку цифровые подписи EOA используют криптографию с открытым ключом, их можно генерировать и проверять офчейн! Именно так работает безгазовое голосование в DAO — вместо того, чтобы отправлять голоса ончейн, цифровые подписи могут создаваться и проверяться офчейн с помощью криптографических библиотек.

В то время как аккаунты EOA имеют приватный ключ, аккаунты умных контрактов не имеют никакого приватного или секретного ключа (поэтому «Вход с помощью Ethereum» и т. п. не может нативно работать с аккаунтами умных контрактов).

Проблема, которую призван решить EIP-1271: как мы можем определить, что подпись умного контракта действительна, если у умного контракта нет «секрета», который он может включить в подпись?

Как работает EIP-1271?

Умные контракты не имеют приватных ключей, которые можно использовать для подписи сообщений. Так как же мы можем определить, является ли подпись подлинной?

Что ж, одна из идей заключается в том, что мы можем просто спросить у умного контракта, является ли подпись подлинной!

EIP-1271 стандартизирует идею «запроса» у умного контракта о действительности данной подписи.

Контракт, реализующий EIP-1271, должен иметь функцию isValidSignature, которая принимает сообщение и подпись. Затем контракт может запустить некоторую логику проверки (спецификация не предписывает здесь ничего конкретного) и вернуть значение, указывающее, действительна ли подпись.

Если isValidSignature возвращает действительный результат, это практически означает, что контракт говорит: «да, я одобряю эту подпись + сообщение!»

Интерфейс

Вот точный интерфейс в спецификации EIP-1271 (мы поговорим о параметре _hash ниже, но пока думайте о нем как о проверяемом сообщении):

1pragma solidity ^0.5.0;
2
3contract ERC1271 {
4
5 // bytes4(keccak256("isValidSignature(bytes32,bytes)")
6 bytes4 constant internal MAGICVALUE = 0x1626ba7e;
7
8 /**
9 * @dev Должна возвращать, является ли предоставленная подпись действительной для предоставленного хэша
10 * @param _hash Хэш данных для подписи
11 * @param _signature Массив байтов подписи, связанный с _hash
12 *
13 * ДОЛЖНА возвращать магическое значение bytes4 0x1626ba7e при успешном выполнении функции.
14 * НЕ ДОЛЖНА изменять состояние (с использованием STATICCALL для solc < 0.5, модификатора view для solc > 0.5)
15 * ДОЛЖНА разрешать внешние вызовы
16 */
17 function isValidSignature(
18 bytes32 _hash,
19 bytes memory _signature)
20 public
21 view
22 returns (bytes4 magicValue);
23}
Показать все

Пример реализации EIP-1271: Safe

Контракты могут реализовывать isValidSignature многими способами — спецификация не говорит много о точной реализации.

Одним из примечательных контрактов, реализующих EIP-1271, является Safe (ранее Gnosis Safe).

В коде Safe функция isValidSignature реализована (opens in a new tab) так, что подписи можно создавать и проверять двумя способами (opens in a new tab):

  1. Ончейн-сообщения
    1. Создание: владелец Safe создает новую транзакцию Safe, чтобы «подписать» сообщение, передавая сообщение в качестве данных в транзакцию. Как только достаточное количество владельцев подпишет транзакцию для достижения порога мультиподписи, транзакция транслируется и выполняется. В транзакции есть функция Safe (signMessage(bytes calldata _data)), которая добавляет сообщение в список «одобренных» сообщений.
    2. Проверка: вызовите isValidSignature в контракте Safe и передайте сообщение для проверки в качестве параметра сообщения, а пустое значение для параметра подписи (opens in a new tab) (т. е. 0x). Safe увидит, что параметр подписи пуст, и вместо криптографической проверки подписи он просто проверит, находится ли сообщение в списке «одобренных» сообщений.
  2. Офчейн-сообщения:
    1. Создание: владелец Safe создает сообщение офчейн, затем получает подписи от других владельцев Safe по отдельности, пока не будет достаточно подписей для преодоления порога одобрения мультиподписи.
    2. Проверка: вызовите isValidSignature. В параметр сообщения передайте сообщение, которое нужно проверить. В параметр подписи передайте все индивидуальные подписи владельцев Safe, объединенные вместе, одна за другой. Safe проверит, что подписей достаточно для достижения порога и что каждая подпись действительна. Если это так, он вернет значение, указывающее на успешную проверку подписи.

Что именно представляет собой параметр _hash? Почему бы не передать все сообщение целиком?

Вы могли заметить, что функция isValidSignature в интерфейсе EIP-1271 (opens in a new tab) принимает не само сообщение, а параметр _hash. Это означает, что вместо передачи полного сообщения произвольной длины в isValidSignature мы передаем 32-байтовый хэш сообщения (обычно keccak256).

Каждый байт calldata — т. е. данных параметров функции, передаваемых в функцию умного контракта — стоит 16 единиц газа (4 единицы газа, если это нулевой байт) (opens in a new tab), так что это может сэкономить много газа, если сообщение длинное.

Предыдущие спецификации EIP-1271

Существуют спецификации EIP-1271, в которых функция isValidSignature имеет первый параметр типа bytes (произвольной длины, вместо фиксированной длины bytes32) и имя параметра message. Это более старая версия (opens in a new tab) стандарта EIP-1271.

Как следует реализовывать EIP-1271 в моих собственных контрактах?

Здесь спецификация очень открыта. Реализация Safe содержит несколько хороших идей:

  • Вы можете считать подписи EOA от «владельца» контракта действительными.
  • Вы можете хранить список одобренных сообщений и считать действительными только их.

В конце концов, это зависит от вас как от разработчика контракта!

Заключение

EIP-1271 (opens in a new tab) — это универсальный стандарт, который позволяет умным контрактам проверять подписи. Он открывает возможность для умных контрактов действовать больше как EOA — например, предоставляя способ для «Входа с помощью Ethereum» работать с умными контрактами — и может быть реализован многими способами (Safe имеет нетривиальную, интересную реализацию для рассмотрения).

Последнее обновление страницы: 16 января 2026 г.

Было ли это руководство полезным?