WEB3DEV Español

Cover image for EIP-1271: Firmando y Verificando Firmas de Contratos Inteligentes
Hector
Hector

Posted on

EIP-1271: Firmando y Verificando Firmas de Contratos Inteligentes

El estándar EIP-1271 permite a los contratos inteligentes verificar firmas.

En este tutorial, te daremos un vistazo sobre las firmas digitales, el trasfondo del EPI-1271 y la implementación específica del EIP-1271 usado por Safe (conocido previamente como Gnosis Safe). Todo esto puede servirte como un punto de partida para implementar el EIP-1271 en tus propios contratos.

¿Qué es una Firma?

En este contexto, una firma (más precisamente una “firma digital”) es un mensaje además de algún tipo de prueba que el mensaje vino de una persona/remitente/dirección específica.

Por ejemplo, una firma digital puede verse así:

  1. Mensaje: “Quiero iniciar sesión en esta página web con mi billetera Ethereum”
  2. Firmante: Mi dirección es 0x000…
  3. Prueba: Aquí hay alguna prueba que yo, 0x000…, creé este mensaje (esto es algo, usualmente, criptográfico)

Es importante tomar en cuenta que una firma digital incluye ambos un “mensaje” y una “firma”.

¿Por qué? Por ejemplo, si me das un contrato para firmar y luego corto la página de la firma y te la devuelvo, sólo con mis firmas y sin el resto del contrato, el contrato no sería válido.

De la misma forma, ¡una firma digital no significa nada sin el mensaje asociado!

¿Por qué EIP-1271 existe?

Para poder crear una firma digital para usarla en blockchains basadas en Ethereum, generalmente necesitas una clave privada secreta, que nadie más sabe. Esto es lo que hace que tu firma sea tuya (nadie más puede crear la misma firma sin tener conocimiento de la clave secreta).

Tu cuenta ethereum (por ejemplo, tu cuenta externa/EOA) tiene una clave privada asociada con ella, y esta es la clave privada que es usada típicamente cuando una página web o dapp te pide una firma (por ejemplo “Abre tu sesión con Ethereum”).

Una app puede verificar una firma que creas, usando una biblioteca de terceros como ethers.js sin conocer tu clave privada y tener la confianza que fuiste tú el que creo la firma.

De hecho, porque las firmas digitales EOA usan una clave privada criptográfica, ¡pueden ser generadas y verificadas fuera de la cadena! Así es como las votaciones sin gas funcionan: en vez de realizar los votos en la cadena, las firmas digitales pueden ser creadas y verificadas fuera de la cadena usando bibliotecas criptográficas.

Mientras que las cuentas EOA tienen claves privadas, las cuentas de los contratos inteligentes no tienen ningún tipo de clave privada o secreta (así que “Abre tu sesión con Ethereum”, etc. no puede trabajar de forma nativa con cuentas de contratos inteligentes).

El problema que el EIP-1271 apunta a resolver es: ¿cómo podemos saber si una firma de un trato inteligente es válida, si el contrato inteligente no tiene un “secreto” que pueda incorporar en la firma?

¿Cómo funciona el EIP-1271?

Los contratos inteligentes no tienen claves privadas que puedan usar mensajes firmados. Así que, ¿cómo podemos saber si una firma es auténtica?

Bueno, una idea es que ¡podemos pedirle al contrato inteligente si una firma es auténtica!

Lo que el EIP-1271 hace es estandarizar la idea de “pedirle” a un contrato inteligente si cierta firma es válida.

Un contrato que implementa el EIP-1271 debe tener una función llamada isValidSignature, el cual toma un mensaje y la firma. El contrato, entonces, puede ejecutar algunas lógicas de validación (la especificación no hace cumplir nada específico aquí) y luego retorna el valor, indicando si la firma es válida o no.

Si isValidSignature retorna un resultado válido, es prácticamente el contrato diciendo “si, apruebo esta firma y el mensaje”.

Interfaz

Aquí está la interfaz exacta de las especificaciones EIP-1271 (hablaremos sobre el parámetro _hashabajo, pero por ahora, piensa en ello como el mensaje que está siendo verificado):

pragma solidity ^0.5.0;

