WEB3DEV

Cover image for EIP-1271: ASSINANDO E VERIFICANDO ASSINATURAS DE CONTRATOS INTELIGENTES
Fatima Lima
Fatima Lima

Posted on

EIP-1271: ASSINANDO E VERIFICANDO ASSINATURAS DE CONTRATOS INTELIGENTES

O padrão EIP-1271 permite a verificação de assinaturas pelos contratos inteligentes.

Neste tutorial, apresentamos uma visão geral das assinaturas digitais, o histórico e a implementação específica da EIP-1271 usada pelo Safe (anteriormente Gnosis Safe). Em resumo, isso pode servir como ponto de partida para implementação da EIP-1271 em seus próprios contratos.

O QUE É UMA ASSINATURA?

Nesse contexto, uma assinatura (mais precisamente, uma "assinatura digital") é uma mensagem mais algum tipo de prova de que a mensagem veio de uma pessoa/remetente/endereço específico.

Por exemplo, uma assinatura digital pode ter a seguinte aparência:

  1. Mensagem: “Quero fazer login neste site com minha carteira Ethereum.”
  2. Signatário: Meu endereço é 0x000…
  3. Prova: Aqui está uma prova de que eu, 0x000..., realmente criei toda essa mensagem (isso geralmente é algo criptográfico).

É importante observar que uma assinatura digital inclui tanto uma "mensagem" quanto uma "assinatura".

Por quê? Por exemplo, se você me desse um contrato para assinar e eu cortasse a página de assinatura e lhe devolvesse apenas as minhas assinaturas, sem o restante do contrato, o contrato não seria válido.

Da mesma forma, uma assinatura digital não significa nada sem uma mensagem associada!

POR QUE A EIP-1271 EXISTE?

Para criar uma assinatura digital para uso em blockchains baseados em Ethereum, você geralmente precisa de uma chave privada secreta que ninguém mais conhece. Isso é o que torna a assinatura sua (ninguém mais pode criar a mesma assinatura sem o conhecimento da chave secreta).

Sua conta Ethereum (ou seja, sua conta de propriedade externa /EOA) tem uma chave privada associada a ela e essa é a chave privada que normalmente é usada quando um site ou aplicativo solicita uma assinatura (por exemplo, para "Log in with Ethereum").

Um app pode verificar uma assinatura que você cria usando uma biblioteca de terceiros, como a ethers.js sem conhecer sua chave privada e estar seguro de que foi você quem criou a assinatura.

De fato, como as assinaturas digitais EOA usam criptografia de chave pública, elas podem ser geradas e verificadas off-chain (fora da cadeia)! É assim que funciona a votação DAO sem gas - em vez de enviar votos on-chain ( na cadeia ), as assinaturas digitais podem ser criadas e verificadas off-chain usando bibliotecas criptográficas.

Enquanto as contas EOA têm uma chave privada, as contas de contrato inteligente não têm nenhum tipo de chave privada ou secreta (portanto, "Log in with Ethereum" (Fazer login com Ethereum) etc. não funciona nativamente com contas de contrato inteligente).

O problema que a EIP-1271 pretende resolver: como podemos saber que uma assinatura de contrato inteligente é válida se o contrato inteligente não tem nenhum "segredo" que possa ser incorporado à assinatura?

COMO A EIP-1271 FUNCIONA?

Os contratos inteligentes não têm chaves privadas que possam ser usadas para assinar mensagens. Então, como podemos saber se uma assinatura é autêntica?

Bem, uma ideia é que podemos simplesmente perguntar ao contrato inteligente se uma assinatura é autêntica!

O que a EIP-1271 faz é padronizar essa ideia de "perguntar" a um contrato inteligente se uma determinada assinatura é válida.

Um contrato que implemente a EIP-1271 deve ter uma função chamada isValidSignature que recebe uma mensagem e uma assinatura. O contrato pode, então, executar alguma lógica de validação (a especificação não impõe nada específico aqui) e, em seguida, retornar um valor indicando se a assinatura é válida ou não.

Se a isValidSignature retorna um resultado válido, isso é basicamente o contrato dizendo "sim, eu aprovo essa assinatura + mensagem!”

Interface

Esta é a interface exata na especificação EIP-1271 (falaremos sobre o parâmetro _hash abaixo, mas, por enquanto, pense nele como a mensagem que está sendo verificada):

pragma solidity ^0.5.0;

