Перейти до основного вмісту

EIP-1271: Підписання та перевірка підписів смарт-контрактів

eip-1271
смарт-контракти
перевірка
підписання
Середній рівень
Нейтан Х. Люн
12 січня 2023 р.
5 хвилин на читання

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

У цьому посібнику ми зробимо огляд цифрових підписів, передумов створення EIP-1271 та конкретної реалізації EIP-1271, яку використовує Safe (opens in a new tab) (раніше Gnosis Safe). Усе це разом може слугувати відправною точкою для реалізації EIP-1271 у ваших власних контрактах.

Що таке підпис?

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

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

  1. Повідомлення: «Я хочу увійти на цей вебсайт за допомогою свого гаманця Етеріум».
  2. Підписант: Моя адреса — 0x000…
  3. Доказ: Ось певний доказ того, що я, 0x000…, дійсно створив усе це повідомлення (зазвичай це щось криптографічне).

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

Чому? Наприклад, якби ви дали мені контракт на підпис, а потім я відрізав сторінку з підписом і повернув вам лише свої підписи без решти контракту, контракт був би недійсним.

Так само цифровий підпис нічого не означає без пов'язаного з ним повідомлення!

Чому існує EIP-1271?

Щоб створити цифровий підпис для використання в блокчейнах на базі Етеріуму, вам зазвичай потрібен секретний приватний ключ, якого більше ніхто не знає. Саме це робить ваш підпис вашим (ніхто інший не може створити такий самий підпис без знання секретного ключа).

Ваш акаунт Етеріум (тобто ваш зовнішній акаунт/EOA) має пов'язаний з ним приватний ключ, і саме цей приватний ключ зазвичай використовується, коли вебсайт або децентралізований застосунок (dapp) просить вас надати підпис (наприклад, для «Увійти за допомогою Етеріум»).

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

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

Хоча акаунти EOA мають приватний ключ, акаунти смарт-контрактів не мають жодного приватного або секретного ключа (тому «Увійти за допомогою Етеріум» тощо не може працювати з акаунтами смарт-контрактів за замовчуванням).

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

Як працює EIP-1271?

Смарт-контракти не мають приватних ключів, які можна використовувати для підписання повідомлень. Тож як ми можемо визначити, чи є підпис справжнім?

Ну, одна з ідей полягає в тому, що ми можемо просто запитати смарт-контракт, чи є підпис справжнім!

Те, що робить EIP-1271, — це стандартизація цієї ідеї «запитування» смарт-контракту про те, чи є даний підпис дійсним.

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

Якщо isValidSignature повертає дійсний результат, це фактично означає, що контракт каже: «Так, я схвалюю цей підпис + повідомлення!»

Інтерфейс

Ось точний інтерфейс у специфікації EIP-1271 (ми поговоримо про параметр _hash нижче, але поки що сприймайте його як повідомлення, що перевіряється):

Приклад реалізації 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).

Кожен байт даних виклику — тобто даних параметрів функції, переданих у функцію смарт-контракту, — коштує 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 — наприклад, забезпечуючи спосіб роботи «Увійти за допомогою Етеріум» зі смарт-контрактами — і його можна реалізувати багатьма способами (Safe має нетривіальну, цікаву реалізацію для розгляду).