contract ERC1271 {

 // bytes4(keccak256("isValidSignature(bytes32,bytes)")

 bytes4 constant internal MAGICVALUE = 0x1626ba7e;

 /**

  * @dev Debería regresar si la firma proveída es válida por el hash proveído

  * @param _hash      El hash de los datos a ser firmados

  * @param _signature El array de la firma del byte, asociada con _hash

  *

  * DEBEN regresar al valor mágico bytes4 0x1626ba7e cuando la función pasa.

  * NO DEBE modificar el estado (usando STATICCALL para solc < 0.5, mira el modificador solc > 0.5)

  * DEBE permitir llamadas externas

  */


 function isValidSignature(

   bytes32 _hash,

   bytes memory _signature)

   public

   view

   returns (bytes4 magicValue);

}

Enter fullscreen mode Exit fullscreen mode

Ejemplo de Implementación EIP-1271: SAFE

Los contratos pueden implementar isValidSignature de muchas formas: sólo la especificación no dice mucho sobre la implementación exacta.

Un contrato notable que implementa EIP-1271 es Safe (conocida anteriormente Gnosis Safe).

El código Safe, isValidSignature es implementado así que las firmas pueden ser creadas y verificadas de dos formas:

  1. Mensajes en la Cadena

    1. Creación: un dueño de safe crea una nueva transacción safe para “firmar” un mensaje, pasando el mensaje como datos, en la transacción. Una vez que suficientes dueños firmen la transacción para llegar al umbral multisig, la transacción es transmitida y ejecutada. En la transacción, hay una función safe invocada, la cual añade el mensaje a una lista de mensajes “aprobados’.
    2. Verificación: llama isValidSignature en el contrato Safe, y pasa el mensaje para verificar como el parámetro del mensaje y un valor vacío para el parámetro de la firma (es decir, 0x). Safe verá que el parámetro de la firma está vacío y en vez de verificar la firma criptográfica, sabrá que sólo tiene que seguir y revisar si el mensaje está en la lista de mensajes “aprobados”.
  2. Mensajes fuera de la Cadena:

    1. Creación: un dueño de safe crea un mensaje fuera de la cadena, luego otros dueños de safe firman el mensaje individualmente hasta que hayan suficientes firmas para sobreponer el umbral para aprobar el multisig.
    2. Verificación: llama isValidSignature. En el parámetro del mensaje, pasa el mensaje para ser verificado. En la firma del parámetro, pasa en cada firma individual de los dueños, todos juntos y concatenados, de forma consecutiva.

¿Cuál es exactamente el parámetro _hash? ¿Por qué no pasar todo el mensaje?

Te puedes haber percatado que la función isValidSignature en la interfaz EIP-1271 no toma el mensaje en sí mismo, en cambio toma el parámetro _hash. Lo que esto significa es que en vez de pasar el mensaje completo de longitud arbitraria a isValidSignature, en cambio pasamos al hash del mensaje de 32-bytes (generalmente keccak256),

Cada byte de calldata, es decir, datos de parámetros de función, pasados a una función de contrato inteligente, tiene un costo de 16 gas(4 gas si el byte es cero), así que esto puede salvar mucho gas si el mensaje es largo.

Especificaciones Previas del EIP-1271

Hay especificaciones EIP-1271 afuera que tienen una función isValidSignature con el primer parámetro del tipo bytes (de longitud arbitraria, a diferencia de una longitud establecida bytes32) y el parámetro del nombre message. Esta es una versión antigua del estándar EIP-127.

¿Cómo debe ser implementado el EIP-1271 en mis propios contratos?

Las especificaciones son muy abiertas aquí. La implementación Safe tiene buenas ideas:

  • Puedes considerar las firmas EOA desde el “dueño” del contrato para que sea válido.
  • Puedes almacenar una lista de mensajes aprobados y sólo considerar aquellos que sean válidos.

Al final, ¡depende de tí como el desarrollador del contrato!

Conclusión

El EIP-1271 es un estándar versátil que permite a los contratos inteligentes verificar las firmas. El EIP-1271 abre las puertas para que los contratos inteligentes actúen más como las EOAs: por ejemplo, proveyendo una forma para “Acceder con Ethereum” para trabajar con los contratos inteligentes, y pueden ser implementados de muchas formas (Safe tiene una forma interesante de implementación no trivial para considerar).

Este artículo es una traducción de Nathan H. Leung, hecha por Héctor Botero. Puedes encontrar el artículo original aquí.
Sería genial escucharte en nuestro Discord, puedes contarnos tus ideas, comentarios, sugerencias y dejarnos saber lo que necesitas.
Si prefieres puedes escribirnos a @web3dev_es en Twitter.

Discussion (0)