contract ERC1271 {
 // bytes4(keccak256("isValidSignature(bytes32,bytes)")

 bytes4 constant internal MAGICVALUE = 0x1626ba7e;


 /**

  * @dev Deve retornar se a assinatura fornecida é válida para o hash fornecido

  * @param _hash      Hash dos dados a serem assinados

  * @param _signature Array de bytes de assinatura associado a _hash

  *

  * DEVE retornar o valor mágico 0x1626ba7e do bytes4 quando a função é aprovada

  * NÃO DEVE modificar o estado (usando STATICCALL para solc < 0,5, modificador de visualização para solc > 0,5)

  * DEVE permitir chamadas externas

  */

 function isValidSignature(

   bytes32 _hash,

   bytes memory _signature)

   public

   view

   returns (bytes4 magicValue);

}
Enter fullscreen mode Exit fullscreen mode

EXEMPLO DE IMPLEMENTAÇÃO EIP-1271: SAFE

Contratos podem implementar a isValidSignature de várias formas —A especificação apenas não diz muito sobre a implementação exata.

Um contrato notável que implementa a EIP-1271 é o Safe (anteriormente Gnosis Safe).

No código do Safe, isValidSignature está implementada de forma que as assinaturas possam ser criadas e verificadas de duas formas:

  1. Mensagens on-chain
    1. Criação: um proprietário do safe cria uma nova transação segura para "assinar" uma mensagem, passando a mensagem como dados para a transação. Quando um número suficiente de proprietários assinar a transação para atingir o limite de multisig (assinaturas múltiplas), a transação será transmitida e executada. Na transação, há uma função safe (segura) chamada que adiciona a mensagem a uma lista de mensagens "aprovadas".
    2. Verificação: chamar a isValidSignature. No parâmetro message (mensagem), passar a mensagem para ser verificada. No parâmetro signature (assinatura) fazer a verificação como o parâmetro message e um valor vazio para o parâmetro signature (i.e. 0x). O Safe verá que o parâmetro signature está vazio e, em vez de verificar criptograficamente a assinatura, ele saberá que deve simplesmente verificar se a mensagem está na lista de mensagens "aprovadas".
  2. Mensagens Off-chain:
    1. Criação: Um proprietário safe cria uma mensagem off-chain e, em seguida, faz com que outros proprietários safe assinem a mensagem individualmente até que haja assinaturas suficientes para superar o limite de aprovação multisig.
    2. Verificação: chamar a isValidSignature. No parâmetro message, passe a mensagem a ser verificada. No parâmetro signature (assinatura), passe as assinaturas individuais de cada proprietário safe, todas concatenadas juntas, consecutivas. O Safe verificará se há assinaturas suficientes para atingir o limite e se cada assinatura é válida. Em caso afirmativo, ele retornará um valor indicando que a verificação da assinatura foi bem-sucedida.

O QUE É REALMENTE O PARÂMETRO _HASH? POR QUE NÃO PASSAR A MENSAGEM COMPLETA?

Você deve ter observado que a função isValidSignature na interface da EIP-1271 não recebe a mensagem em si, mas sim um parâmetro _hash. Isso significa que, em vez de passar a mensagem completa de comprimento arbitrário para isValidSignature, passamos um hash de 32 bytes da mensagem (geralmente keccak256).

Cada byte de calldata - ou seja, dados de parâmetro de função passados para uma função de contrato inteligente - custa 16 de gas (4 de gas se for zero byte), portanto, isso pode economizar muito gas se a mensagem for longa.

Especificações EIP-1271 anteriores

Há especificações EIP-1271 disponíveis que têm uma função isValidSignature com um primeiro parâmetro do tipo bytes (de comprimento arbitrário, em vez de um comprimento fixo de bytes32) e nome de parâmetro message. É uma versão mais antiga do padrão EIP-1271.

COMO A EIP-1271 DEVE SER IMPLEMENTADA EM MEUS PRÓPRIOS CONTRATOS?

A especificação é muito aberta nesse ponto. A implementação do Safe tem algumas boas ideias:

  • Você pode considerar válidas as assinaturas de EOA do "proprietário" do contrato.
  • Você poderia armazenar uma lista de mensagens aprovadas e considerar apenas as válidas.

No final, é com você, como desenvolvedor do contrato!

CONCLUSÃO

O EIP-1271 é um padrão versátil que permite que contratos inteligentes verifiquem assinaturas. Ele abre a porta para que os contratos inteligentes atuem mais como EOAs - por exemplo, fornecendo uma maneira de "Log in with Ethereum" funcionar com contratos inteligentes - e pode ser implementado de várias maneiras (O Safe tem uma implementação interessante e não trivial a ser considerada).

Esse artigo foi escrito por Nathan H. Leung e traduzido por Fátima Lima. O original pode ser lido aqui.

Latest comments (0)